Replace GrStrokeInfo with GrStyle.
authorbsalomon <bsalomon@google.com>
Tue, 10 May 2016 12:57:27 +0000 (05:57 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 10 May 2016 12:57:27 +0000 (05:57 -0700)
A side effect is that arbitrary path effects can no be pushed deeper into the Ganesh flow for paths. They may be applied by path renderers.
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1957363002

Review-Url: https://codereview.chromium.org/1957363002

49 files changed:
gyp/gpu.gypi
include/gpu/GrContext.h
include/gpu/GrDrawContext.h
include/gpu/GrTestUtils.h
src/gpu/GrBlurUtils.cpp
src/gpu/GrBlurUtils.h
src/gpu/GrClipMaskManager.cpp
src/gpu/GrDrawContext.cpp
src/gpu/GrPath.cpp
src/gpu/GrPath.h
src/gpu/GrPathRenderer.h
src/gpu/GrPathRendererChain.cpp
src/gpu/GrPathRendering.cpp
src/gpu/GrPathRendering.h
src/gpu/GrResourceProvider.cpp
src/gpu/GrResourceProvider.h
src/gpu/GrSWMaskHelper.cpp
src/gpu/GrSWMaskHelper.h
src/gpu/GrSoftwarePathRenderer.cpp
src/gpu/GrStrokeInfo.cpp [deleted file]
src/gpu/GrStrokeInfo.h [deleted file]
src/gpu/GrStyle.h
src/gpu/GrTestUtils.cpp
src/gpu/SkGpuDevice.cpp
src/gpu/SkGpuDevice_drawTexture.cpp
src/gpu/batches/GrAAConvexPathRenderer.cpp
src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
src/gpu/batches/GrAAHairLinePathRenderer.cpp
src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
src/gpu/batches/GrDashLinePathRenderer.cpp
src/gpu/batches/GrDefaultPathRenderer.cpp
src/gpu/batches/GrDefaultPathRenderer.h
src/gpu/batches/GrMSAAPathRenderer.cpp
src/gpu/batches/GrMSAAPathRenderer.h
src/gpu/batches/GrPLSPathRenderer.cpp
src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
src/gpu/batches/GrTessellatingPathRenderer.cpp
src/gpu/effects/GrDashingEffect.cpp
src/gpu/effects/GrDashingEffect.h
src/gpu/gl/GrGLPath.cpp
src/gpu/gl/GrGLPath.h
src/gpu/gl/GrGLPathRange.cpp
src/gpu/gl/GrGLPathRange.h
src/gpu/gl/GrGLPathRendering.cpp
src/gpu/gl/GrGLPathRendering.h
src/gpu/text/GrStencilAndCoverTextContext.cpp
src/gpu/text/GrStencilAndCoverTextContext.h
tests/GpuDrawPathTest.cpp
tests/TessellatingPathRendererTests.cpp

index 6b4837a..48f1c85 100644 (file)
       '<(skia_src_path)/gpu/GrStencil.h',
       '<(skia_src_path)/gpu/GrStencilAttachment.cpp',
       '<(skia_src_path)/gpu/GrStencilAttachment.h',
-      '<(skia_src_path)/gpu/GrStrokeInfo.cpp',
-      '<(skia_src_path)/gpu/GrStrokeInfo.h',
       '<(skia_src_path)/gpu/GrStyle.cpp',
       '<(skia_src_path)/gpu/GrStyle.h',
       '<(skia_src_path)/gpu/GrTessellator.cpp',
index 1c9a27e..44dfda6 100644 (file)
@@ -43,7 +43,6 @@ class GrTextBlobCache;
 class GrTextContext;
 class GrTextureParams;
 class GrVertexBuffer;
-class GrStrokeInfo;
 class GrSwizzle;
 class SkTraceMemoryDump;
 
index 7bb9aaf..458ee4f 100644 (file)
@@ -28,7 +28,7 @@ class GrPaint;
 class GrPathProcessor;
 class GrPipelineBuilder;
 class GrRenderTarget;
-class GrStrokeInfo;
+class GrStyle;
 class GrSurface;
 class SkDrawFilter;
 struct SkIPoint;
@@ -53,7 +53,7 @@ public:
 
     // TODO: it is odd that we need both the SkPaint in the following 3 methods.
     // We should extract the text parameters from SkPaint and pass them separately
-    // akin to GrStrokeInfo (GrTextInfo?)
+    // akin to GrStyle (GrTextInfo?)
     virtual void drawText(const GrClip&,  const GrPaint&, const SkPaint&,
                           const SkMatrix& viewMatrix, const char text[], size_t byteLength,
                           SkScalar x, SkScalar y, const SkIRect& clipBounds);
@@ -90,19 +90,15 @@ public:
      *  Draw the rect using a paint.
      *  @param paint        describes how to color pixels.
      *  @param viewMatrix   transformation matrix
-     *  @param strokeInfo   the stroke information (width, join, cap), and.
-     *                      the dash information (intervals, count, phase).
-     *                      If strokeInfo == NULL, then the rect is filled.
-     *                      Otherwise, if stroke width == 0, then the stroke
-     *                      is always a single pixel thick, else the rect is
-     *                      mitered/beveled stroked based on stroke width.
+     *  @param style        The style to apply. Null means fill. Currently path effects are not
+     *                      allowed.
      *  The rects coords are used to access the paint (through texture matrix)
      */
     void drawRect(const GrClip&,
                   const GrPaint& paint,
                   const SkMatrix& viewMatrix,
                   const SkRect&,
-                  const GrStrokeInfo* strokeInfo = nullptr);
+                  const GrStyle* style  = nullptr);
 
     /**
      * Maps a rectangle of shader coordinates to a rectangle and fills that rectangle.
@@ -133,14 +129,13 @@ public:
      *  @param paint        describes how to color pixels.
      *  @param viewMatrix   transformation matrix
      *  @param rrect        the roundrect to draw
-     *  @param strokeInfo   the stroke information (width, join, cap) and
-     *                      the dash information (intervals, count, phase).
+     *  @param style        style to apply to the rrect. Currently path effects are not allowed.
      */
     void drawRRect(const GrClip&,
                    const GrPaint&,
                    const SkMatrix& viewMatrix,
                    const SkRRect& rrect,
-                   const GrStrokeInfo&);
+                   const GrStyle& style);
 
     /**
      *  Shortcut for drawing an SkPath consisting of nested rrects using a paint.
@@ -164,14 +159,13 @@ public:
      * @param paint         describes how to color pixels.
      * @param viewMatrix    transformation matrix
      * @param path          the path to draw
-     * @param strokeInfo    the stroke information (width, join, cap) and
-     *                      the dash information (intervals, count, phase).
+     * @param style         style to apply to the path.
      */
     void drawPath(const GrClip&,
                   const GrPaint&,
                   const SkMatrix& viewMatrix,
                   const SkPath&,
-                  const GrStrokeInfo&);
+                  const GrStyle& style);
 
     /**
      * Draws vertices with a paint.
@@ -226,14 +220,13 @@ public:
      * @param paint         describes how to color pixels.
      * @param viewMatrix    transformation matrix
      * @param oval          the bounding rect of the oval.
-     * @param strokeInfo    the stroke information (width, join, cap) and
-     *                      the dash information (intervals, count, phase).
+     * @param style         style to apply to the oval. Currently path effects are not allowed.
      */
     void drawOval(const GrClip&,
                   const GrPaint& paint,
                   const SkMatrix& viewMatrix,
                   const SkRect& oval,
-                  const GrStrokeInfo& strokeInfo);
+                  const GrStyle& style);
 
     /**
      *  Draw the image stretched differentially to fit into dst.
@@ -318,7 +311,7 @@ private:
                           const GrPaint& paint,
                           const SkMatrix& viewMatrix,
                           const SkPath& path,
-                          const GrStrokeInfo& strokeInfo);
+                          const GrStyle& style);
 
     // This entry point allows the GrTextContext-derived classes to add their batches to
     // the drawTarget.
index 475e38a..caaf5d9 100644 (file)
 #ifdef GR_TEST_UTILS
 
 #include "GrColor.h"
+#include "SkPathEffect.h"
 #include "SkRandom.h"
 #include "SkStrokeRec.h"
+#include "../private/SkTemplates.h"
 
-class GrStrokeInfo;
+class GrStyle;
 class SkMatrix;
 class SkPath;
 class SkRRect;
@@ -24,7 +26,7 @@ struct SkRect;
 
 namespace GrTest {
 /**
- * A helper for use in Test functions.
+ * Helpers for use in Test functions.
  */
 const SkMatrix& TestMatrix(SkRandom*);
 const SkMatrix& TestMatrixPreservesRightAngles(SkRandom*);
@@ -36,9 +38,34 @@ const SkRRect& TestRRectSimple(SkRandom*);
 const SkPath& TestPath(SkRandom*);
 const SkPath& TestPathConvex(SkRandom*);
 SkStrokeRec TestStrokeRec(SkRandom*);
-GrStrokeInfo TestStrokeInfo(SkRandom*);
+/** Creates styles with dash path effects and null path effects */
+void TestStyle(SkRandom*, GrStyle*);
 
-}
+// We have a simplified dash path effect here to avoid relying on SkDashPathEffect which
+// is in the optional build target effects.
+class TestDashPathEffect : public SkPathEffect {
+public:
+    static sk_sp<SkPathEffect> Make(const SkScalar* intervals, int count, SkScalar phase) {
+        return sk_sp<SkPathEffect>(new TestDashPathEffect(intervals, count, phase));
+    }
+
+    bool filterPath(SkPath* dst, const SkPath&, SkStrokeRec* , const SkRect*) const override;
+    DashType asADash(DashInfo* info) const override;
+    Factory getFactory() const override { return nullptr; }
+    void toString(SkString*) const override {}
+
+private:
+    TestDashPathEffect(const SkScalar* intervals, int count, SkScalar phase);
+
+    int                     fCount;
+    SkAutoTArray<SkScalar>  fIntervals;
+    SkScalar                fPhase;
+    SkScalar                fInitialDashLength;
+    int                     fInitialDashIndex;
+    SkScalar                fIntervalLength;
+};
+
+}  // namespace GrTest
 
 static inline GrColor GrRandomColor(SkRandom* random) {
     // There are only a few cases of random colors which interest us
index aee1581..0a8351f 100644 (file)
@@ -10,7 +10,7 @@
 #include "GrCaps.h"
 #include "GrContext.h"
 #include "effects/GrSimpleTextureEffect.h"
-#include "GrStrokeInfo.h"
+#include "GrStyle.h"
 #include "GrTexture.h"
 #include "GrTextureProvider.h"
 #include "SkDraw.h"
@@ -54,11 +54,10 @@ static bool sw_draw_with_mask_filter(GrDrawContext* drawContext,
                                      const SkMaskFilter* filter,
                                      const SkIRect& clipBounds,
                                      GrPaint* grp,
-                                     SkStrokeRec::InitStyle style) {
+                                     SkStrokeRec::InitStyle fillOrHairline) {
     SkMask  srcM, dstM;
-
     if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM,
-                            SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) {
+                            SkMask::kComputeBoundsAndRenderImage_CreateMode, fillOrHairline)) {
         return false;
     }
     SkAutoMaskFreeImage autoSrc(srcM.fImage);
@@ -96,7 +95,7 @@ static bool sw_draw_with_mask_filter(GrDrawContext* drawContext,
 static sk_sp<GrTexture> create_mask_GPU(GrContext* context,
                                         SkRect* maskRect,
                                         const SkPath& devPath,
-                                        SkStrokeRec::InitStyle style,
+                                        SkStrokeRec::InitStyle fillOrHairline,
                                         bool doAA,
                                         int sampleCnt) {
     // This mask will ultimately be drawn as a non-AA rect (see draw_mask).
@@ -139,7 +138,7 @@ static sk_sp<GrTexture> create_mask_GPU(GrContext* context,
     // the origin using tempPaint.
     SkMatrix translate;
     translate.setTranslate(-maskRect->fLeft, -maskRect->fTop);
-    drawContext->drawPath(clip, tempPaint, translate, devPath, GrStrokeInfo(style));
+    drawContext->drawPath(clip, tempPaint, translate, devPath, GrStyle(fillOrHairline));
     return drawContext->asTexture();;
 }
 
@@ -149,52 +148,50 @@ static void draw_path_with_mask_filter(GrContext* context,
                                        GrPaint* paint,
                                        const SkMatrix& viewMatrix,
                                        const SkMaskFilter* maskFilter,
-                                       const SkPathEffect* pathEffect,
-                                       const GrStrokeInfo& strokeInfo,
-                                       SkPath* pathPtr,
+                                       const GrStyle& style,
+                                       const SkPath* path,
                                        bool pathIsMutable) {
     SkASSERT(maskFilter);
 
     SkIRect clipBounds;
     clip.getConservativeBounds(drawContext->width(), drawContext->height(), &clipBounds);
     SkTLazy<SkPath> tmpPath;
+    SkStrokeRec::InitStyle fillOrHairline;
 
-    static const SkRect* cullRect = nullptr;  // TODO: what is our bounds?
-
-    SkASSERT(strokeInfo.isDashed() || !pathEffect);
-    SkStrokeRec::InitStyle maskStyle;
-    if (strokeInfo.isHairlineStyle()) {
-        maskStyle = SkStrokeRec::kHairline_InitStyle;
-    } else {
-        SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init();
-        SkStrokeRec rec = strokeInfo;
-        if (strokeInfo.isDashed()) {
-            if (pathEffect->filterPath(strokedPath, *pathPtr, &rec, cullRect)) {
-                pathPtr = strokedPath;
-                pathPtr->setIsVolatile(true);
-                pathIsMutable = true;
-            }
-        }
-        if (rec.applyToPath(strokedPath, *pathPtr)) {
-            // Apply the stroke to the path if there is one
-            pathPtr = strokedPath;
-            pathPtr->setIsVolatile(true);
-            pathIsMutable = true;
+    // We just fully apply the style here.
+    if (style.applies()) {
+        if (!style.applyToPath(tmpPath.init(), &fillOrHairline, *path,
+                                   GrStyle::MatrixToScaleFactor(viewMatrix))) {
+            return;
         }
-        maskStyle = SkStrokeRec::kFill_InitStyle;
-    }
-
-    // avoid possibly allocating a new path in transform if we can
-    SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init();
-    if (!pathIsMutable) {
-        devPathPtr->setIsVolatile(true);
+        pathIsMutable = true;
+        path = tmpPath.get();
+    } else if (style.isSimpleHairline()) {
+        fillOrHairline = SkStrokeRec::kHairline_InitStyle;
+    } else {
+        SkASSERT(style.isSimpleFill());
+        fillOrHairline = SkStrokeRec::kFill_InitStyle;
     }
 
     // transform the path into device space
-    pathPtr->transform(viewMatrix, devPathPtr);
+    if (!viewMatrix.isIdentity()) {
+        SkPath* result;
+        if (pathIsMutable) {
+            result = const_cast<SkPath*>(path);
+        } else {
+            if (!tmpPath.isValid()) {
+                tmpPath.init();
+            }
+            result = tmpPath.get();
+        }
+        path->transform(viewMatrix, result);
+        path = result;
+        result->setIsVolatile(true);
+        pathIsMutable = true;
+    }
 
     SkRect maskRect;
-    if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(devPathPtr->getBounds()),
+    if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(path->getBounds()),
                                      clipBounds,
                                      viewMatrix,
                                      &maskRect)) {
@@ -210,8 +207,8 @@ static void draw_path_with_mask_filter(GrContext* context,
                                             paint,
                                             clip,
                                             viewMatrix,
-                                            SkStrokeRec(maskStyle),
-                                            *devPathPtr)) {
+                                            SkStrokeRec(fillOrHairline),
+                                            *path)) {
             // the mask filter was able to draw itself directly, so there's nothing
             // left to do.
             return;
@@ -219,8 +216,8 @@ static void draw_path_with_mask_filter(GrContext* context,
 
         sk_sp<GrTexture> mask(create_mask_GPU(context,
                                               &maskRect,
-                                              *devPathPtr,
-                                              maskStyle,
+                                              *path,
+                                              fillOrHairline,
                                               paint->isAntiAlias(),
                                               drawContext->numColorSamples()));
         if (mask) {
@@ -238,96 +235,59 @@ static void draw_path_with_mask_filter(GrContext* context,
     }
 
     sw_draw_with_mask_filter(drawContext, context->textureProvider(),
-                             clip, viewMatrix, *devPathPtr,
-                             maskFilter, clipBounds, paint, maskStyle);
+                             clip, viewMatrix, *path,
+                             maskFilter, clipBounds, paint, fillOrHairline);
 }
 
 void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
                                          GrDrawContext* drawContext,
                                          const GrClip& clip,
-                                         const SkPath& origPath,
+                                         const SkPath& path,
                                          GrPaint* paint,
                                          const SkMatrix& viewMatrix,
                                          const SkMaskFilter* mf,
-                                         const SkPathEffect* pathEffect,
-                                         const GrStrokeInfo& origStrokeInfo,
+                                         const GrStyle& style,
                                          bool pathIsMutable) {
-    SkPath* pathPtr = const_cast<SkPath*>(&origPath);
-
-    SkTLazy<SkPath> tmpPath;
-    GrStrokeInfo strokeInfo(origStrokeInfo);
-
-    if (!strokeInfo.isDashed() && pathEffect && pathEffect->filterPath(tmpPath.init(), *pathPtr,
-                                                                       &strokeInfo, nullptr)) {
-        pathPtr = tmpPath.get();
-        pathPtr->setIsVolatile(true);
-        pathIsMutable = true;
-        pathEffect = nullptr;
-    }
-
-    draw_path_with_mask_filter(context, drawContext, clip, paint, viewMatrix, mf, pathEffect,
-                               strokeInfo, pathPtr, pathIsMutable);
+    draw_path_with_mask_filter(context, drawContext, clip, paint, viewMatrix, mf,
+                               style, &path, pathIsMutable);
 }
 
 void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
                                          GrDrawContext* drawContext,
                                          const GrClip& clip,
-                                         const SkPath& origSrcPath,
+                                         const SkPath& origPath,
                                          const SkPaint& paint,
                                          const SkMatrix& origViewMatrix,
                                          const SkMatrix* prePathMatrix,
                                          const SkIRect& clipBounds,
                                          bool pathIsMutable) {
-    SkASSERT(!pathIsMutable || origSrcPath.isVolatile());
-
-    GrStrokeInfo strokeInfo(paint);
-    // comment out the line below to determine if it is the reason that the chrome mac perf bot
-    // has begun crashing
-    // strokeInfo.setResScale(SkDraw::ComputeResScaleForStroking(origViewMatrix));
+    SkASSERT(!pathIsMutable || origPath.isVolatile());
 
+    GrStyle style(paint);
     // If we have a prematrix, apply it to the path, optimizing for the case
     // where the original path can in fact be modified in place (even though
     // its parameter type is const).
-    SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
+
+    const SkPath* path = &origPath;
     SkTLazy<SkPath> tmpPath;
-    SkTLazy<SkPath> effectPath;
-    SkPathEffect* pathEffect = paint.getPathEffect();
 
     SkMatrix viewMatrix = origViewMatrix;
 
     if (prePathMatrix) {
-        // stroking, path effects, and blurs are supposed to be applied *after* the prePathMatrix.
-        // The pre-path-matrix also should not affect shading.
-        if (!paint.getMaskFilter() && !pathEffect && !paint.getShader() &&
-            (strokeInfo.isFillStyle() || strokeInfo.isHairlineStyle())) {
+        // Styling, blurs, and shading are supposed to be applied *after* the prePathMatrix.
+        if (!paint.getMaskFilter() && !paint.getShader() && !style.applies()) {
             viewMatrix.preConcat(*prePathMatrix);
         } else {
-            SkPath* result = pathPtr;
-
-            if (!pathIsMutable) {
-                result = tmpPath.init();
-                result->setIsVolatile(true);
-                pathIsMutable = true;
-            }
-            // should I push prePathMatrix on our MV stack temporarily, instead
-            // of applying it here? See SkDraw.cpp
-            pathPtr->transform(*prePathMatrix, result);
-            pathPtr = result;
+            SkPath* result = pathIsMutable ? const_cast<SkPath*>(path) : tmpPath.init();
+            pathIsMutable = true;
+            path->transform(*prePathMatrix, result);
+            path = result;
+            result->setIsVolatile(true);
         }
     }
     // at this point we're done with prePathMatrix
     SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
 
-    SkTLazy<SkPath> tmpPath2;
-
-    if (!strokeInfo.isDashed() && pathEffect &&
-        pathEffect->filterPath(tmpPath2.init(), *pathPtr, &strokeInfo, nullptr)) {
-        pathPtr = tmpPath2.get();
-        pathPtr->setIsVolatile(true);
-        pathIsMutable = true;
-        pathEffect = nullptr;
-    }
-
     GrPaint grPaint;
     if (!SkPaintToGrPaint(context, paint, viewMatrix, drawContext->isGammaCorrect(),
                           &grPaint)) {
@@ -336,9 +296,9 @@ void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
 
     if (paint.getMaskFilter()) {
         draw_path_with_mask_filter(context, drawContext, clip, &grPaint, viewMatrix,
-                                   paint.getMaskFilter(), pathEffect, strokeInfo,
-                                   pathPtr, pathIsMutable);
+                                   paint.getMaskFilter(), style,
+                                   path, pathIsMutable);
     } else {
-        drawContext->drawPath(clip, grPaint, viewMatrix, *pathPtr, strokeInfo);
+        drawContext->drawPath(clip, grPaint, viewMatrix, *path, style);
     }
 }
index a22239a..aef1bdb 100644 (file)
@@ -13,7 +13,7 @@ class GrContext;
 class GrDrawContext;
 class GrPaint;
 class GrRenderTarget;
-class GrStrokeInfo;
+class GrStyle;
 struct SkIRect;
 class SkMaskFilter;
 class SkMatrix;
@@ -50,8 +50,7 @@ namespace GrBlurUtils {
                                 GrPaint*,
                                 const SkMatrix& viewMatrix,
                                 const SkMaskFilter*,
-                                const SkPathEffect*,
-                                const GrStrokeInfo&,
+                                const GrStyle&,
                                 bool pathIsMutable);
 
 };
index 654b315..56c0ee6 100644 (file)
@@ -85,7 +85,6 @@ bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context,
         if (path.isInverseFillType()) {
             path.toggleInverseFillType();
         }
-        GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
 
         GrPathRendererChain::DrawType type;
 
@@ -103,7 +102,7 @@ bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context,
         canDrawArgs.fShaderCaps = context->caps()->shaderCaps();
         canDrawArgs.fViewMatrix = &viewMatrix;
         canDrawArgs.fPath = &path;
-        canDrawArgs.fStroke = &stroke;
+        canDrawArgs.fStyle = &GrStyle::SimpleFill();
         canDrawArgs.fAntiAlias = element->isAA();
         canDrawArgs.fIsStencilDisabled = isStencilDisabled;
         canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
@@ -591,7 +590,7 @@ static void draw_element(GrDrawContext* dc,
                 path.toggleInverseFillType();
             }
 
-            dc->drawPath(clip, paint, viewMatrix, path, GrStrokeInfo::FillInfo());
+            dc->drawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill());
             break;
         }
     }
