Add control over whether lines are special cased in SkDashPath. Disable when called from GrShape.
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2055253002

Review-Url: https://codereview.chromium.org/2055253002
diff --git a/src/gpu/GrShape.cpp b/src/gpu/GrShape.cpp
index d2bec72..11b2d38 100644
--- a/src/gpu/GrShape.cpp
+++ b/src/gpu/GrShape.cpp
@@ -211,8 +211,8 @@
         // Should we consider bounds? Would have to include in key, but it'd be nice to know
         // if the bounds actually modified anything before including in key.
         SkStrokeRec strokeRec = parent.fStyle.strokeRec();
-        strokeRec.setResScale(scale);
-        if (!pe->filterPath(fPath.get(), *srcForPathEffect, &strokeRec, nullptr)) {
+        if (!parent.fStyle.applyPathEffectToPath(fPath.get(), &strokeRec, *srcForPathEffect,
+                                                 scale)) {
             // If the path effect fails then we continue as though there was no path effect.
             // If the original was a rrect that we couldn't canonicalize because of the path
             // effect, then do so now.
diff --git a/src/gpu/GrShape.h b/src/gpu/GrShape.h
index 3efb66f..93896ce 100644
--- a/src/gpu/GrShape.h
+++ b/src/gpu/GrShape.h
@@ -168,6 +168,17 @@
         return true;
     }
 
+    /**
+     * If the unstyled shape is a straight line segment, returns true and sets pts to the endpoints.
+     * An inverse filled line path is still considered a line.
+     */
+     bool asLine(SkPoint pts[2]) const {
+         if (fType != Type::kPath) {
+             return false;
+         }
+         return fPath.get()->isLine(pts);
+     }
+
     /** Returns the unstyled geometry as a path. */
     void asPath(SkPath* out) const {
         switch (fType) {
diff --git a/src/gpu/GrStyle.cpp b/src/gpu/GrStyle.cpp
index bb1f03d..10a0deb 100644
--- a/src/gpu/GrStyle.cpp
+++ b/src/gpu/GrStyle.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "GrStyle.h"
+#include "SkDashPathPriv.h"
 
 int GrStyle::KeySize(const GrStyle &style, Apply apply, uint32_t flags) {
     GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
@@ -120,12 +121,29 @@
     }
 }
 
-static inline bool apply_path_effect(SkPath* dst, SkStrokeRec* strokeRec,
-                                     const sk_sp<SkPathEffect>& pe, const SkPath& src) {
-    if (!pe) {
+bool GrStyle::applyPathEffect(SkPath* dst, SkStrokeRec* strokeRec, const SkPath& src) const {
+    if (!fPathEffect) {
         return false;
     }
-    if (!pe->filterPath(dst, src, strokeRec, nullptr)) {
+    if (SkPathEffect::kDash_DashType == fDashInfo.fType) {
+        // We apply the dash ourselves here rather than using the path effect. This is so that
+        // we can control whether the dasher applies the strokeRec for special cases. Our keying
+        // depends on the strokeRec being applied separately.
+        SkScalar phase = fDashInfo.fPhase;
+        const SkScalar* intervals = fDashInfo.fIntervals.get();
+        int intervalCnt = fDashInfo.fIntervals.count();
+        SkScalar initialLength;
+        int initialIndex;
+        SkScalar intervalLength;
+        SkDashPath::CalcDashParameters(phase, intervals, intervalCnt, &initialLength,
+                                       &initialIndex, &intervalLength);
+        if (!SkDashPath::InternalFilter(dst, src, strokeRec,
+                                        nullptr, intervals, intervalCnt,
+                                        initialLength, initialIndex, intervalLength,
+                                        SkDashPath::StrokeRecApplication::kDisallow)) {
+            return false;
+        }
+    } else if (!fPathEffect->filterPath(dst, src, strokeRec, nullptr)) {
         return false;
     }
     dst->setIsVolatile(true);
@@ -137,7 +155,7 @@
     SkASSERT(dst);
     SkStrokeRec strokeRec = fStrokeRec;
     strokeRec.setResScale(resScale);
-    if (!apply_path_effect(dst, &strokeRec, fPathEffect, src)) {
+    if (!this->applyPathEffect(dst, &strokeRec, src)) {
         return false;
     }
     *remainingStroke = strokeRec;
@@ -151,7 +169,7 @@
     SkStrokeRec strokeRec = fStrokeRec;
     strokeRec.setResScale(resScale);
     const SkPath* pathForStrokeRec = &src;
-    if (apply_path_effect(dst, &strokeRec, fPathEffect, src)) {
+    if (this->applyPathEffect(dst, &strokeRec, src)) {
         pathForStrokeRec = dst;
     } else if (fPathEffect) {
         return false;
diff --git a/src/gpu/GrStyle.h b/src/gpu/GrStyle.h
index 5190834..326f800 100644
--- a/src/gpu/GrStyle.h
+++ b/src/gpu/GrStyle.h
@@ -201,6 +201,8 @@
         SkAutoSTArray<4, SkScalar>  fIntervals;
     };
 
+    bool applyPathEffect(SkPath* dst, SkStrokeRec* strokeRec, const SkPath& src) const;
+
     SkStrokeRec         fStrokeRec;
     sk_sp<SkPathEffect> fPathEffect;
     DashInfo            fDashInfo;
diff --git a/src/utils/SkDashPath.cpp b/src/utils/SkDashPath.cpp
index 833c7cc..8317d20 100644
--- a/src/utils/SkDashPath.cpp
+++ b/src/utils/SkDashPath.cpp
@@ -216,7 +216,8 @@
 bool SkDashPath::InternalFilter(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
                                 const SkRect* cullRect, const SkScalar aIntervals[],
                                 int32_t count, SkScalar initialDashLength, int32_t initialDashIndex,
-                                SkScalar intervalLength) {
+                                SkScalar intervalLength,
+                                StrokeRecApplication strokeRecApplication) {
 
     // we do nothing if the src wants to be filled
     SkStrokeRec::Style style = rec->getStyle();
@@ -235,7 +236,8 @@
     }
 
     SpecialLineRec lineRec;
-    bool specialLine = lineRec.init(*srcPtr, dst, rec, count >> 1, intervalLength);
+    bool specialLine = (StrokeRecApplication::kAllow == strokeRecApplication) &&
+                       lineRec.init(*srcPtr, dst, rec, count >> 1, intervalLength);
 
     SkPathMeasure   meas(*srcPtr, false, rec->getResScale());
 
diff --git a/src/utils/SkDashPathPriv.h b/src/utils/SkDashPathPriv.h
index 54bf9a4..1151281 100644
--- a/src/utils/SkDashPathPriv.h
+++ b/src/utils/SkDashPathPriv.h
@@ -11,7 +11,7 @@
 #include "SkPathEffect.h"
 
 namespace SkDashPath {
-    /*
+    /**
      * Calculates the initialDashLength, initialDashIndex, and intervalLength based on the
      * inputed phase and intervals. If adjustedPhase is passed in, then the phase will be
      * adjusted to be between 0 and intervalLength. The result will be stored in adjustedPhase.
@@ -26,13 +26,23 @@
     bool FilterDashPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
                         const SkPathEffect::DashInfo& info);
 
-    /*
-     * Caller should have already used ValidDashPath to exclude invalid data.
+    /** See comments for InternalFilter */
+    enum class StrokeRecApplication {
+        kDisallow,
+        kAllow,
+    };
+
+    /**
+     * Caller should have already used ValidDashPath to exclude invalid data. Typically, this leaves
+     * the strokeRec unmodified. However, for some simple shapes (e.g. a line) it may directly
+     * evaluate the dash and stroke to produce a stroked output path with a fill strokeRec. Passing
+     * true for disallowStrokeRecApplication turns this behavior off.
      */
     bool InternalFilter(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
                         const SkRect* cullRect, const SkScalar aIntervals[],
                         int32_t count, SkScalar initialDashLength, int32_t initialDashIndex,
-                        SkScalar intervalLength);
+                        SkScalar intervalLength,
+                        StrokeRecApplication = StrokeRecApplication::kAllow);
 
     bool ValidDashPath(SkScalar phase, const SkScalar intervals[], int32_t count);
 }