@@ -785,7 +784,6 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
             // stencil with arbitrary stencil settings.
             GrPathRenderer::StencilSupport stencilSupport;
 
-            GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
             SkRegion::Op op = element->getOp();
 
             GrPathRenderer* pr = nullptr;
@@ -806,7 +804,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
                 canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps();
                 canDrawArgs.fViewMatrix = &viewMatrix;
                 canDrawArgs.fPath = &clipPath;
-                canDrawArgs.fStroke = &stroke;
+                canDrawArgs.fStyle = &GrStyle::SimpleFill();
                 canDrawArgs.fAntiAlias = false;
                 canDrawArgs.fIsStencilDisabled = pipelineBuilder.getStencil().isDisabled();
                 canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
@@ -861,7 +859,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
                             args.fColor = GrColor_WHITE;
                             args.fViewMatrix = &viewMatrix;
                             args.fPath = &clipPath;
-                            args.fStroke = &stroke;
+                            args.fStyle = &GrStyle::SimpleFill();
                             args.fAntiAlias = false;
                             args.fGammaCorrect = false;
                             pr->drawPath(args);
@@ -896,7 +894,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
                         args.fColor = GrColor_WHITE;
                         args.fViewMatrix = &viewMatrix;
                         args.fPath = &clipPath;
-                        args.fStroke = &stroke;
+                        args.fStyle = &GrStyle::SimpleFill();
                         args.fAntiAlias = false;
                         args.fGammaCorrect = false;
                         pr->drawPath(args);
@@ -1100,7 +1098,6 @@ GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context,
 
     helper.init(maskSpaceIBounds, &translate, false);
     helper.clear(GrReducedClip::kAllIn_InitialState == initialState ? 0xFF : 0x00);
-    SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
 
     for (GrReducedClip::ElementList::Iter iter(elements.headIter()) ; iter.get(); iter.next()) {
         const Element* element = iter.get();
@@ -1119,7 +1116,8 @@ GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context,
             SkPath clipPath;
             element->asPath(&clipPath);
             clipPath.toggleInverseFillType();
-            helper.draw(clipPath, stroke, SkRegion::kReplace_Op, element->isAA(), 0x00);
+            helper.draw(clipPath, GrStyle::SimpleFill(), SkRegion::kReplace_Op, element->isAA(),
+                        0x00);
             continue;
         }
 
@@ -1130,7 +1128,7 @@ GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context,
         } else {
             SkPath path;
             element->asPath(&path);
-            helper.draw(path, stroke, op, element->isAA(), 0xFF);
+            helper.draw(path, GrStyle::SimpleFill(), op, element->isAA(), 0xFF);
         }
     }
 
index 6c80f52..a7c7f6a 100644 (file)
@@ -279,18 +279,22 @@ void GrDrawContext::drawRect(const GrClip& clip,
                              const GrPaint& paint,
                              const SkMatrix& viewMatrix,
                              const SkRect& rect,
-                             const GrStrokeInfo* strokeInfo) {
+                             const GrStyle* style) {
+    if (!style) {
+        style = &GrStyle::SimpleFill();
+    }
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRect");
 
-    // Dashing should've been devolved to a path in SkGpuDevice
-    SkASSERT(!strokeInfo || !strokeInfo->isDashed());
+    // Path effects should've been devolved to a path in SkGpuDevice
+    SkASSERT(!style->pathEffect());
 
     AutoCheckFlush acf(fDrawingManager);
 
-    SkScalar width = !strokeInfo ? -1 : strokeInfo->getWidth();
+    const SkStrokeRec& stroke = style->strokeRec();
+    SkScalar width = stroke.getWidth();
 
     // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
     // cases where the RT is fully inside a stroke.
@@ -337,7 +341,7 @@ void GrDrawContext::drawRect(const GrClip& clip,
             // The stroke path needs the rect to remain axis aligned (no rotation or skew).
             if (viewMatrix.rectStaysRect()) {
                 batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect,
-                                                               *strokeInfo));
+                                                               stroke));
             }
         } else {
             // Non-AA hairlines are snapped to pixel centers to make which pixels are hit
@@ -367,8 +371,7 @@ void GrDrawContext::drawRect(const GrClip& clip,
     SkPath path;
     path.setIsVolatile(true);
     path.addRect(rect);
-    this->internalDrawPath(clip, paint, viewMatrix, path,
-                           strokeInfo ? *strokeInfo : GrStrokeInfo::FillInfo());
+    this->internalDrawPath(clip, paint, viewMatrix, path, *style);
 }
 
 bool GrDrawContextPriv::drawAndStencilRect(const SkIRect* scissorRect,
@@ -536,7 +539,7 @@ void GrDrawContext::drawRRect(const GrClip& clip,
                               const GrPaint& paint,
                               const SkMatrix& viewMatrix,
                               const SkRRect& rrect,
-                              const GrStrokeInfo& strokeInfo) {
+                              const GrStyle& style) {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
@@ -546,8 +549,8 @@ void GrDrawContext::drawRRect(const GrClip& clip,
        return;
     }
 
-    SkASSERT(!strokeInfo.isDashed()); // this should've been devolved to a path in SkGpuDevice
-
+    SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
+    const SkStrokeRec stroke = style.strokeRec();
     AutoCheckFlush acf(fDrawingManager);
 
     if (should_apply_coverage_aa(paint, fRenderTarget.get())) {
@@ -556,7 +559,7 @@ void GrDrawContext::drawRRect(const GrClip& clip,
         SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateRRectBatch(paint.getColor(),
                                                                          viewMatrix,
                                                                          rrect,
-                                                                         strokeInfo,
+                                                                         stroke,
                                                                          shaderCaps));
         if (batch) {
             GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
@@ -568,7 +571,7 @@ void GrDrawContext::drawRRect(const GrClip& clip,
     SkPath path;
     path.setIsVolatile(true);
     path.addRRect(rrect);
-    this->internalDrawPath(clip, paint, viewMatrix, path, strokeInfo);
+    this->internalDrawPath(clip, paint, viewMatrix, path, style);
 }
 
 bool GrDrawContext::drawFilledDRRect(const GrClip& clip,
@@ -654,7 +657,7 @@ void GrDrawContext::drawDRRect(const GrClip& clip,
     path.setFillType(SkPath::kEvenOdd_FillType);
 
     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
-    this->internalDrawPath(clip, paint, viewMatrix, path, GrStrokeInfo::FillInfo());
+    this->internalDrawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -663,7 +666,7 @@ void GrDrawContext::drawOval(const GrClip& clip,
                              const GrPaint& paint,
                              const SkMatrix& viewMatrix,
                              const SkRect& oval,
-                             const GrStrokeInfo& strokeInfo) {
+                             const GrStyle& style) {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
@@ -673,16 +676,16 @@ void GrDrawContext::drawOval(const GrClip& clip,
        return;
     }
 
-    SkASSERT(!strokeInfo.isDashed()); // this should've been devolved to a path in SkGpuDevice
+    SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
 
     AutoCheckFlush acf(fDrawingManager);
-
+    const SkStrokeRec& stroke = style.strokeRec();
     if (should_apply_coverage_aa(paint, fRenderTarget.get())) {
         GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
         SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(paint.getColor(),
                                                                         viewMatrix,
                                                                         oval,
-                                                                        strokeInfo,
+                                                                        stroke,
                                                                         shaderCaps));
         if (batch) {
             GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
@@ -694,7 +697,7 @@ void GrDrawContext::drawOval(const GrClip& clip,
     SkPath path;
     path.setIsVolatile(true);
     path.addOval(oval);
-    this->internalDrawPath(clip, paint, viewMatrix, path, strokeInfo);
+    this->internalDrawPath(clip, paint, viewMatrix, path, style);
 }
 
 void GrDrawContext::drawImageNine(const GrClip& clip,
@@ -721,11 +724,7 @@ void GrDrawContext::drawImageNine(const GrClip& clip,
 
 
 // Can 'path' be drawn as a pair of filled nested rectangles?
-static bool is_nested_rects(const SkMatrix& viewMatrix,
-                            const SkPath& path,
-                            const SkStrokeRec& stroke,
-                            SkRect rects[2]) {
-    SkASSERT(stroke.isFillStyle());
+static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) {
 
     if (path.isInverseFillType()) {
         return false;
@@ -799,7 +798,7 @@ void GrDrawContext::drawPath(const GrClip& clip,
                              const GrPaint& paint,
                              const SkMatrix& viewMatrix,
                              const SkPath& path,
-                             const GrStrokeInfo& strokeInfo) {
+                             const GrStyle& style) {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
@@ -814,12 +813,12 @@ void GrDrawContext::drawPath(const GrClip& clip,
 
     AutoCheckFlush acf(fDrawingManager);
 
-    if (should_apply_coverage_aa(paint, fRenderTarget.get()) && !strokeInfo.isDashed()) {
-        if (strokeInfo.getWidth() < 0 && !path.isConvex()) {
+    if (should_apply_coverage_aa(paint, fRenderTarget.get()) && !style.pathEffect()) {
+        if (style.isSimpleFill() && !path.isConvex()) {
             // Concave AA paths are expensive - try to avoid them for special cases
             SkRect rects[2];
 
-            if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
+            if (fills_as_nested_rects(viewMatrix, path, rects)) {
                 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFillNestedRects(
                     paint.getColor(), viewMatrix, rects));
                 if (batch) {
@@ -837,7 +836,7 @@ void GrDrawContext::drawPath(const GrClip& clip,
             SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(paint.getColor(),
                                                                             viewMatrix,
                                                                             ovalRect,
-                                                                            strokeInfo,
+                                                                            style.strokeRec(),
                                                                             shaderCaps));
             if (batch) {
                 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip);
@@ -852,7 +851,7 @@ void GrDrawContext::drawPath(const GrClip& clip,
     // cache. This presents a potential hazard for buffered drawing. However,
     // the writePixels that uploads to the scratch will perform a flush so we're
     // OK.
-    this->internalDrawPath(clip, paint, viewMatrix, path, strokeInfo);
+    this->internalDrawPath(clip, paint, viewMatrix, path, style);
 }
 
 bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
@@ -892,7 +891,7 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
     canDrawArgs.fShaderCaps = fDrawContext->fDrawingManager->getContext()->caps()->shaderCaps();
     canDrawArgs.fViewMatrix = &viewMatrix;
     canDrawArgs.fPath = &path;
-    canDrawArgs.fStroke = &GrStrokeInfo::FillInfo();
+    canDrawArgs.fStyle = &GrStyle::SimpleFill();
     canDrawArgs.fAntiAlias = useCoverageAA;
     canDrawArgs.fIsStencilDisabled = isStencilDisabled;
     canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
@@ -923,7 +922,7 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
     args.fColor = GrColor_WHITE;
     args.fViewMatrix = &viewMatrix;
     args.fPath = &path;
-    args.fStroke = &GrStrokeInfo::FillInfo();
+    args.fStyle = &GrStyle::SimpleFill();
     args.fAntiAlias = useCoverageAA;
     args.fGammaCorrect = fDrawContext->isGammaCorrect();
     pr->drawPath(args);
@@ -933,16 +932,12 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
 void GrDrawContext::internalDrawPath(const GrClip& clip,
                                      const GrPaint& paint,
                                      const SkMatrix& viewMatrix,
-                                     const SkPath& path,
-                                     const GrStrokeInfo& strokeInfo) {
+                                     const SkPath& origPath,
+                                     const GrStyle& origStyle) {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
-    SkASSERT(!path.isEmpty());
+    SkASSERT(!origPath.isEmpty());
 
-    // An Assumption here is that path renderer would use some form of tweaking
-    // the src color (either the input alpha or in the frag shader) to implement
-    // aa. If we have some future driver-mojo path AA that can do the right
-    // thing WRT to the blend then we'll need some query on the PR.
     bool useCoverageAA = should_apply_coverage_aa(paint, fRenderTarget.get());
     const bool isStencilDisabled = true;
     bool isStencilBufferMSAA = fRenderTarget->isStencilBufferMultisampled();
@@ -951,61 +946,65 @@ void GrDrawContext::internalDrawPath(const GrClip& clip,
         useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType
                       : GrPathRendererChain::kColor_DrawType;
 
-    const SkPath* pathPtr = &path;
     SkTLazy<SkPath> tmpPath;
-    const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
+    SkTLazy<GrStyle> tmpStyle;
 
     GrPathRenderer::CanDrawPathArgs canDrawArgs;
     canDrawArgs.fShaderCaps = fDrawingManager->getContext()->caps()->shaderCaps();
     canDrawArgs.fViewMatrix = &viewMatrix;
-    canDrawArgs.fPath = pathPtr;
-    canDrawArgs.fStroke = strokeInfoPtr;
+    canDrawArgs.fPath = &origPath;
+    canDrawArgs.fStyle = &origStyle;
     canDrawArgs.fAntiAlias = useCoverageAA;
     canDrawArgs.fIsStencilDisabled = isStencilDisabled;
     canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
 
-    // Try a 1st time without stroking the path and without allowing the SW renderer
+    // Try a 1st time without applying any of the style to the geometry (and barring sw)
     GrPathRenderer* pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
-
-    GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
-    if (nullptr == pr && strokeInfo.isDashed()) {
-        // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
-        if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
+    SkScalar styleScale =  GrStyle::MatrixToScaleFactor(viewMatrix);
+
+    if (!pr && canDrawArgs.fStyle->pathEffect()) {
+        // It didn't work above, so try again with the path effect applied.
+        SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
+        if (!canDrawArgs.fStyle->applyPathEffectToPath(tmpPath.init(), &rec, *canDrawArgs.fPath,
+                                                       styleScale)) {
+            GrStyle noPathEffect(canDrawArgs.fStyle->strokeRec(), nullptr);
+            this->internalDrawPath(clip, paint, viewMatrix, *canDrawArgs.fPath, noPathEffect);
             return;
         }
-        pathPtr = tmpPath.get();
-        if (pathPtr->isEmpty()) {
+        tmpStyle.init(rec, nullptr);
+        canDrawArgs.fPath = tmpPath.get();
+        canDrawArgs.fStyle = tmpStyle.get();
+        if (canDrawArgs.fPath->isEmpty()) {
             return;
         }
-        strokeInfoPtr = &dashlessStrokeInfo;
-
-        canDrawArgs.fPath = pathPtr;
-        canDrawArgs.fStroke = strokeInfoPtr;
 
         pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
     }
-
-    if (nullptr == pr) {
-        if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, nullptr) &&
-            !strokeInfoPtr->isFillStyle()) {
-            // It didn't work above, so try again with stroke converted to a fill.
+    if (!pr) {
+        SkASSERT(!canDrawArgs.fStyle->pathEffect());
+        if (canDrawArgs.fStyle->strokeRec().needToApply()) {
             if (!tmpPath.isValid()) {
                 tmpPath.init();
             }
-            dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
-            if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
+            // It didn't work above, so try again by applying the stroke to the geometry.
+            SkStrokeRec::InitStyle fillOrHairline;
+            if (!canDrawArgs.fStyle->applyToPath(tmpPath.get(), &fillOrHairline,
+                                                 *canDrawArgs.fPath, styleScale)) {
                 return;
             }
-            pathPtr = tmpPath.get();
-            if (pathPtr->isEmpty()) {
+            if (!tmpStyle.isValid()) {
+                tmpStyle.init(fillOrHairline);
+            } else {
+                tmpStyle.get()->resetToInitStyle(fillOrHairline);
+            }
+            canDrawArgs.fPath = tmpPath.get();
+            canDrawArgs.fStyle = tmpStyle.get();
+            if (canDrawArgs.fPath->isEmpty()) {
                 return;
             }
-            dashlessStrokeInfo.setFillStyle();
-            strokeInfoPtr = &dashlessStrokeInfo;
-        }
 
-        canDrawArgs.fPath = pathPtr;
-        canDrawArgs.fStroke = strokeInfoPtr;
+            pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
+        }
 
         // This time, allow SW renderer
         pr = fDrawingManager->getPathRenderer(canDrawArgs, true, type);
@@ -1026,8 +1025,8 @@ void GrDrawContext::internalDrawPath(const GrClip& clip,
     args.fPipelineBuilder = &pipelineBuilder;
     args.fColor = paint.getColor();
     args.fViewMatrix = &viewMatrix;
-    args.fPath = pathPtr;
-    args.fStroke = strokeInfoPtr;
+    args.fPath = canDrawArgs.fPath;
+    args.fStyle = canDrawArgs.fStyle;
     args.fAntiAlias = useCoverageAA;
     args.fGammaCorrect = this->isGammaCorrect();
     pr->drawPath(args);
index 04d93b1..91a245d 100644 (file)
@@ -6,13 +6,28 @@
  */
 
 #include "GrPath.h"
+#include "GrStyle.h"
 
 namespace {
 // Verb count limit for generating path key from content of a volatile path.
 // The value should accomodate at least simple rects and rrects.
 static const int kSimpleVolatilePathVerbLimit = 10;
 
-inline static bool compute_key_for_line_path(const SkPath& path, const GrStrokeInfo& stroke,
+static inline int style_data_cnt(const GrStyle& style) {
+    int cnt = GrStyle::KeySize(style, GrStyle::Apply::kPathEffectAndStrokeRec);
+    // This should only fail for an arbitrary path effect, and we should not have gotten
+    // here with anything other than a dash path effect.
+    SkASSERT(cnt >= 0);
+    return cnt;
+}
+
+static inline void write_style_key(uint32_t* dst, const GrStyle& style) {
+    // Pass 1 for the scale since the GPU will apply the style not GrStyle::applyToPath().
+    GrStyle::WriteKey(dst, style, GrStyle::Apply::kPathEffectAndStrokeRec, SK_Scalar1);
+}
+
+
+inline static bool compute_key_for_line_path(const SkPath& path, const GrStyle& style,
                                              GrUniqueKey* key) {
     SkPoint pts[2];
     if (!path.isLine(pts)) {
@@ -20,37 +35,37 @@ inline static bool compute_key_for_line_path(const SkPath& path, const GrStrokeI
     }
     static_assert((sizeof(pts) % sizeof(uint32_t)) == 0 && sizeof(pts) > sizeof(uint32_t),
                   "pts_needs_padding");
+    int styleDataCnt = style_data_cnt(style);
 
     const int kBaseData32Cnt = 1 + sizeof(pts) / sizeof(uint32_t);
-    int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt();
     static const GrUniqueKey::Domain kOvalPathDomain = GrUniqueKey::GenerateDomain();
-    GrUniqueKey::Builder builder(key, kOvalPathDomain, kBaseData32Cnt + strokeDataCnt);
+    GrUniqueKey::Builder builder(key, kOvalPathDomain, kBaseData32Cnt + styleDataCnt);
     builder[0] = path.getFillType();
     memcpy(&builder[1], &pts, sizeof(pts));
-    if (strokeDataCnt > 0) {
-        stroke.asUniqueKeyFragment(&builder[kBaseData32Cnt]);
+    if (styleDataCnt > 0) {
+        write_style_key(&builder[kBaseData32Cnt], style);
     }
     return true;
 }
 
-inline static bool compute_key_for_oval_path(const SkPath& path, const GrStrokeInfo& stroke,
+inline static bool compute_key_for_oval_path(const SkPath& path, const GrStyle& style,
                                              GrUniqueKey* key) {
     SkRect rect;
     // Point order is significant when dashing, so we cannot devolve to a rect key.
-    if (stroke.isDashed() || !path.isOval(&rect)) {
+    if (style.pathEffect() || !path.isOval(&rect)) {
         return false;
     }
     static_assert((sizeof(rect) % sizeof(uint32_t)) == 0 && sizeof(rect) > sizeof(uint32_t),
                   "rect_needs_padding");
 
     const int kBaseData32Cnt = 1 + sizeof(rect) / sizeof(uint32_t);
-    int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt();
+    int styleDataCnt = style_data_cnt(style);
     static const GrUniqueKey::Domain kOvalPathDomain = GrUniqueKey::GenerateDomain();
-    GrUniqueKey::Builder builder(key, kOvalPathDomain, kBaseData32Cnt + strokeDataCnt);
+    GrUniqueKey::Builder builder(key, kOvalPathDomain, kBaseData32Cnt + styleDataCnt);
     builder[0] = path.getFillType();
     memcpy(&builder[1], &rect, sizeof(rect));
-    if (strokeDataCnt > 0) {
-        stroke.asUniqueKeyFragment(&builder[kBaseData32Cnt]);
+    if (styleDataCnt > 0) {
+        write_style_key(&builder[kBaseData32Cnt], style);
     }
     return true;
 }
@@ -58,7 +73,7 @@ inline static bool compute_key_for_oval_path(const SkPath& path, const GrStrokeI
 // Encodes the full path data to the unique key for very small, volatile paths. This is typically
 // hit when clipping stencils the clip stack. Intention is that this handles rects too, since
 // SkPath::isRect seems to do non-trivial amount of work.
-inline static bool compute_key_for_simple_path(const SkPath& path, const GrStrokeInfo& stroke,
+inline static bool compute_key_for_simple_path(const SkPath& path, const GrStyle& style,
                                                GrUniqueKey* key) {
     if (!path.isVolatile()) {
         return false;
@@ -109,9 +124,9 @@ inline static bool compute_key_for_simple_path(const SkPath& path, const GrStrok
     // 2) stroke data (varying size)
 
     const int baseData32Cnt = 2 + verbData32Cnt + pointData32Cnt + conicWeightData32Cnt;
-    const int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt();
+    const int styleDataCnt = style_data_cnt(style);
     static const GrUniqueKey::Domain kSimpleVolatilePathDomain = GrUniqueKey::GenerateDomain();
-    GrUniqueKey::Builder builder(key, kSimpleVolatilePathDomain, baseData32Cnt + strokeDataCnt);
+    GrUniqueKey::Builder builder(key, kSimpleVolatilePathDomain, baseData32Cnt + styleDataCnt);
     int i = 0;
     builder[i++] = path.getFillType();
 
@@ -153,57 +168,68 @@ inline static bool compute_key_for_simple_path(const SkPath& path, const GrStrok
         SkDEBUGCODE(i += conicWeightData32Cnt);
     }
     SkASSERT(i == baseData32Cnt);
-    if (strokeDataCnt > 0) {
-        stroke.asUniqueKeyFragment(&builder[baseData32Cnt]);
+    if (styleDataCnt > 0) {
+        write_style_key(&builder[baseData32Cnt], style);
     }
     return true;
 }
 
-inline static void compute_key_for_general_path(const SkPath& path, const GrStrokeInfo& stroke,
+inline static void compute_key_for_general_path(const SkPath& path, const GrStyle& style,
                                                 GrUniqueKey* key) {
     const int kBaseData32Cnt = 2;
-    int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt();
+    int styleDataCnt = style_data_cnt(style);
     static const GrUniqueKey::Domain kGeneralPathDomain = GrUniqueKey::GenerateDomain();
-    GrUniqueKey::Builder builder(key, kGeneralPathDomain, kBaseData32Cnt + strokeDataCnt);
+    GrUniqueKey::Builder builder(key, kGeneralPathDomain, kBaseData32Cnt + styleDataCnt);
     builder[0] = path.getGenerationID();
     builder[1] = path.getFillType();
-    if (strokeDataCnt > 0) {
-        stroke.asUniqueKeyFragment(&builder[kBaseData32Cnt]);
+    if (styleDataCnt > 0) {
+        write_style_key(&builder[kBaseData32Cnt], style);
     }
 }
 
 }
 
-void GrPath::ComputeKey(const SkPath& path, const GrStrokeInfo& stroke, GrUniqueKey* key,
+void GrPath::ComputeKey(const SkPath& path, const GrStyle& style, GrUniqueKey* key,
                         bool* outIsVolatile) {
-    if (compute_key_for_line_path(path, stroke, key)) {
+    if (compute_key_for_line_path(path, style, key)) {
         *outIsVolatile = false;
         return;
     }
 
-    if (compute_key_for_oval_path(path, stroke, key)) {
+    if (compute_key_for_oval_path(path, style, key)) {
         *outIsVolatile = false;
         return;
     }
 
-    if (compute_key_for_simple_path(path, stroke, key)) {
+    if (compute_key_for_simple_path(path, style, key)) {
         *outIsVolatile = false;
         return;
     }
 
-    compute_key_for_general_path(path, stroke, key);
+    compute_key_for_general_path(path, style, key);
     *outIsVolatile = path.isVolatile();
 }
 
 #ifdef SK_DEBUG
-bool GrPath::isEqualTo(const SkPath& path, const GrStrokeInfo& stroke) const {
-    if (!fStroke.hasEqualEffect(stroke)) {
+bool GrPath::isEqualTo(const SkPath& path, const GrStyle& style) const {
+    // Since this is only called in debug we don't care about performance.
+    int cnt0 = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectAndStrokeRec);
+    int cnt1 = GrStyle::KeySize(style, GrStyle::Apply::kPathEffectAndStrokeRec);
+    if (cnt0 < 0 || cnt1 < 0 || cnt0 != cnt1) {
         return false;
     }
-
+    if (cnt0) {
+        SkAutoTArray<uint32_t> key0(cnt0);
+        SkAutoTArray<uint32_t> key1(cnt0);
+        write_style_key(key0.get(), fStyle);
+        write_style_key(key1.get(), style);
+        if (0 != memcmp(key0.get(), key1.get(), cnt0)) {
+            return false;
+        }
+    }
     // We treat same-rect ovals as identical - but only when not dashing.
     SkRect ovalBounds;
-    if (!fStroke.isDashed() && fSkPath.isOval(&ovalBounds)) {
+    if (!fStyle.isDashed() && fSkPath.isOval(&ovalBounds)) {
         SkRect otherOvalBounds;
         return path.isOval(&otherOvalBounds) && ovalBounds == otherOvalBounds;
     }
index 4cb12f4..ee3123f 100644 (file)
@@ -9,8 +9,8 @@
 #define GrPath_DEFINED
 
 #include "GrGpuResource.h"
-#include "GrStrokeInfo.h"
 #include "GrPathRendering.h"
+#include "GrStyle.h"
 #include "SkPath.h"
 #include "SkRect.h"
 
@@ -19,25 +19,25 @@ public:
     /**
      * Initialize to a path with a fixed stroke. Stroke must not be hairline.
      */
-    GrPath(GrGpu* gpu, const SkPath& skPath, const GrStrokeInfo& stroke)
+    GrPath(GrGpu* gpu, const SkPath& skPath, const GrStyle& style)
         : INHERITED(gpu)
         , fBounds(SkRect::MakeEmpty())
         , fFillType(GrPathRendering::kWinding_FillType)
 #ifdef SK_DEBUG
         , fSkPath(skPath)
-        , fStroke(stroke)
+        , fStyle(style)
 #endif
     {
     }
 
-    static void ComputeKey(const SkPath& path, const GrStrokeInfo& stroke, GrUniqueKey* key,
+    static void ComputeKey(const SkPath& path, const GrStyle& style, GrUniqueKey* key,
                            bool* outIsVolatile);
 
     const SkRect& getBounds() const { return fBounds; }
 
     GrPathRendering::FillType getFillType() const { return fFillType; }
 #ifdef SK_DEBUG
-    bool isEqualTo(const SkPath& path, const GrStrokeInfo& stroke) const;
+    bool isEqualTo(const SkPath& path, const GrStyle& style) const;
 #endif
 
 protected:
@@ -46,7 +46,7 @@ protected:
     GrPathRendering::FillType fFillType;
 #ifdef SK_DEBUG
     SkPath fSkPath;
-    GrStrokeInfo fStroke;
+    GrStyle fStyle;
 #endif
 
 private:
index 1072f69..3bc0230 100644 (file)
 
 #include "GrDrawTarget.h"
 #include "GrStencil.h"
-#include "GrStrokeInfo.h"
+#include "GrStyle.h"
 
 #include "SkDrawProcs.h"
 #include "SkTArray.h"
 
 class SkPath;
-
 struct GrPoint;
 
 /**
@@ -72,14 +71,14 @@ public:
      * fPipelineBuilder  The pipelineBuilder
      * fViewMatrix       The viewMatrix
      * fPath             The path to draw
-     * fStroke           The stroke information (width, join, cap)
+     * fStyle            The styling info (path effect, stroking info)
      * fAntiAlias        True if anti-aliasing is required.
      */
     struct CanDrawPathArgs {
         const GrShaderCaps*         fShaderCaps;
         const SkMatrix*             fViewMatrix;
         const SkPath*               fPath;
-        const GrStrokeInfo*         fStroke;
+        const GrStyle*              fStyle;
         bool                        fAntiAlias;
 
         // These next two are only used by GrStencilAndCoverPathRenderer
@@ -90,7 +89,7 @@ public:
             SkASSERT(fShaderCaps);
             SkASSERT(fViewMatrix);
             SkASSERT(fPath);
-            SkASSERT(fStroke);
+            SkASSERT(fStyle);
             SkASSERT(!fPath->isEmpty());
         }
     };
@@ -116,7 +115,7 @@ public:
      * fColor                 Color to render with
      * fViewMatrix            The viewMatrix
      * fPath                  the path to draw.
-     * fStroke                the stroke information (width, join, cap)
+     * fStyle                 the style information (path effect, stroke info)
      * fAntiAlias             true if anti-aliasing is required.
      * fGammaCorrect          true if gamma-correct rendering is to be used.
      */
@@ -127,7 +126,7 @@ public:
         GrColor                     fColor;
         const SkMatrix*             fViewMatrix;
         const SkPath*               fPath;
-        const GrStrokeInfo*         fStroke;
+        const GrStyle*              fStyle;
         bool                        fAntiAlias;
         bool                        fGammaCorrect;
 
@@ -137,7 +136,7 @@ public:
             SkASSERT(fPipelineBuilder);
             SkASSERT(fViewMatrix);
             SkASSERT(fPath);
-            SkASSERT(fStroke);
+            SkASSERT(fStyle);
             SkASSERT(!fPath->isEmpty());
         }
     };
@@ -153,7 +152,7 @@ public:
         canArgs.fShaderCaps = args.fTarget->caps()->shaderCaps();
         canArgs.fViewMatrix = args.fViewMatrix;
         canArgs.fPath = args.fPath;
-        canArgs.fStroke = args.fStroke;
+        canArgs.fStyle = args.fStyle;
         canArgs.fAntiAlias = args.fAntiAlias;
 
         canArgs.fIsStencilDisabled = args.fPipelineBuilder->getStencil().isDisabled();
@@ -162,8 +161,7 @@ public:
         SkASSERT(this->canDrawPath(canArgs));
         if (!args.fPipelineBuilder->getStencil().isDisabled()) {
             SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fPath));
-            SkASSERT(!args.fStroke->isDashed());
-            SkASSERT(args.fStroke->isFillStyle());
+            SkASSERT(args.fStyle->isSimpleFill());
         }
 #endif
         return this->onDrawPath(args);
@@ -197,22 +195,21 @@ public:
     /**
      * Draws the path to the stencil buffer. Assume the writable stencil bits are already
      * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
-     *
      */
     void stencilPath(const StencilPathArgs& args) {
         SkDEBUGCODE(args.validate();)
         SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fPath));
-
         this->onStencilPath(args);
     }
 
     // Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
     // If we can, we draw lots faster (raster device does this same test).
-    static bool IsStrokeHairlineOrEquivalent(const GrStrokeInfo& stroke, const SkMatrix& matrix,
+    static bool IsStrokeHairlineOrEquivalent(const GrStyle& style, const SkMatrix& matrix,
                                              SkScalar* outCoverage) {
-        if (stroke.isDashed()) {
+        if (style.pathEffect()) {
             return false;
         }
+        const SkStrokeRec& stroke = style.strokeRec();
         if (stroke.isHairlineStyle()) {
             if (outCoverage) {
                 *outCoverage = SK_Scalar1;
@@ -279,13 +276,12 @@ private:
         drawArgs.fColor = 0xFFFFFFFF;
         drawArgs.fViewMatrix = args.fViewMatrix;
         drawArgs.fPath = args.fPath;
-        drawArgs.fStroke = &GrStrokeInfo::FillInfo();
+        drawArgs.fStyle = &GrStyle::SimpleFill();
         drawArgs.fAntiAlias = false;
         drawArgs.fGammaCorrect = false;
         this->drawPath(drawArgs);
     }
 
-
     typedef SkRefCnt INHERITED;
 };
 
index c9e21ad..8994186 100644 (file)
@@ -79,7 +79,7 @@ GrPathRenderer* GrPathRendererChain::getPathRenderer(
     }
     if (minStencilSupport != GrPathRenderer::kNoSupport_StencilSupport) {
         // We don't support (and shouldn't need) stenciling of non-fill paths.
-        if (!args.fStroke->isFillStyle() || args.fStroke->isDashed()) {
+        if (!args.fStyle->isSimpleFill()) {
             return nullptr;
         }
     }
index a3bba4b..d1345c9 100644 (file)
@@ -54,7 +54,7 @@ private:
 GrPathRange* GrPathRendering::createGlyphs(const SkTypeface* typeface,
                                            const SkScalerContextEffects& effects,
                                            const SkDescriptor* desc,
-                                           const GrStrokeInfo& stroke) {
+                                           const GrStyle& style) {
     if (nullptr == typeface) {
         typeface = SkTypeface::GetDefaultTypeface();
         SkASSERT(nullptr != typeface);
@@ -62,7 +62,7 @@ GrPathRange* GrPathRendering::createGlyphs(const SkTypeface* typeface,
 
     if (desc) {
         SkAutoTUnref<GlyphGenerator> generator(new GlyphGenerator(*typeface, effects, *desc));
-        return this->createPathRange(generator, stroke);
+        return this->createPathRange(generator, style);
     }
 
     SkScalerContextRec rec;
@@ -83,5 +83,5 @@ GrPathRange* GrPathRendering::createGlyphs(const SkTypeface* typeface,
     SkScalerContextEffects noEffects;
 
     SkAutoTUnref<GlyphGenerator> generator(new GlyphGenerator(*typeface, noEffects, *genericDesc));
-    return this->createPathRange(generator, stroke);
+    return this->createPathRange(generator, style);
 }
index 8ee3d7b..8eea321 100644 (file)
@@ -17,7 +17,7 @@ class SkDescriptor;
 class SkTypeface;
 class GrPath;
 class GrStencilSettings;
-class GrStrokeInfo;
+class GrStyle;
 
 /**
  * Abstract class wrapping HW path rendering API.
@@ -81,21 +81,23 @@ public:
      * Creates a new gpu path, based on the specified path and stroke and returns it.
      * The caller owns a ref on the returned path which must be balanced by a call to unref.
      *
-     * @param skPath the path geometry.
-     * @param stroke the path stroke.
-     * @return a new path.
+     * @param SkPath    the geometry.
+     * @param GrStyle   the style applied to the path. Styles with non-dash path effects are not
+     *                  allowed.
+     * @return a new GPU path object.
      */
-    virtual GrPath* createPath(const SkPath&, const GrStrokeInfo&) = 0;
+    virtual GrPath* createPath(const SkPath&, const GrStyle&) = 0;
 
     /**
-     * Creates a range of gpu paths with a common stroke. The caller owns a ref on the
+     * Creates a range of gpu paths with a common style. The caller owns a ref on the
      * returned path range which must be balanced by a call to unref.
      *
      * @param PathGenerator class that generates SkPath objects for each path in the range.
-     * @param GrStrokeInfo   the common stroke applied to each path in the range.
+     * @param GrStyle   the common style applied to each path in the range. Styles with non-dash
+     *                  path effects are not allowed.
      * @return a new path range.
      */
-    virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStrokeInfo&) = 0;
+    virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStyle&) = 0;
 
     /**
      * Creates a range of glyph paths, indexed by glyph id. The glyphs will have an
@@ -118,15 +120,15 @@ public:
      *                     including with the stroke information baked directly into
      *                     the outlines.
      *
-     * @param GrStrokeInfo Common stroke that the GPU will apply to every path. Note that
-     *                     if the glyph outlines contain baked-in strokes from the font
-     *                     descriptor, the GPU stroke will be applied on top of those
+     * @param GrStyle      Common style that the GPU will apply to every path. Note that
+     *                     if the glyph outlines contain baked-in styles from the font
+     *                     descriptor, the GPU style will be applied on top of those
      *                     outlines.
      *
      * @return a new path range populated with glyphs.
      */
     GrPathRange* createGlyphs(const SkTypeface*, const SkScalerContextEffects&,
-                              const SkDescriptor*, const GrStrokeInfo&);
+                              const SkDescriptor*, const GrStyle&);
 
     /** None of these params are optional, pointers used just to avoid making copies. */
     struct StencilPathArgs {
index f57d7eb..9fa202a 100644 (file)
@@ -70,24 +70,24 @@ const GrBuffer* GrResourceProvider::createQuadIndexBuffer() {
     return this->createInstancedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey);
 }
 
-GrPath* GrResourceProvider::createPath(const SkPath& path, const GrStrokeInfo& stroke) {
+GrPath* GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
     SkASSERT(this->gpu()->pathRendering());
-    return this->gpu()->pathRendering()->createPath(path, stroke);
+    return this->gpu()->pathRendering()->createPath(path, style);
 }
 
 GrPathRange* GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen,
-                                                 const GrStrokeInfo& stroke) {
+                                                 const GrStyle& style) {
     SkASSERT(this->gpu()->pathRendering());
-    return this->gpu()->pathRendering()->createPathRange(gen, stroke);
+    return this->gpu()->pathRendering()->createPathRange(gen, style);
 }
 
 GrPathRange* GrResourceProvider::createGlyphs(const SkTypeface* tf,
                                               const SkScalerContextEffects& effects,
                                               const SkDescriptor* desc,
-                                              const GrStrokeInfo& stroke) {
+                                              const GrStyle& style) {
 
     SkASSERT(this->gpu()->pathRendering());
-    return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, stroke);
+    return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, style);
 }
 
 GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType,
index 9701bf1..ea3a28a 100644 (file)
@@ -18,7 +18,7 @@ class GrPath;
 class GrRenderTarget;
 class GrSingleOwner;
 class GrStencilAttachment;
-class GrStrokeInfo;
+class GrStyle;
 class SkDescriptor;
 class SkPath;
 class SkTypeface;
@@ -83,10 +83,10 @@ public:
      * Factories for GrPath and GrPathRange objects. It's an error to call these if path rendering
      * is not supported.
      */
-    GrPath* createPath(const SkPath&, const GrStrokeInfo&);
-    GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStrokeInfo&);
+    GrPath* createPath(const SkPath&, const GrStyle&);
+    GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStyle&);
     GrPathRange* createGlyphs(const SkTypeface*, const SkScalerContextEffects&,
-                              const SkDescriptor*, const GrStrokeInfo&);
+                              const SkDescriptor*, const GrStyle&);
 
     using GrTextureProvider::assignUniqueKeyToResource;
     using GrTextureProvider::findAndRefResourceByUniqueKey;
index b69edab..937b343 100644 (file)
@@ -11,6 +11,7 @@
 #include "GrDrawTarget.h"
 #include "GrGpu.h"
 #include "GrPipelineBuilder.h"
+#include "GrStyle.h"
 
 #include "SkData.h"
 #include "SkDistanceFieldGen.h"
@@ -117,22 +118,11 @@ void GrSWMaskHelper::draw(const SkRect& rect, SkRegion::Op op,
 /**
  * Draw a single path element of the clip stack into the accumulation bitmap
  */
-void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op,
+void GrSWMaskHelper::draw(const SkPath& path, const GrStyle& style, SkRegion::Op op,
                           bool antiAlias, uint8_t alpha) {
-
     SkPaint paint;
-    if (stroke.isHairlineStyle()) {
-        paint.setStyle(SkPaint::kStroke_Style);
-    } else {
-        if (stroke.isFillStyle()) {
-            paint.setStyle(SkPaint::kFill_Style);
-        } else {
-            paint.setStyle(SkPaint::kStroke_Style);
-            paint.setStrokeJoin(stroke.getJoin());
-            paint.setStrokeCap(stroke.getCap());
-            paint.setStrokeWidth(stroke.getWidth());
-        }
-    }
+    paint.setPathEffect(sk_ref_sp(style.pathEffect()));
+    style.strokeRec().applyToPaint(&paint);
     paint.setAntiAlias(antiAlias);
 
     SkTBlitterAllocator allocator;
@@ -307,7 +297,7 @@ void GrSWMaskHelper::toSDF(unsigned char* sdf) {
  */
 GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
                                                  const SkPath& path,
-                                                 const SkStrokeRec& stroke,
+                                                 const GrStyle& style,
                                                  const SkIRect& resultBounds,
                                                  bool antiAlias,
                                                  const SkMatrix* matrix) {
@@ -317,7 +307,7 @@ GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
         return nullptr;
     }
 
-    helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
+    helper.draw(path, style, SkRegion::kReplace_Op, antiAlias, 0xFF);
 
     GrTexture* texture(helper.createTexture());
     if (!texture) {
index d1e1265..ee38ab7 100644 (file)
@@ -55,11 +55,10 @@ public:
     bool init(const SkIRect& resultBounds, const SkMatrix* matrix, bool allowCompression = true);
 
     // Draw a single rect into the accumulation bitmap using the specified op
-    void draw(const SkRect& rect, SkRegion::Op op,
-              bool antiAlias, uint8_t alpha);
+    void draw(const SkRect& rect, SkRegion::Op op, bool antiAlias, uint8_t alpha);
 
     // Draw a single path into the accumuation bitmap using the specified op
-    void draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op,
+    void draw(const SkPath& path, const GrStyle& style, SkRegion::Op op,
               bool antiAlias, uint8_t alpha);
 
     // Move the mask generation results from the internal bitmap to the gpu.
@@ -77,7 +76,7 @@ public:
     // to the GPU. The result is returned.
     static GrTexture* DrawPathMaskToTexture(GrContext* context,
                                             const SkPath& path,
-                                            const SkStrokeRec& stroke,
+                                            const GrStyle& style,
                                             const SkIRect& resultBounds,
                                             bool antiAlias,
                                             const SkMatrix* matrix);
index ca2ca64..dc0dbd2 100644 (file)
 
 ////////////////////////////////////////////////////////////////////////////////
 bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-    if (nullptr == fContext) {
-        return false;
-    }
-    if (args.fStroke->isDashed()) {
-        return false;
-    }
-    return true;
+    return SkToBool(fContext);
 }
 
 namespace {
@@ -130,7 +124,7 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) {
     }
 
     SkAutoTUnref<GrTexture> texture(
-            GrSWMaskHelper::DrawPathMaskToTexture(fContext, *args.fPath, *args.fStroke,
+            GrSWMaskHelper::DrawPathMaskToTexture(fContext, *args.fPath, *args.fStyle,
                                                   devPathBounds,
                                                   args.fAntiAlias, args.fViewMatrix));
     if (nullptr == texture) {
diff --git a/src/gpu/GrStrokeInfo.cpp b/src/gpu/GrStrokeInfo.cpp
deleted file mode 100644 (file)
index b37c660..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrStrokeInfo.h"
-#include "GrResourceKey.h"
-#include "SkDashPathPriv.h"
-
-bool all_dash_intervals_zero(const SkScalar* intervals, int count) {
-    for (int i = 0 ; i < count; ++i) {
-        if (intervals[i] != 0) {
-            return false;
-        }
-    }
-    return true;
-}
-
-bool GrStrokeInfo::applyDashToPath(SkPath* dst, GrStrokeInfo* dstStrokeInfo,
-                                   const SkPath& src) const {
-    if (this->isDashed()) {
-        SkPathEffect::DashInfo info;
-        info.fIntervals = fIntervals.get();
-        info.fCount = fIntervals.count();
-        info.fPhase = fDashPhase;
-        GrStrokeInfo filteredStroke(*this, false);
-        // Handle the case where all intervals are 0 and we simply drop the dash effect
-        if (all_dash_intervals_zero(fIntervals.get(), fIntervals.count())) {
-            *dstStrokeInfo = filteredStroke;
-            *dst = src;
-            return true;
-        }
-        // See if we can filter the dash into a path on cpu
-        if (SkDashPath::FilterDashPath(dst, src, &filteredStroke, nullptr, info)) {
-            *dstStrokeInfo = filteredStroke;
-            return true;
-        }
-    }
-    return false;
-}
-
-void GrStrokeInfo::asUniqueKeyFragment(uint32_t* data) const {
-    const int kSkScalarData32Cnt = sizeof(SkScalar) / sizeof(uint32_t);
-    enum {
-        kStyleBits = 2,
-        kJoinBits = 2,
-        kCapBits = 32 - kStyleBits - kJoinBits,
-
-        kJoinShift = kStyleBits,
-        kCapShift = kJoinShift + kJoinBits,
-    };
-
-    static_assert(SkStrokeRec::kStyleCount <= (1 << kStyleBits), "style_shift_will_be_wrong");
-    static_assert(SkPaint::kJoinCount <= (1 << kJoinBits), "cap_shift_will_be_wrong");
-    static_assert(SkPaint::kCapCount <= (1 << kCapBits), "cap_does_not_fit");
-    uint32_t styleKey = this->getStyle();
-    if (this->needToApply()) {
-        styleKey |= this->getJoin() << kJoinShift;
-        styleKey |= this->getCap() << kCapShift;
-    }
-    int i = 0;
-    data[i++] = styleKey;
-
-    // Memcpy the scalar fields. Does not "reinterpret_cast<SkScalar&>(data[i]) = ..." due to
-    // scalars having more strict alignment requirements than what data can guarantee. The
-    // compiler should optimize memcpys to assignments.
-    SkScalar scalar;
-    scalar = this->getMiter();
-    memcpy(&data[i], &scalar, sizeof(scalar));
-    i += kSkScalarData32Cnt;
-
-    scalar = this->getWidth();
-    memcpy(&data[i], &scalar, sizeof(scalar));
-    i += kSkScalarData32Cnt;
-
-    if (this->isDashed()) {
-        SkScalar phase = this->getDashPhase();
-        memcpy(&data[i], &phase, sizeof(phase));
-        i += kSkScalarData32Cnt;
-
-        int32_t count = this->getDashCount() & static_cast<int32_t>(~1);
-        SkASSERT(count == this->getDashCount());
-        const SkScalar* intervals = this->getDashIntervals();
-        int intervalByteCnt = count * sizeof(SkScalar);
-        memcpy(&data[i], intervals, intervalByteCnt);
-        // Enable the line below if fields are added after dashing.
-        SkDEBUGCODE(i += kSkScalarData32Cnt * count);
-    }
-
-    SkASSERT(this->computeUniqueKeyFragmentData32Cnt() == i);
-}
diff --git a/src/gpu/GrStrokeInfo.h b/src/gpu/GrStrokeInfo.h
deleted file mode 100644 (file)
index 9cf7d83..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrStrokeInfo_DEFINED
-#define GrStrokeInfo_DEFINED
-
-#include "SkPathEffect.h"
-#include "SkStrokeRec.h"
-#include "SkTemplates.h"
-
-class GrUniqueKey;
-
-/*
- * GrStrokeInfo encapsulates all the pertinent infomation regarding the stroke. The SkStrokeRec
- * which holds information on fill style, width, miter, cap, and join. It also holds information
- * about the dash like intervals, count, and phase.
- */
-class GrStrokeInfo : public SkStrokeRec {
-public:
-    static const GrStrokeInfo& FillInfo() {
-        static const GrStrokeInfo gFill(kFill_InitStyle);
-        return gFill;
-    }
-
-    GrStrokeInfo(SkStrokeRec::InitStyle style)
-        : INHERITED(style)
-        , fDashType(SkPathEffect::kNone_DashType) {
-    }
-
-    GrStrokeInfo(const GrStrokeInfo& src, bool includeDash = true)
-        : INHERITED(src) {
-        if (includeDash && src.isDashed()) {
-            fDashType = src.fDashType;
-            fDashPhase = src.fDashPhase;
-            fIntervals.reset(src.getDashCount());
-            memcpy(fIntervals.get(), src.fIntervals.get(), fIntervals.count() * sizeof(SkScalar));
-        } else {
-            fDashType = SkPathEffect::kNone_DashType;
-        }
-    }
-
-    GrStrokeInfo(const SkPaint& paint, SkPaint::Style styleOverride)
-        : INHERITED(paint, styleOverride)
-        , fDashType(SkPathEffect::kNone_DashType) {
-        this->init(paint);
-    }
-
-    explicit GrStrokeInfo(const SkPaint& paint)
-        : INHERITED(paint)
-        , fDashType(SkPathEffect::kNone_DashType) {
-        this->init(paint);
-    }
-
-    GrStrokeInfo& operator=(const GrStrokeInfo& other) {
-        if (other.isDashed()) {
-            fDashType = other.fDashType;
-            fDashPhase = other.fDashPhase;
-            fIntervals.reset(other.getDashCount());
-            memcpy(fIntervals.get(), other.fIntervals.get(), fIntervals.count() * sizeof(SkScalar));
-        } else {
-            this->removeDash();
-        }
-        this->INHERITED::operator=(other);
-        return *this;
-    }
-
-    bool hasEqualEffect(const GrStrokeInfo& other) const {
-        if (this->isDashed() != other.isDashed()) {
-            return false;
-        }
-        if (this->isDashed()) {
-            if (fDashPhase != other.fDashPhase ||
-                fIntervals.count() != other.fIntervals.count() ||
-                memcmp(fIntervals.get(), other.fIntervals.get(),
-                       fIntervals.count() * sizeof(SkScalar)) != 0) {
-                return false;
-            }
-        }
-        return this->INHERITED::hasEqualEffect(other);
-    }
-
-    /*
-     * This functions takes in a patheffect and updates the dashing information if the path effect
-     * is a Dash type. Returns true if the path effect is a dashed effect and we are stroking,
-     * otherwise it returns false.
-     */
-    bool setDashInfo(const SkPathEffect* pe) {
-        if (pe && !this->isFillStyle()) {
-            SkPathEffect::DashInfo dashInfo;
-            fDashType = pe->asADash(&dashInfo);
-            if (SkPathEffect::kDash_DashType == fDashType) {
-                fIntervals.reset(dashInfo.fCount);
-                dashInfo.fIntervals = fIntervals.get();
-                pe->asADash(&dashInfo);
-                fDashPhase = dashInfo.fPhase;
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /*
-     * Like the above, but sets with an explicit SkPathEffect::DashInfo
-     */
-    bool setDashInfo(const SkPathEffect::DashInfo& info) {
-        if (!this->isFillStyle()) {
-            fDashType = SkPathEffect::kDash_DashType;
-            fDashPhase = info.fPhase;
-            fIntervals.reset(info.fCount);
-            for (int i = 0; i < fIntervals.count(); i++) {
-                fIntervals[i] = info.fIntervals[i];
-            }
-            return true;
-        }
-        return false;
-    }
-
-    bool isDashed() const {
-        return (!this->isFillStyle() && SkPathEffect::kDash_DashType == fDashType);
-    }
-
-    int32_t getDashCount() const {
-        SkASSERT(this->isDashed());
-        return fIntervals.count();
-    }
-
-    SkScalar getDashPhase() const {
-        SkASSERT(this->isDashed());
-        return fDashPhase;
-    }
-
-    const SkScalar* getDashIntervals() const {
-        SkASSERT(this->isDashed());
-        return fIntervals.get();
-    }
-
-    void removeDash() {
-        fDashType = SkPathEffect::kNone_DashType;
-    }
-
-    /** Applies the dash to a path, if the stroke info has dashing.
-     * @return true if the dashing was applied (dst and dstStrokeInfo will be modified).
-     *         false if the stroke info did not have dashing. The dst and dstStrokeInfo
-     *               will be unmodified. The stroking in the SkStrokeRec might still
-     *               be applicable.
-     */
-    bool applyDashToPath(SkPath* dst, GrStrokeInfo* dstStrokeInfo, const SkPath& src) const;
-
-    /**
-     * Computes the length of the data that will be written by asUniqueKeyFragment() function.
-     */
-    int computeUniqueKeyFragmentData32Cnt() const {
-        const int kSkScalarData32Cnt = sizeof(SkScalar) / sizeof(uint32_t);
-        // SkStrokeRec data: 32 bits for style+join+cap and 2 scalars for miter and width.
-        int strokeKeyData32Cnt = 1 + 2 * kSkScalarData32Cnt;
-
-        if (this->isDashed()) {
-            // One scalar for dash phase and one for each dash value.
-            strokeKeyData32Cnt += (1 + this->getDashCount()) * kSkScalarData32Cnt;
-        }
-        return strokeKeyData32Cnt;
-    }
-
-    /**
-     * Writes the object contents as uint32_t data, to be used with GrUniqueKey.
-     * Note: the data written does not encode the length, so care must be taken to ensure
-     * that the full unique key data is encoded properly. For example, GrStrokeInfo
-     * fragment can be placed last in the sequence, at fixed index.
-     */
-    void asUniqueKeyFragment(uint32_t*) const;
-
-private:
-    // Prevent accidental usage, should use GrStrokeInfo::hasEqualEffect.
-    bool hasEqualEffect(const SkStrokeRec& other) const;
-
-    void init(const SkPaint& paint) {
-        const SkPathEffect* pe = paint.getPathEffect();
-        this->setDashInfo(pe);
-    }
-
-    SkPathEffect::DashType fDashType;
-    SkScalar               fDashPhase;
-    SkAutoSTArray<2, SkScalar> fIntervals;
-    typedef SkStrokeRec INHERITED;
-};
-
-#endif
index 6166b56..07efb40 100644 (file)
@@ -85,6 +85,11 @@ public:
         this->initPathEffect(paint.getPathEffect());
     }
 
+    explicit GrStyle(const SkPaint& paint, SkPaint::Style overrideStyle)
+            : fStrokeRec(paint, overrideStyle) {
+        this->initPathEffect(paint.getPathEffect());
+    }
+
     GrStyle& operator=(const GrStyle& that) {
         fPathEffect = that.fPathEffect;
         fDashInfo = that.fDashInfo;
@@ -133,6 +138,12 @@ public:
         return this->pathEffect() || (!fStrokeRec.isFillStyle() && !fStrokeRec.isHairlineStyle());
     }
 
+    static SkScalar MatrixToScaleFactor(const SkMatrix& matrix) {
+        // getMaxScale will return -1 if the matrix has perspective. In that case we can use a scale
+        // factor of 1. This isn't necessarily a good choice and in the future we might consider
+        // taking a bounds here for the perspective case.
+        return SkScalarAbs(matrix.getMaxScale());
+    }
     /**
      * Applies just the path effect and returns remaining stroke information. This will fail if
      * there is no path effect. dst may or may not have been overwritten on failure. Scale controls
index 86a84ce..e962978 100644 (file)
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
-#include "GrStrokeInfo.h"
 #include "GrTestUtils.h"
+#include "GrStyle.h"
+#include "SkDashPathPriv.h"
 #include "SkMatrix.h"
-#include "SkPathEffect.h"
 #include "SkPath.h"
 #include "SkRRect.h"
 
@@ -237,26 +237,53 @@ SkStrokeRec TestStrokeRec(SkRandom* random) {
     return rec;
 }
 
-GrStrokeInfo TestStrokeInfo(SkRandom* random) {
-    SkStrokeRec::InitStyle style =
+void TestStyle(SkRandom* random, GrStyle* style) {
+    SkStrokeRec::InitStyle initStyle =
             SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
-    GrStrokeInfo strokeInfo(style);
-    randomize_stroke_rec(&strokeInfo, random);
-    SkPathEffect::DashInfo dashInfo;
-    dashInfo.fCount = random->nextRangeU(1, 50) * 2;
-    dashInfo.fIntervals = new SkScalar[dashInfo.fCount];
-    SkScalar sum = 0;
-    for (int i = 0; i < dashInfo.fCount; i++) {
-        dashInfo.fIntervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01),
-                                                         SkDoubleToScalar(10.0));
-        sum += dashInfo.fIntervals[i];
+    SkStrokeRec stroke(initStyle);
+    randomize_stroke_rec(&stroke, random);
+    sk_sp<SkPathEffect> pe;
+    if (random->nextBool()) {
+        int cnt = random->nextRangeU(1, 50) * 2;
+        SkAutoTDeleteArray<SkScalar> intervals(new SkScalar[cnt]);
+        SkScalar sum = 0;
+        for (int i = 0; i < cnt; i++) {
+            intervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01),
+                                                   SkDoubleToScalar(10.0));
+            sum += intervals[i];
+        }
+        SkScalar phase = random->nextRangeScalar(0, sum);
+        pe = TestDashPathEffect::Make(intervals.get(), cnt, phase);
     }
-    dashInfo.fPhase = random->nextRangeScalar(0, sum);
-    strokeInfo.setDashInfo(dashInfo);
-    delete[] dashInfo.fIntervals;
-    return strokeInfo;
+    *style = GrStyle(stroke, pe.get());
+}
+
+TestDashPathEffect::TestDashPathEffect(const SkScalar* intervals, int count, SkScalar phase) {
+    fCount = count;
+    fIntervals.reset(count);
+    memcpy(fIntervals.get(), intervals, count * sizeof(SkScalar));
+    SkDashPath::CalcDashParameters(phase, intervals, count, &fInitialDashLength,
+                                   &fInitialDashIndex, &fIntervalLength, &fPhase);
+}
+
+    bool TestDashPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
+                                     const SkRect* cullRect) const {
+    return SkDashPath::InternalFilter(dst, src, rec, cullRect, fIntervals.get(), fCount,
+                                      fInitialDashLength, fInitialDashIndex, fIntervalLength);
 }
 
-};
+SkPathEffect::DashType TestDashPathEffect::asADash(DashInfo* info) const {
+    if (info) {
+        if (info->fCount >= fCount && info->fIntervals) {
+            memcpy(info->fIntervals, fIntervals.get(), fCount * sizeof(SkScalar));
+        }
+        info->fCount = fCount;
+        info->fPhase = fPhase;
+    }
+    return kDash_DashType;
+}
+
+
+}  // namespace GrTest
 
 #endif
index ba5848b..a0f81e7 100644 (file)
@@ -15,7 +15,7 @@
 #include "GrImageIDTextureAdjuster.h"
 #include "GrLayerHoister.h"
 #include "GrRecordReplaceDraw.h"
-#include "GrStrokeInfo.h"
+#include "GrStyle.h"
 #include "GrTracing.h"
 #include "SkCanvasPriv.h"
 #include "SkErrorInternals.h"
@@ -454,7 +454,7 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
     }
 
     if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
-        GrStrokeInfo strokeInfo(paint, SkPaint::kStroke_Style);
+        GrStyle style(paint, SkPaint::kStroke_Style);
         GrPaint grPaint;
         if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
                               this->surfaceProps().isGammaCorrect(), &grPaint)) {
@@ -464,7 +464,7 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
         path.setIsVolatile(true);
         path.moveTo(pts[0]);
         path.lineTo(pts[1]);
-        fDrawContext->drawPath(fClip, grPaint, *draw.fMatrix, path, strokeInfo);
+        fDrawContext->drawPath(fClip, grPaint, *draw.fMatrix, path, style);
         return;
     }
 
@@ -535,9 +535,8 @@ void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint
         return;
     }
 
-    GrStrokeInfo strokeInfo(paint);
-
-    fDrawContext->drawRect(fClip, grPaint, *draw.fMatrix, rect, &strokeInfo);
+    GrStyle style(paint);
+    fDrawContext->drawRect(fClip, grPaint, *draw.fMatrix, rect, &style);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -554,7 +553,7 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
         return;
     }
 
-    GrStrokeInfo strokeInfo(paint);
+    GrStyle style(paint);
     if (paint.getMaskFilter()) {
         // try to hit the fast path for drawing filtered round rects
 
@@ -577,7 +576,7 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
                                                                         &grPaint,
                                                                         fClip,
                                                                         *draw.fMatrix,
-                                                                        strokeInfo,
+                                                                        style.strokeRec(),
                                                                         devRRect)) {
                         return;
                     }
@@ -587,7 +586,7 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
         }
     }
 
-    if (paint.getMaskFilter() || paint.getPathEffect()) {
+    if (paint.getMaskFilter() || style.pathEffect()) {
         // The only mask filter the native rrect drawing code could've handle was taken
         // care of above.
         // A path effect will presumably transform this rrect into something else.
@@ -601,9 +600,9 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
         return;
     }
 
-    SkASSERT(!strokeInfo.isDashed());
+    SkASSERT(!style.pathEffect());
 
-    fDrawContext->drawRRect(fClip, grPaint, *draw.fMatrix, rect, strokeInfo);
+    fDrawContext->drawRRect(fClip, grPaint, *draw.fMatrix, rect, style);
 }
 
 
@@ -675,10 +674,7 @@ void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint
         return;
     }
 
-    GrStrokeInfo strokeInfo(paint);
-    SkASSERT(!strokeInfo.isDashed());
-
-    fDrawContext->drawOval(fClip, grPaint, *draw.fMatrix, oval, strokeInfo);
+    fDrawContext->drawOval(fClip, grPaint, *draw.fMatrix, oval, GrStyle(paint));
 }
 
 #include "SkMaskFilter.h"
index 9750c96..156bb7e 100644 (file)
@@ -10,7 +10,7 @@
 #include "GrBlurUtils.h"
 #include "GrCaps.h"
 #include "GrDrawContext.h"
-#include "GrStrokeInfo.h"
+#include "GrStyle.h"
 #include "GrTextureParamsAdjuster.h"
 #include "SkDraw.h"
 #include "SkGrPriv.h"
@@ -240,6 +240,6 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer,
     rectPath.addRect(clippedDstRect);
     rectPath.setIsVolatile(true);
     GrBlurUtils::drawPathWithMaskFilter(this->context(), fDrawContext.get(), fClip,
-                                        rectPath, &grPaint, viewMatrix, mf, paint.getPathEffect(),
-                                        GrStrokeInfo::FillInfo(), true);
+                                        rectPath, &grPaint, viewMatrix, mf, GrStyle::SimpleFill(),
+                                        true);
 }
index 8c55de7..f557c9b 100644 (file)
@@ -18,7 +18,6 @@
 #include "GrPathUtils.h"
 #include "GrProcessor.h"
 #include "GrPipelineBuilder.h"
-#include "GrStrokeInfo.h"
 #include "SkGeometry.h"
 #include "SkPathPriv.h"
 #include "SkString.h"
@@ -682,7 +681,7 @@ const GrGeometryProcessor* QuadEdgeEffect::TestCreate(GrProcessorTestData* d) {
 
 bool GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     return (args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
-            args.fStroke->isFillStyle() && !args.fPath->isInverseFillType() &&
+            args.fStyle->isSimpleFill() && !args.fPath->isInverseFillType() &&
             args.fPath->isConvex());
 }
 
index f891b8d..ba52bf9 100644 (file)
@@ -81,13 +81,14 @@ GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() {
 
 ////////////////////////////////////////////////////////////////////////////////
 bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-
+    // We don't currently apply the dash or factor it into the DF key. (skbug.com/5082)
+    if (args.fStyle->pathEffect()) {
+        return false;
+    }
     // TODO: Support inverse fill
     if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias ||
-        SkStrokeRec::kHairline_Style == args.fStroke->getStyle() ||
-        args.fPath->isInverseFillType() || args.fPath->isVolatile() ||
-        // We don't currently apply the dash or factor it into the DF key. (skbug.com/5082)
-        args.fStroke->isDashed()) {
+        args.fStyle->isSimpleHairline() || args.fPath->isInverseFillType() ||
+        args.fPath->isVolatile()) {
         return false;
     }
 
@@ -100,16 +101,23 @@ bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c
     // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP
     // the goal is to accelerate rendering of lots of small paths that may be scaling
     SkScalar maxScale = args.fViewMatrix->getMaxScale();
+#if 0 // This is more accurate but changes some GMs. TODO: Standalone change to enable this.
+    SkRect bounds;
+    args.fStyle->adjustBounds(&bounds, args.fPath->getBounds());
+    SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
+#else
     const SkRect& bounds = args.fPath->getBounds();
     SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
+    const SkStrokeRec& stroke = args.fStyle->strokeRec();
     // Approximate stroked size by adding the maximum of the stroke width or 2x the miter limit
-    if (!args.fStroke->isFillStyle()) {
-        SkScalar extraWidth = args.fStroke->getWidth();
-        if (SkPaint::kMiter_Join == args.fStroke->getJoin()) {
-            extraWidth = SkTMax(extraWidth, 2.0f*args.fStroke->getMiter());
+    if (!stroke.isFillStyle()) {
+        SkScalar extraWidth = stroke.getWidth();
+        if (SkPaint::kMiter_Join == stroke.getJoin()) {
+            extraWidth = SkTMax(extraWidth, 2.0f*stroke.getMiter());
         }
         maxDim += extraWidth;
     }
+#endif
 
     return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP;
 }
@@ -552,11 +560,12 @@ bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) {
         }
     }
 
-    AADistanceFieldPathBatch::Geometry geometry(*args.fStroke);
-    if (SkStrokeRec::kFill_Style == args.fStroke->getStyle()) {
+    // It's ok to ignore style's path effect because canDrawPath filtered out path effects.
+    AADistanceFieldPathBatch::Geometry geometry(args.fStyle->strokeRec());
+    if (args.fStyle->isSimpleFill()) {
         geometry.fPath = *args.fPath;
     } else {
-        args.fStroke->applyToPath(&geometry.fPath, *args.fPath);
+        args.fStyle->strokeRec().applyToPath(&geometry.fPath, *args.fPath);
     }
     geometry.fColor = args.fColor;
     geometry.fAntiAlias = args.fAntiAlias;
index effd8c3..db4bbdf 100644 (file)
@@ -618,7 +618,12 @@ bool GrAAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const
         return false;
     }
 
-    if (!IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullptr)) {
+    if (!IsStrokeHairlineOrEquivalent(*args.fStyle, *args.fViewMatrix, nullptr)) {
+        return false;
+    }
+
+    // We don't currently handle dashing in this class though perhaps we should.
+    if (args.fStyle->pathEffect()) {
         return false;
     }
 
@@ -939,11 +944,11 @@ void AAHairlineBatch::onPrepareDraws(Target* target) const {
 static GrDrawBatch* create_hairline_batch(GrColor color,
                                           const SkMatrix& viewMatrix,
                                           const SkPath& path,
-                                          const GrStrokeInfo& stroke,
+                                          const GrStyle& style,
                                           const SkIRect& devClipBounds) {
     SkScalar hairlineCoverage;
     uint8_t newCoverage = 0xff;
-    if (GrPathRenderer::IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) {
+    if (GrPathRenderer::IsStrokeHairlineOrEquivalent(style, viewMatrix, &hairlineCoverage)) {
         newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
     }
 
@@ -964,7 +969,7 @@ bool GrAAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
     args.fPipelineBuilder->clip().getConservativeBounds(rt->width(), rt->height(), &devClipBounds);
 
     SkAutoTUnref<GrDrawBatch> batch(create_hairline_batch(args.fColor, *args.fViewMatrix, *args.fPath,
-                                                          *args.fStroke, devClipBounds));
+                                                          *args.fStyle, devClipBounds));
     args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
 
     return true;
@@ -977,11 +982,10 @@ bool GrAAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
 DRAW_BATCH_TEST_DEFINE(AAHairlineBatch) {
     GrColor color = GrRandomColor(random);
     SkMatrix viewMatrix = GrTest::TestMatrix(random);
-    GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle);
     SkPath path = GrTest::TestPath(random);
     SkIRect devClipBounds;
     devClipBounds.setEmpty();
-    return create_hairline_batch(color, viewMatrix, path, stroke, devClipBounds);
+    return create_hairline_batch(color, viewMatrix, path, GrStyle::SimpleHairline(), devClipBounds);
 }
 
 #endif
index 446f67f..91d3338 100644 (file)
@@ -17,7 +17,7 @@
 #include "GrPathUtils.h"
 #include "GrProcessor.h"
 #include "GrPipelineBuilder.h"
-#include "GrStrokeInfo.h"
+#include "GrStyle.h"
 #include "SkGeometry.h"
 #include "SkString.h"
 #include "SkTraceEvent.h"
@@ -46,16 +46,20 @@ bool GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& arg
     if (!args.fPath->isConvex()) {
         return false;
     }
-    if (args.fStroke->getStyle() == SkStrokeRec::kStroke_Style) {
+    if (args.fStyle->pathEffect()) {
+        return false;
+    }
+    const SkStrokeRec& stroke = args.fStyle->strokeRec();
+    if (stroke.getStyle() == SkStrokeRec::kStroke_Style) {
         if (!args.fViewMatrix->isSimilarity()) {
             return false;
         }
-        SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * args.fStroke->getWidth();
-        return strokeWidth >= 1.0f && strokeWidth <= kMaxStrokeWidth && !args.fStroke->isDashed() &&
-                SkPathPriv::IsClosedSingleContour(*args.fPath) &&
-                args.fStroke->getJoin() != SkPaint::Join::kRound_Join;
+        SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth();
+        return strokeWidth >= 1.0f && strokeWidth <= kMaxStrokeWidth &&
+               SkPathPriv::IsClosedSingleContour(*args.fPath) &&
+               stroke.getJoin() != SkPaint::Join::kRound_Join;
     }
-    return args.fStroke->getStyle() == SkStrokeRec::kFill_Style;
+    return stroke.getStyle() == SkStrokeRec::kFill_Style;
 }
 
 // extract the result vertices and indices from the GrAAConvexTessellator
@@ -325,10 +329,10 @@ bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
     geometry.fColor = args.fColor;
     geometry.fViewMatrix = *args.fViewMatrix;
     geometry.fPath = *args.fPath;
-    geometry.fStrokeWidth = args.fStroke->isFillStyle() ? -1.0f : args.fStroke->getWidth();
-    geometry.fJoin = args.fStroke->isFillStyle() ? SkPaint::Join::kMiter_Join :
-                                                   args.fStroke->getJoin();
-    geometry.fMiterLimit = args.fStroke->getMiter();
+    bool fill = args.fStyle->isSimpleFill();
+    geometry.fStrokeWidth = fill ? -1.0f : args.fStyle->strokeRec().getWidth();
+    geometry.fJoin = fill ? SkPaint::Join::kMiter_Join : args.fStyle->strokeRec().getJoin();
+    geometry.fMiterLimit = args.fStyle->strokeRec().getMiter();
 
     SkAutoTUnref<GrDrawBatch> batch(AAFlatteningConvexPathBatch::Create(geometry));
     args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
index 9ee27c7..8cb8046 100644 (file)
@@ -12,8 +12,8 @@
 
 bool GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     SkPoint pts[2];
-    if (args.fStroke->isDashed() && args.fPath->isLine(pts)) {
-        return GrDashingEffect::CanDrawDashLine(pts, *args.fStroke, *args.fViewMatrix);
+    if (args.fStyle->isDashed() && args.fPath->isLine(pts)) {
+        return GrDashingEffect::CanDrawDashLine(pts, *args.fStyle, *args.fViewMatrix);
     }
     return false;
 }
@@ -28,7 +28,7 @@ bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
                                                                          pts,
                                                                          args.fAntiAlias,
                                                                          msaaIsEnabled,
-                                                                         *args.fStroke));
+                                                                         *args.fStyle));
     if (!batch) {
         return false;
     }
index 1de0bf7..9994b26 100644 (file)
@@ -422,22 +422,21 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
                                              GrColor color,
                                              const SkMatrix& viewMatrix,
                                              const SkPath& path,
-                                             const GrStrokeInfo& origStroke,
+                                             const GrStyle& origStyle,
                                              bool stencilOnly) {
-    SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke);
+    const GrStyle* style = &origStyle;
 
     SkScalar hairlineCoverage;
     uint8_t newCoverage = 0xff;
-    if (IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, &hairlineCoverage)) {
+    bool isHairline = false;
+    if (IsStrokeHairlineOrEquivalent(*style, viewMatrix, &hairlineCoverage)) {
         newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
-
-        if (!stroke->isHairlineStyle()) {
-            stroke.writable()->setHairlineStyle();
-        }
+        style = &GrStyle::SimpleHairline();
+        isHairline = true;
+    } else {
+        SkASSERT(style->isSimpleFill());
     }
 
-    const bool isHairline = stroke->isHairlineStyle();
-
     // Save the current xp on the draw state so we can reset it if needed
     const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
     SkAutoTUnref<const GrXPFactory> backupXPFactory(SkSafeRef(xpFactory));
@@ -460,7 +459,7 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
         lastPassIsBounds = false;
         drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
     } else {
-        if (single_pass_path(path, *stroke)) {
+        if (single_pass_path(path, style->strokeRec())) {
             passCount = 1;
             if (stencilOnly) {
                 passes[0] = &gDirectToStencil;
@@ -596,10 +595,11 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
 }
 
 bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-    // this class can draw any path with any fill but doesn't do any anti-aliasing.
-    return !args.fAntiAlias && (args.fStroke->isFillStyle() ||
-                                IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix,
-                                                             nullptr));
+    // this class can draw any path with any simple fill style but doesn't do any anti-aliasing.
+    return !args.fAntiAlias &&
+           (args.fStyle->isSimpleFill() || IsStrokeHairlineOrEquivalent(*args.fStyle,
+                                                                        *args.fViewMatrix,
+                                                                        nullptr));
 }
 
 bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
@@ -609,7 +609,7 @@ bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
                                   args.fColor,
                                   *args.fViewMatrix,
                                   *args.fPath,
-                                  *args.fStroke,
+                                  *args.fStyle,
                                   false);
 }
 
@@ -618,7 +618,7 @@ void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
     SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType());
     SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType());
     this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix,
-                           *args.fPath, GrStrokeInfo::FillInfo(), true);
+                           *args.fPath, GrStyle::SimpleFill(), true);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -631,7 +631,7 @@ DRAW_BATCH_TEST_DEFINE(DefaultPathBatch) {
 
     // For now just hairlines because the other types of draws require two batches.
     // TODO we should figure out a way to combine the stencil and cover steps into one batch
-    GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle);
+    GrStyle style(SkStrokeRec::kHairline_InitStyle);
     SkPath path = GrTest::TestPath(random);
 
     // Compute srcSpaceTol
index 8156462..8a74d3a 100644 (file)
@@ -35,7 +35,7 @@ private:
                           GrColor,
                           const SkMatrix& viewMatrix,
                           const SkPath&,
-                          const GrStrokeInfo&,
+                          const GrStyle&,
                           bool stencilOnly);
 
     bool    fSeparateStencil;
index a9ba06c..a382c42 100644 (file)
@@ -29,7 +29,7 @@ static const float kTolerance = 0.5f;
 ////////////////////////////////////////////////////////////////////////////////
 // Helpers for drawPath
 
-static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) {
+static inline bool single_pass_path(const SkPath& path) {
     if (!path.isInverseFillType()) {
         return path.isConvex();
     }
@@ -38,7 +38,7 @@ static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& strok
 
 GrPathRenderer::StencilSupport
 GrMSAAPathRenderer::onGetStencilSupport(const SkPath& path) const {
-    if (single_pass_path(path, SkStrokeRec(SkStrokeRec::kFill_InitStyle))) {
+    if (single_pass_path(path)) {
         return GrPathRenderer::kNoRestriction_StencilSupport;
     } else {
         return GrPathRenderer::kStencilOnly_StencilSupport;
@@ -571,9 +571,7 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawTarget* target,
                                           GrColor color,
                                           const SkMatrix& viewMatrix,
                                           const SkPath& path,
-                                          const GrStrokeInfo& origStroke,
                                           bool stencilOnly) {
-    SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke);
 
     const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
     SkAutoTUnref<const GrXPFactory> backupXPFactory(SkSafeRef(xpFactory));
@@ -586,7 +584,7 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawTarget* target,
     bool                        reverse = false;
     bool                        lastPassIsBounds;
 
-    if (single_pass_path(path, *stroke)) {
+    if (single_pass_path(path)) {
         passCount = 1;
         if (stencilOnly) {
             passes[0] = &gDirectToStencil;
@@ -703,34 +701,35 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawTarget* target,
 }
 
 bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-    return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullptr) &&
-           !args.fAntiAlias;
+    // This path renderer does not support hairlines. We defer on anything that could be handled
+    // as a hairline by another path renderer. Also, arbitrary path effects could produce
+    // a hairline result.
+    return !IsStrokeHairlineOrEquivalent(*args.fStyle, *args.fViewMatrix, nullptr) &&
+           !args.fStyle->hasNonDashPathEffect() && !args.fAntiAlias;
 }
 
 bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrMSAAPathRenderer::onDrawPath");
-    SkPath path;
-    GrStrokeInfo stroke(*args.fStroke);
-    if (stroke.isDashed()) {
-        if (!stroke.applyDashToPath(&path, &stroke, *args.fPath)) {
+    SkPath tmpPath;
+    const SkPath* path;
+    if (args.fStyle->applies()) {
+        SkStrokeRec::InitStyle fill;
+        SkScalar styleScale = GrStyle::MatrixToScaleFactor(*args.fViewMatrix);
+        if (!args.fStyle->applyToPath(&tmpPath, &fill, *args.fPath, styleScale)) {
             return false;
         }
+        // We don't accept styles that are hairlines or have path effects that could produce
+        // hairlines.
+        SkASSERT(SkStrokeRec::kFill_InitStyle == fill);
+        path = &tmpPath;
     } else {
-        path = *args.fPath;
-    }
-    if (!stroke.isFillStyle()) {
-        stroke.setResScale(SkScalarAbs(args.fViewMatrix->getMaxScale()));
-        if (!stroke.applyToPath(&path, path)) {
-            return false;
-        }
-        stroke.setFillStyle();
+        path = args.fPath;
     }
     return this->internalDrawPath(args.fTarget,
                                   args.fPipelineBuilder,
                                   args.fColor,
                                   *args.fViewMatrix,
-                                  path,
-                                  stroke,
+                                  *path,
                                   false);
 }
 
@@ -739,7 +738,7 @@ void GrMSAAPathRenderer::onStencilPath(const StencilPathArgs& args) {
     SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType());
     SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType());
     this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, *args.fViewMatrix,
-                           *args.fPath, GrStrokeInfo::FillInfo(), true);
+                           *args.fPath, true);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
index a355360..434a962 100644 (file)
@@ -26,7 +26,6 @@ private:
                           GrColor,
                           const SkMatrix& viewMatrix,
                           const SkPath&,
-                          const GrStrokeInfo&,
                           bool stencilOnly);
 
     typedef GrPathRenderer INHERITED;
index 46993c7..c26b4c0 100644 (file)
@@ -23,7 +23,7 @@
 #include "GrPathUtils.h"
 #include "GrProcessor.h"
 #include "GrPipelineBuilder.h"
-#include "GrStrokeInfo.h"
+#include "GrStyle.h"
 #include "GrTessellator.h"
 #include "batches/GrVertexBatch.h"
 #include "glsl/GrGLSLGeometryProcessor.h"
@@ -778,7 +778,7 @@ bool GrPLSPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     // We have support for even-odd rendering, but are having some troublesome
     // seams. Disable in the presence of even-odd for now.
     return args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
-            args.fStroke->isFillStyle() && !args.fPath->isInverseFillType() &&
+            args.fStyle->isSimpleFill() && !args.fPath->isInverseFillType() &&
             args.fPath->getFillType() == SkPath::FillType::kWinding_FillType;
 }
 
index 6933efe..9d8d07d 100644 (file)
@@ -14,7 +14,7 @@
 #include "GrPath.h"
 #include "GrRenderTarget.h"
 #include "GrResourceProvider.h"
-#include "GrStrokeInfo.h"
+#include "GrStyle.h"
 #include "batches/GrRectBatchFactory.h"
 
 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
@@ -31,7 +31,9 @@ GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider*
 }
 
 bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-    if (args.fStroke->isHairlineStyle()) {
+    // GrPath doesn't support hairline paths. Also, an arbitrary path effect could change
+    // the style type to hairline.
+    if (!args.fStyle->hasNonDashPathEffect() || args.fStyle->strokeRec().isHairlineStyle()) {
         return false;
     }
     if (!args.fIsStencilDisabled) {
@@ -45,19 +47,19 @@ bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c
 }
 
 static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const SkPath& skPath,
-                           const GrStrokeInfo& stroke) {
+                           const GrStyle& style) {
     GrUniqueKey key;
     bool isVolatile;
-    GrPath::ComputeKey(skPath, stroke, &key, &isVolatile);
+    GrPath::ComputeKey(skPath, style, &key, &isVolatile);
     SkAutoTUnref<GrPath> path(
         static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key)));
     if (!path) {
-        path.reset(resourceProvider->createPath(skPath, stroke));
+        path.reset(resourceProvider->createPath(skPath, style));
         if (!isVolatile) {
             resourceProvider->assignUniqueKeyToResource(key, path);
         }
     } else {
-        SkASSERT(path->isEqualTo(skPath, stroke));
+        SkASSERT(path->isEqualTo(skPath, style));
     }
     return path.release();
 }
@@ -66,14 +68,14 @@ void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
                               "GrStencilAndCoverPathRenderer::onStencilPath");
     SkASSERT(!args.fPath->isInverseFillType());
-    SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, *args.fPath, GrStrokeInfo::FillInfo()));
+    SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, *args.fPath, GrStyle::SimpleFill()));
     args.fTarget->stencilPath(*args.fPipelineBuilder, *args.fViewMatrix, p, p->getFillType());
 }
 
 bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
                               "GrStencilAndCoverPathRenderer::onDrawPath");
-    SkASSERT(!args.fStroke->isHairlineStyle());
+    SkASSERT(!args.fStyle->strokeRec().isHairlineStyle());
     const SkPath& path = *args.fPath;
     GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder;
     const SkMatrix& viewMatrix = *args.fViewMatrix;
@@ -85,7 +87,7 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
         pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag);
     }
 
-    SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStroke));
+    SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStyle));
 
     if (path.isInverseFillType()) {
         static constexpr GrStencilSettings kInvertedStencilPass(
index 2c8520b..d2cfb6e 100644 (file)
@@ -105,9 +105,10 @@ GrTessellatingPathRenderer::GrTessellatingPathRenderer() {
 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     // This path renderer can draw all fill styles, all stroke styles except hairlines, but does
     // not do antialiasing. It can do convex and concave paths, but we'll leave the convex ones to
-    // simpler algorithms.
-    return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullptr) &&
-           !args.fAntiAlias && !args.fPath->isConvex();
+    // simpler algorithms. Similary, we skip the non-hairlines that can be treated as hairline.
+    // An arbitrary path effect could produce a hairline result so we pass on those.
+    return !IsStrokeHairlineOrEquivalent(*args.fStyle, *args.fViewMatrix, nullptr) &&
+           !args.fStyle->hasNonDashPathEffect() && !args.fAntiAlias && !args.fPath->isConvex();
 }
 
 class TessellatingPathBatch : public GrVertexBatch {
@@ -116,10 +117,10 @@ public:
 
     static GrDrawBatch* Create(const GrColor& color,
                                const SkPath& path,
-                               const GrStrokeInfo& stroke,
+                               const GrStyle& style,
                                const SkMatrix& viewMatrix,
                                SkRect clipBounds) {
-        return new TessellatingPathBatch(color, path, stroke, viewMatrix, clipBounds);
+        return new TessellatingPathBatch(color, path, style, viewMatrix, clipBounds);
     }
 
     const char* name() const override { return "TessellatingPathBatch"; }
@@ -142,48 +143,51 @@ private:
     }
 
     void draw(Target* target, const GrGeometryProcessor* gp) const {
+        GrResourceProvider* rp = target->resourceProvider();
+        SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance;
+        SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMatrix,
+                                                        fPath.getBounds());
+
+        SkScalar styleScale = SK_Scalar1;
+        if (fStyle.applies()) {
+            styleScale = GrStyle::MatrixToScaleFactor(fViewMatrix);
+        }
+
         // construct a cache key from the path's genID and the view matrix
         static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
         GrUniqueKey key;
-        int clipBoundsSize32 =
+        int clipBoundsCnt =
             fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) : 0;
-        int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt();
-        GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strokeDataSize32);
-        builder[0] = fPath.getGenerationID();
-        builder[1] = fPath.getFillType();
-        // For inverse fills, the tessellation is dependent on clip bounds.
-        if (fPath.isInverseFillType()) {
-            memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds));
-        }
-        fStroke.asUniqueKeyFragment(&builder[2 + clipBoundsSize32]);
-        builder.finish();
-        GrResourceProvider* rp = target->resourceProvider();
-        SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrBuffer>(key));
-        int actualCount;
-        SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance;
-        SkScalar tol = GrPathUtils::scaleToleranceToSrc(
-            screenSpaceTol, fViewMatrix, fPath.getBounds());
-        if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) {
-            this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCount);
-            return;
+        int styleDataCnt = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectAndStrokeRec);
+        if (styleDataCnt >= 0) {
+            GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsCnt + styleDataCnt);
+            builder[0] = fPath.getGenerationID();
+            builder[1] = fPath.getFillType();
+            // For inverse fills, the tessellation is dependent on clip bounds.
+            if (fPath.isInverseFillType()) {
+                memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds));
+            }
+            if (styleDataCnt) {
+                GrStyle::WriteKey(&builder[2 + clipBoundsCnt], fStyle,
+                                  GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
+            }
+            builder.finish();
+            SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrBuffer>(key));
+            int actualCount;
+            if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) {
+                this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCount);
+                return;
+            }
         }
 
         SkPath path;
-        GrStrokeInfo stroke(fStroke);
-        if (stroke.isDashed()) {
-            if (!stroke.applyDashToPath(&path, &stroke, fPath)) {
-                return;
-            }
+        if (fStyle.applies()) {
+            SkStrokeRec::InitStyle fill;
+            SkAssertResult(fStyle.applyToPath(&path, &fill, fPath, styleScale));
+            SkASSERT(SkStrokeRec::kFill_InitStyle == fill);
         } else {
             path = fPath;
         }
-        if (!stroke.isFillStyle()) {
-            stroke.setResScale(SkScalarAbs(fViewMatrix.getMaxScale()));
-            if (!stroke.applyToPath(&path, path)) {
-                return;
-            }
-            stroke.setFillStyle();
-        }
         bool isLinear;
         bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
         StaticVertexAllocator allocator(rp, canMapVB);
@@ -192,7 +196,7 @@ private:
             return;
         }
         this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count);
-        if (!fPath.isVolatile()) {
+        if (!fPath.isVolatile() && styleDataCnt >= 0) {
             TessInfo info;
             info.fTolerance = isLinear ? 0 : tol;
             info.fCount = count;
@@ -240,13 +244,13 @@ private:
 
     TessellatingPathBatch(const GrColor& color,
                           const SkPath& path,
-                          const GrStrokeInfo& stroke,
+                          const GrStyle& style,
                           const SkMatrix& viewMatrix,
                           const SkRect& clipBounds)
       : INHERITED(ClassID())
       , fColor(color)
       , fPath(path)
-      , fStroke(stroke)
+      , fStyle(style)
       , fViewMatrix(viewMatrix) {
         const SkRect& pathBounds = path.getBounds();
         fClipBounds = clipBounds;
@@ -258,14 +262,13 @@ private:
         } else {
             fBounds = path.getBounds();
         }
-        SkScalar radius = stroke.getInflationRadius();
-        fBounds.outset(radius, radius);
+        style.adjustBounds(&fBounds, fBounds);
         viewMatrix.mapRect(&fBounds);
     }
 
     GrColor                 fColor;
     SkPath                  fPath;
-    GrStrokeInfo            fStroke;
+    GrStyle                 fStyle;
     SkMatrix                fViewMatrix;
     SkRect                  fClipBounds; // in source space
     GrXPOverridesForBatch   fPipelineInfo;
@@ -291,7 +294,7 @@ bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
     }
     vmi.mapRect(&clipBounds);
     SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fColor, *args.fPath,
-                                                                  *args.fStroke, *args.fViewMatrix,
+                                                                  *args.fStyle, *args.fViewMatrix,
                                                                   clipBounds));
     args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
 
@@ -313,8 +316,11 @@ DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) {
         SkFAIL("Cannot invert matrix\n");
     }
     vmi.mapRect(&clipBounds);
-    GrStrokeInfo strokeInfo = GrTest::TestStrokeInfo(random);
-    return TessellatingPathBatch::Create(color, path, strokeInfo, viewMatrix, clipBounds);
+    GrStyle style;
+    do {
+        GrTest::TestStyle(random, &style);
+    } while (style.strokeRec().isHairlineStyle());
+    return TessellatingPathBatch::Create(color, path, style, viewMatrix, clipBounds);
 }
 
 #endif
index f1e8016..8a38ebe 100644 (file)
@@ -16,7 +16,7 @@
 #include "GrDefaultGeoProcFactory.h"
 #include "GrInvariantOutput.h"
 #include "GrProcessor.h"
-#include "GrStrokeInfo.h"
+#include "GrStyle.h"
 #include "SkGr.h"
 #include "batches/GrVertexBatch.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
@@ -29,7 +29,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 // Returns whether or not the gpu can fast path the dash line effect.
-bool GrDashingEffect::CanDrawDashLine(const SkPoint pts[2], const GrStrokeInfo& strokeInfo,
+bool GrDashingEffect::CanDrawDashLine(const SkPoint pts[2], const GrStyle& style,
                                       const SkMatrix& viewMatrix) {
     // Pts must be either horizontal or vertical in src space
     if (pts[0].fX != pts[1].fX && pts[0].fY != pts[1].fY) {
@@ -42,16 +42,16 @@ bool GrDashingEffect::CanDrawDashLine(const SkPoint pts[2], const GrStrokeInfo&
         return false;
     }
 
-    if (!strokeInfo.isDashed() || 2 != strokeInfo.getDashCount()) {
+    if (!style.isDashed() || 2 != style.dashIntervalCnt()) {
         return false;
     }
 
-    const SkScalar* intervals = strokeInfo.getDashIntervals();
+    const SkScalar* intervals = style.dashIntervals();
     if (0 == intervals[0] && 0 == intervals[1]) {
         return false;
     }
 
-    SkPaint::Cap cap = strokeInfo.getCap();
+    SkPaint::Cap cap = style.strokeRec().getCap();
     // Current we do don't handle Round or Square cap dashes
     if (SkPaint::kRound_Cap == cap && intervals[0] != 0.f) {
         return false;
@@ -690,14 +690,15 @@ private:
 };
 
 static GrDrawBatch* create_batch(GrColor color, const SkMatrix& viewMatrix, const SkPoint pts[2],
-                                 bool useAA, const GrStrokeInfo& strokeInfo, bool msaaRT) {
-    const SkScalar* intervals = strokeInfo.getDashIntervals();
-    SkScalar phase = strokeInfo.getDashPhase();
+                                 bool useAA, const GrStyle& style, bool msaaRT) {
+    SkASSERT(GrDashingEffect::CanDrawDashLine(pts, style, viewMatrix));
+    const SkScalar* intervals = style.dashIntervals();
+    SkScalar phase = style.dashPhase();
 
-    SkPaint::Cap cap = strokeInfo.getCap();
+    SkPaint::Cap cap = style.strokeRec().getCap();
 
     DashBatch::Geometry geometry;
-    geometry.fSrcStrokeWidth = strokeInfo.getWidth();
+    geometry.fSrcStrokeWidth = style.strokeRec().getWidth();
 
     // the phase should be normalized to be [0, sum of all intervals)
     SkASSERT(phase >= 0 && phase < intervals[0] + intervals[1]);
@@ -747,8 +748,8 @@ GrDrawBatch* GrDashingEffect::CreateDashLineBatch(GrColor color,
                                                   const SkPoint pts[2],
                                                   bool useAA,
                                                   bool msaaIsEnabled,
-                                                  const GrStrokeInfo& strokeInfo) {
-    return create_batch(color, viewMatrix, pts, useAA, strokeInfo, msaaIsEnabled);
+                                                  const GrStyle& style) {
+    return create_batch(color, viewMatrix, pts, useAA, style, msaaIsEnabled);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1289,17 +1290,11 @@ DRAW_BATCH_TEST_DEFINE(DashBatch) {
     p.setStyle(SkPaint::kStroke_Style);
     p.setStrokeWidth(SkIntToScalar(1));
     p.setStrokeCap(cap);
+    p.setPathEffect(GrTest::TestDashPathEffect::Make(intervals, 2, phase));
 
-    GrStrokeInfo strokeInfo(p);
+    GrStyle style(p);
 
-    SkPathEffect::DashInfo info;
-    info.fIntervals = intervals;
-    info.fCount = 2;
-    info.fPhase = phase;
-    SkDEBUGCODE(bool success = ) strokeInfo.setDashInfo(info);
-    SkASSERT(success);
-
-    return create_batch(color, viewMatrix, pts, useAA, strokeInfo, msaaRT);
+    return create_batch(color, viewMatrix, pts, useAA, style, msaaRT);
 }
 
 #endif
index d67a63e..8899820 100644 (file)
@@ -14,7 +14,7 @@
 
 class GrClip;
 class GrDrawBatch;
-class GrStrokeInfo;
+class GrStyle;
 
 namespace GrDashingEffect {
     GrDrawBatch* CreateDashLineBatch(GrColor,
@@ -22,8 +22,8 @@ namespace GrDashingEffect {
                                      const SkPoint pts[2],
                                      bool useAA,
                                      bool msaaIsEnabled,
-                                     const GrStrokeInfo& strokeInfo);
-    bool CanDrawDashLine(const SkPoint pts[2], const GrStrokeInfo& strokeInfo,
+                                     const GrStyle& style);
+    bool CanDrawDashLine(const SkPoint pts[2], const GrStyle& style,
                          const SkMatrix& viewMatrix);
 }
 
index ed5a31d..0546018 100644 (file)
@@ -8,6 +8,7 @@
 #include "GrGLPath.h"
 #include "GrGLPathRendering.h"
 #include "GrGLGpu.h"
+#include "GrStyle.h"
 
 namespace {
 inline GrGLubyte verb_to_gl_path_cmd(SkPath::Verb verb) {
@@ -251,9 +252,7 @@ void GrGLPath::InitPathObjectPathData(GrGLGpu* gpu,
     SkAssertResult(init_path_object_for_general_path<false>(gpu, pathID, skPath));
 }
 
-void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const GrStrokeInfo& stroke) {
-    SkASSERT(stroke.needToApply());
-    SkASSERT(!stroke.isDashed());
+void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const SkStrokeRec& stroke) {
     SkASSERT(!stroke.isHairlineStyle());
     GR_GL_CALL(gpu->glInterface(),
                PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
@@ -270,8 +269,8 @@ void GrGLPath::InitPathObjectEmptyPath(GrGLGpu* gpu, GrGLuint pathID) {
     GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, nullptr, 0, GR_GL_FLOAT, nullptr));
 }
 
-GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& origStroke)
-    : INHERITED(gpu, origSkPath, origStroke),
+GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStyle& style)
+    : INHERITED(gpu, origSkPath, style),
       fPathID(gpu->glPathRendering()->genPaths(1)) {
 
     if (origSkPath.isEmpty()) {
@@ -281,21 +280,21 @@ GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& o
     } else {
         const SkPath* skPath = &origSkPath;
         SkTLazy<SkPath> tmpPath;
-        const GrStrokeInfo* stroke = &origStroke;
-        GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle);
+        SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
 
-        if (stroke->isDashed()) {
+        if (style.pathEffect()) {
             // Skia stroking and NVPR stroking differ with respect to dashing
             // pattern.
-            // Convert a dashing to either a stroke or a fill.
-            if (stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) {
+            // Convert a dashing (or other path effect) to either a stroke or a fill.
+            if (style.applyPathEffectToPath(tmpPath.init(), &stroke, *skPath, SK_Scalar1)) {
                 skPath = tmpPath.get();
-                stroke = &tmpStroke;
             }
+        } else {
+            stroke = style.strokeRec();
         }
 
         bool didInit = false;
-        if (stroke->needToApply() && stroke->getCap() != SkPaint::kButt_Cap) {
+        if (stroke.needToApply() && stroke.getCap() != SkPaint::kButt_Cap) {
             // Skia stroking and NVPR stroking differ with respect to stroking
             // end caps of empty subpaths.
             // Convert stroke to fill if path contains empty subpaths.
@@ -304,10 +303,9 @@ GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& o
                 if (!tmpPath.isValid()) {
                     tmpPath.init();
                 }
-                SkAssertResult(stroke->applyToPath(tmpPath.get(), *skPath));
+                SkAssertResult(stroke.applyToPath(tmpPath.get(), *skPath));
                 skPath = tmpPath.get();
-                tmpStroke.setFillStyle();
-                stroke = &tmpStroke;
+                stroke.setFillStyle();
             }
         }
 
@@ -315,18 +313,16 @@ GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& o
             InitPathObjectPathData(gpu, fPathID, *skPath);
         }
 
-        fShouldStroke = stroke->needToApply();
-        fShouldFill = stroke->isFillStyle() ||
-                stroke->getStyle() == SkStrokeRec::kStrokeAndFill_Style;
+        fShouldStroke = stroke.needToApply();
+        fShouldFill = stroke.isFillStyle() ||
+                stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
 
         fFillType = convert_skpath_filltype(skPath->getFillType());
         fBounds = skPath->getBounds();
-
+        SkScalar radius = stroke.getInflationRadius();
+        fBounds.outset(radius, radius);
         if (fShouldStroke) {
-            InitPathObjectStroke(gpu, fPathID, *stroke);
-
-            // FIXME: try to account for stroking, without rasterizing the stroke.
-            fBounds.outset(stroke->getWidth(), stroke->getWidth());
+            InitPathObjectStroke(gpu, fPathID, stroke);
         }
     }
 
index 1ef1346..ddcee53 100644 (file)
@@ -12,6 +12,7 @@
 #include "gl/GrGLTypes.h"
 
 class GrGLGpu;
+class GrStyle;
 
 /**
  * Currently this represents a path built using GL_NV_path_rendering. If we
@@ -27,12 +28,12 @@ public:
     static void InitPathObjectPathData(GrGLGpu*,
                                        GrGLuint pathID,
                                        const SkPath&);
-    static void InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const GrStrokeInfo& stroke);
+    static void InitPathObjectStroke(GrGLGpu*, GrGLuint pathID, const SkStrokeRec&);
 
     static void InitPathObjectEmptyPath(GrGLGpu*, GrGLuint pathID);
 
 
-    GrGLPath(GrGLGpu* gpu, const SkPath& path, const GrStrokeInfo& stroke);
+    GrGLPath(GrGLGpu*, const SkPath&, const GrStyle&);
     GrGLuint pathID() const { return fPathID; }
 
     bool shouldStroke() const { return fShouldStroke; }
index 6ed7bcc..da1e9fe 100644 (file)
@@ -10,9 +10,9 @@
 #include "GrGLPathRendering.h"
 #include "GrGLGpu.h"
 
-GrGLPathRange::GrGLPathRange(GrGLGpu* gpu, PathGenerator* pathGenerator, const GrStrokeInfo& stroke)
+GrGLPathRange::GrGLPathRange(GrGLGpu* gpu, PathGenerator* pathGenerator, const GrStyle& style)
     : INHERITED(gpu, pathGenerator),
-      fStroke(stroke),
+      fStyle(style),
       fBasePathID(gpu->glPathRendering()->genPaths(this->getNumPaths())),
       fGpuMemorySize(0) {
     this->init();
@@ -23,9 +23,9 @@ GrGLPathRange::GrGLPathRange(GrGLGpu* gpu,
                              GrGLuint basePathID,
                              int numPaths,
                              size_t gpuMemorySize,
-                             const GrStrokeInfo& stroke)
+                             const GrStyle& style)
     : INHERITED(gpu, numPaths),
-      fStroke(stroke),
+      fStyle(style),
       fBasePathID(basePathID),
       fGpuMemorySize(gpuMemorySize) {
     this->init();
@@ -33,19 +33,20 @@ GrGLPathRange::GrGLPathRange(GrGLGpu* gpu,
 }
 
 void GrGLPathRange::init() {
+    const SkStrokeRec& stroke = fStyle.strokeRec();
     // Must force fill:
     // * dashing: NVPR stroke dashing is different to Skia.
     // * end caps: NVPR stroking degenerate contours with end caps is different to Skia.
-    bool forceFill = fStroke.isDashed() ||
-            (fStroke.needToApply() && fStroke.getCap() != SkPaint::kButt_Cap);
+    bool forceFill = fStyle.pathEffect() ||
+            (stroke.needToApply() && stroke.getCap() != SkPaint::kButt_Cap);
 
     if (forceFill) {
         fShouldStroke = false;
         fShouldFill = true;
     } else {
-        fShouldStroke = fStroke.needToApply();
-        fShouldFill = fStroke.isFillStyle() ||
-                fStroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
+        fShouldStroke = stroke.needToApply();
+        fShouldFill = stroke.isFillStyle() ||
+                stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
     }
 }
 
@@ -54,7 +55,6 @@ void GrGLPathRange::onInitPath(int index, const SkPath& origSkPath) const {
     if (nullptr == gpu) {
         return;
     }
-
     // Make sure the path at this index hasn't been initted already.
     SkDEBUGCODE(
         GrGLboolean isPath;
@@ -65,32 +65,25 @@ void GrGLPathRange::onInitPath(int index, const SkPath& origSkPath) const {
         GrGLPath::InitPathObjectEmptyPath(gpu, fBasePathID + index);
     } else if (fShouldStroke) {
         GrGLPath::InitPathObjectPathData(gpu, fBasePathID + index, origSkPath);
-        GrGLPath::InitPathObjectStroke(gpu, fBasePathID + index, fStroke);
+        GrGLPath::InitPathObjectStroke(gpu, fBasePathID + index, fStyle.strokeRec());
     } else {
         const SkPath* skPath = &origSkPath;
         SkTLazy<SkPath> tmpPath;
-        const GrStrokeInfo* stroke = &fStroke;
-        GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle);
-
-        // Dashing must be applied to the path. However, if dashing is present,
-        // we must convert all the paths to fills. The GrStrokeInfo::applyDash leaves
-        // simple paths as strokes but converts other paths to fills.
-        // Thus we must stroke the strokes here, so that all paths in the
-        // path range are using the same style.
-        if (fStroke.isDashed()) {
-            if (!stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) {
+        if (!fStyle.isSimpleFill()) {
+            SkStrokeRec::InitStyle fill;
+            // The path effect must be applied to the path. However, if a path effect is present,
+            // we must convert all the paths to fills. The path effect application may leave
+            // simple paths as strokes but converts other paths to fills.
+            // Thus we must stroke the strokes here, so that all paths in the
+            // path range are using the same style.
+            if (!fStyle.applyToPath(tmpPath.init(), &fill, *skPath, SK_Scalar1)) {
                 return;
             }
+            // We shouldn't have allowed hairlines or arbitrary path effect styles to get here
+            // so after application we better have a filled path.
+            SkASSERT(SkStrokeRec::kFill_InitStyle == fill);
             skPath = tmpPath.get();
-            stroke = &tmpStroke;
-        }
-        if (stroke->needToApply()) {
-            if (!tmpPath.isValid()) {
-                tmpPath.init();
-            }
-            if (!stroke->applyToPath(tmpPath.get(), *tmpPath.get())) {
-                return;
-            }
+
         }
         GrGLPath::InitPathObjectPathData(gpu, fBasePathID + index, *skPath);
     }
index ed9766d..7d92010 100644 (file)
@@ -9,7 +9,7 @@
 #define GrGLPathRange_DEFINED
 
 #include "../GrPathRange.h"
-#include "GrStrokeInfo.h"
+#include "GrStyle.h"
 #include "gl/GrGLTypes.h"
 
 class GrGLGpu;
@@ -26,7 +26,7 @@ public:
      * Initialize a GL path range from a PathGenerator. This class will allocate
      * the GPU path objects and initialize them lazily.
      */
-    GrGLPathRange(GrGLGpu*, PathGenerator*, const GrStrokeInfo&);
+    GrGLPathRange(GrGLGpu*, PathGenerator*, const GrStyle&);
 
     /**
      * Initialize a GL path range from an existing range of pre-initialized GPU
@@ -37,7 +37,7 @@ public:
                   GrGLuint basePathID,
                   int numPaths,
                   size_t gpuMemorySize,
-                  const GrStrokeInfo&);
+                  const GrStyle&);
 
     GrGLuint basePathID() const { return fBasePathID; }
 
@@ -54,7 +54,7 @@ private:
     void init();
     size_t onGpuMemorySize() const override { return fGpuMemorySize; }
 
-    const GrStrokeInfo fStroke;
+    const GrStyle fStyle;
     GrGLuint fBasePathID;
     mutable size_t fGpuMemorySize;
     bool fShouldStroke;
index 0ecf58a..5616f9d 100644 (file)
@@ -106,13 +106,13 @@ void GrGLPathRendering::resetContext() {
     fHWPathStencilSettings.invalidate();
 }
 
-GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStrokeInfo& stroke) {
-    return new GrGLPath(this->gpu(), inPath, stroke);
+GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStyle& style) {
+    return new GrGLPath(this->gpu(), inPath, style);
 }
 
 GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
-                                                const GrStrokeInfo& stroke) {
-    return new GrGLPathRange(this->gpu(), pathGenerator, stroke);
+                                                const GrStyle& style) {
+    return new GrGLPathRange(this->gpu(), pathGenerator, style);
 }
 
 void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
index b39c866..8fb699d 100644 (file)
@@ -16,6 +16,7 @@
 
 class GrGLNameAllocator;
 class GrGLGpu;
+class GrStyle;
 
 /**
  * This class wraps the NV_path_rendering extension and manages its various
@@ -33,9 +34,9 @@ public:
     virtual ~GrGLPathRendering();
 
     // GrPathRendering implementations.
-    GrPath* createPath(const SkPath&, const GrStrokeInfo&) override;
+    GrPath* createPath(const SkPath&, const GrStyle&) override;
     virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*,
-                                         const GrStrokeInfo&) override;
+                                         const GrStyle&) override;
 
     /* Called when the 3D context state is unknown. */
     void resetContext();
index c2c1c56..cc01884 100644 (file)
@@ -235,6 +235,18 @@ void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrDrawContex
     }
 }
 
+static inline int style_key_cnt(const GrStyle& style) {
+    int cnt = GrStyle::KeySize(style, GrStyle::Apply::kPathEffectAndStrokeRec);
+    // We should be able to make a key because we filtered out arbitrary path effects.
+    SkASSERT(cnt > 0);
+    return cnt;
+}
+
+static inline void write_style_key(uint32_t* dst, const GrStyle& style) {
+    // Pass 1 for the scale since the GPU will apply the style not GrStyle::applyToPath().
+    GrStyle::WriteKey(dst, style, GrStyle::Apply::kPathEffectAndStrokeRec, SK_Scalar1);
+}
+
 const GrStencilAndCoverTextContext::TextBlob&
 GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob,
                                                    const SkPaint& skPaint) {
@@ -253,11 +265,11 @@ GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob,
         fCacheSize += blob->cpuMemorySize();
         return *blob;
     } else {
-        GrStrokeInfo stroke(skPaint);
+        GrStyle style(skPaint);
         SkSTArray<4, uint32_t, true> key;
-        key.reset(1 + stroke.computeUniqueKeyFragmentData32Cnt());
+        key.reset(1 + style_key_cnt(style));
         key[0] = skBlob->uniqueID();
-        stroke.asUniqueKeyFragment(&key[1]);
+        write_style_key(&key[1], style);
         if (TextBlob** found = fBlobKeyCache.find(key)) {
             fLRUList.remove(*found);
             fLRUList.addToTail(*found);
@@ -353,41 +365,48 @@ private:
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
 GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
-    : fStroke(fontAndStroke),
+    : fStyle(fontAndStroke),
       fFont(fontAndStroke),
       fTotalGlyphCount(0),
       fFallbackGlyphCount(0),
       fDetachedGlyphCache(nullptr),
       fLastDrawnGlyphsID(SK_InvalidUniqueID) {
     SkASSERT(fFont.getTextSize() > 0);
-    SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported.
+    SkASSERT(!fStyle.hasNonDashPathEffect()); // Arbitrary path effects not supported.
+    SkASSERT(!fStyle.isSimpleHairline()); // Hairlines are not supported.
 
     // Setting to "fill" ensures that no strokes get baked into font outlines. (We use the GPU path
     // rendering API for stroking).
     fFont.setStyle(SkPaint::kFill_Style);
 
-    if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle()) {
+    if (fFont.isFakeBoldText() && fStyle.isSimpleFill()) {
+        const SkStrokeRec& stroke = fStyle.strokeRec();
         // Instead of letting fake bold get baked into the glyph outlines, do it with GPU stroke.
         SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(),
                                                     kStdFakeBoldInterpKeys,
                                                     kStdFakeBoldInterpValues,
                                                     kStdFakeBoldInterpLength);
         SkScalar extra = SkScalarMul(fFont.getTextSize(), fakeBoldScale);
-        fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
-                               true /*strokeAndFill*/);
 
+        SkStrokeRec strokeRec(SkStrokeRec::kFill_InitStyle);
+        strokeRec.setStrokeStyle(stroke.needToApply() ? stroke.getWidth() + extra : extra,
+                                 true /*strokeAndFill*/);
+        fStyle = GrStyle(strokeRec, fStyle.pathEffect());
         fFont.setFakeBoldText(false);
     }
 
-    if (!fFont.getPathEffect() && !fStroke.isDashed()) {
+    if (!fFont.getPathEffect() && !fStyle.isDashed()) {
+        const SkStrokeRec& stroke = fStyle.strokeRec();
         // We can draw the glyphs from canonically sized paths.
         fTextRatio = fFont.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
         fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fFont.getTextSize();
 
         // Compensate for the glyphs being scaled by fTextRatio.
-        if (!fStroke.isFillStyle()) {
-            fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
-                                   SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
+        if (!fStyle.isSimpleFill()) {
+            SkStrokeRec strokeRec(SkStrokeRec::kFill_InitStyle);
+            strokeRec.setStrokeStyle(stroke.getWidth() / fTextRatio,
+                                     SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle());
+            fStyle = GrStyle(strokeRec, fStyle.pathEffect());
         }
 
         fFont.setLinearText(true);
@@ -407,7 +426,7 @@ GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
     }
 
     // Generate the key that will be used to cache the GPU glyph path objects.
-    if (fUsingRawGlyphPaths && fStroke.isFillStyle()) {
+    if (fUsingRawGlyphPaths && fStyle.isSimpleFill()) {
         static const GrUniqueKey::Domain kRawFillPathGlyphDomain = GrUniqueKey::GenerateDomain();
 
         const SkTypeface* typeface = fFont.getTypeface();
@@ -416,24 +435,30 @@ GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
     } else {
         static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain();
 
-        int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt();
+        int styleDataCount = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectAndStrokeRec);
+        // Key should be valid since we opted out of drawing arbitrary path effects.
+        SkASSERT(styleDataCount >= 0);
         if (fUsingRawGlyphPaths) {
             const SkTypeface* typeface = fFont.getTypeface();
-            GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + strokeDataCount);
+            GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + styleDataCount);
             reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0;
-            reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount;
-            fStroke.asUniqueKeyFragment(&builder[2]);
+            reinterpret_cast<uint32_t&>(builder[1]) = styleDataCount;
+            if (styleDataCount) {
+                write_style_key(&builder[2], fStyle);
+            }
         } else {
             SkGlyphCache* glyphCache = this->getGlyphCache();
             const SkTypeface* typeface = glyphCache->getScalerContext()->getTypeface();
             const SkDescriptor* desc = &glyphCache->getDescriptor();
             int descDataCount = (desc->getLength() + 3) / 4;
             GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain,
-                                         2 + strokeDataCount + descDataCount);
+                                         2 + styleDataCount + descDataCount);
             reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0;
-            reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount | (descDataCount << 16);
-            fStroke.asUniqueKeyFragment(&builder[2]);
-            memcpy(&builder[2 + strokeDataCount], desc, desc->getLength());
+            reinterpret_cast<uint32_t&>(builder[1]) = styleDataCount | (descDataCount << 16);
+            if (styleDataCount) {
+                write_style_key(&builder[2], fStyle);
+            }
+            memcpy(&builder[2 + styleDataCount], desc, desc->getLength());
         }
     }
 }
@@ -541,13 +566,13 @@ GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx)
         if (fUsingRawGlyphPaths) {
             SkScalerContextEffects noeffects;
             glyphs = ctx->resourceProvider()->createGlyphs(fFont.getTypeface(), noeffects,
-                                                           nullptr, fStroke);
+                                                           nullptr, fStyle);
         } else {
             SkGlyphCache* cache = this->getGlyphCache();
             glyphs = ctx->resourceProvider()->createGlyphs(cache->getScalerContext()->getTypeface(),
                                                            cache->getScalerContext()->getEffects(),
                                                            &cache->getDescriptor(),
-                                                           fStroke);
+                                                           fStyle);
         }
         ctx->resourceProvider()->assignUniqueKeyToResource(fGlyphPathsKey, glyphs);
     }
@@ -621,9 +646,9 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
 
     if (fFallbackTextBlob) {
         SkPaint fallbackSkPaint(originalSkPaint);
-        fStroke.applyToPaint(&fallbackSkPaint);
-        if (!fStroke.isFillStyle()) {
-            fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio);
+        fStyle.strokeRec().applyToPaint(&fallbackSkPaint);
+        if (!fStyle.isSimpleFill()) {
+            fallbackSkPaint.setStrokeWidth(fStyle.strokeRec().getWidth() * fTextRatio);
         }
 
         fallbackTextContext->drawTextBlob(ctx, dc, pipelineBuilder->clip(), fallbackSkPaint,
index b1faba1..2c13ca0 100644 (file)
@@ -9,7 +9,7 @@
 #define GrStencilAndCoverTextContext_DEFINED
 
 #include "GrDrawContext.h"
-#include "GrStrokeInfo.h"
+#include "GrStyle.h"
 #include "SkDrawFilter.h"
 #include "SkTextBlob.h"
 #include "SkTHash.h"
@@ -94,7 +94,7 @@ private:
         GrPathRange* createGlyphs(GrContext*) const;
         void appendGlyph(const SkGlyph&, const SkPoint&, FallbackBlobBuilder*);
 
-        GrStrokeInfo                     fStroke;
+        GrStyle                          fStyle;
         SkPaint                          fFont;
         SkScalar                         fTextRatio;
         float                            fTextInverseRatio;
index 2dc7702..dc8db0f 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "GrContext.h"
 #include "GrPath.h"
-#include "GrStrokeInfo.h"
+#include "GrStyle.h"
 #include "SkBitmap.h"
 #include "SkCanvas.h"
 #include "SkColor.h"
@@ -104,9 +104,8 @@ DEF_GPUTEST(GrPathKeys, reporter, /*factory*/) {
 
     bool isVolatile;
     GrUniqueKey key1, key2;
-    GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
-    GrPath::ComputeKey(path1, stroke, &key1, &isVolatile);
-    GrPath::ComputeKey(path2, stroke, &key2, &isVolatile);
+    GrPath::ComputeKey(path1, GrStyle::SimpleFill(), &key1, &isVolatile);
+    GrPath::ComputeKey(path2, GrStyle::SimpleFill(), &key2, &isVolatile);
     REPORTER_ASSERT(reporter, key1 != key2);
 }
 
index 32973ee..9d55077 100644 (file)
@@ -239,7 +239,7 @@ static void test_path(GrDrawTarget* dt, GrRenderTarget* rt, GrResourceProvider*
     pipelineBuilder.setXPFactory(
         GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
     pipelineBuilder.setRenderTarget(rt);
-    GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
+    GrStyle style(SkStrokeRec::kFill_InitStyle);
     GrPathRenderer::DrawPathArgs args;
     args.fTarget = dt;
     args.fPipelineBuilder = &pipelineBuilder;
@@ -247,7 +247,7 @@ static void test_path(GrDrawTarget* dt, GrRenderTarget* rt, GrResourceProvider*
     args.fColor = GrColor_WHITE;
     args.fViewMatrix = &SkMatrix::I();
     args.fPath = &path;
-    args.fStroke = &stroke;
+    args.fStyle = &style;
     args.fAntiAlias = false;
     tess.drawPath(args);
 }