aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--include/gpu/GrContext.h1
-rw-r--r--include/gpu/GrDrawContext.h31
-rw-r--r--include/gpu/GrTestUtils.h35
-rw-r--r--src/gpu/GrBlurUtils.cpp162
-rw-r--r--src/gpu/GrBlurUtils.h5
-rw-r--r--src/gpu/GrClipMaskManager.cpp18
-rw-r--r--src/gpu/GrDrawContext.cpp139
-rw-r--r--src/gpu/GrPath.cpp86
-rw-r--r--src/gpu/GrPath.h12
-rw-r--r--src/gpu/GrPathRenderer.h30
-rw-r--r--src/gpu/GrPathRendererChain.cpp2
-rw-r--r--src/gpu/GrPathRendering.cpp6
-rw-r--r--src/gpu/GrPathRendering.h26
-rw-r--r--src/gpu/GrResourceProvider.cpp12
-rw-r--r--src/gpu/GrResourceProvider.h8
-rw-r--r--src/gpu/GrSWMaskHelper.cpp22
-rw-r--r--src/gpu/GrSWMaskHelper.h7
-rw-r--r--src/gpu/GrSoftwarePathRenderer.cpp10
-rw-r--r--src/gpu/GrStrokeInfo.cpp93
-rw-r--r--src/gpu/GrStrokeInfo.h191
-rw-r--r--src/gpu/GrStyle.h11
-rw-r--r--src/gpu/GrTestUtils.cpp65
-rw-r--r--src/gpu/SkGpuDevice.cpp26
-rw-r--r--src/gpu/SkGpuDevice_drawTexture.cpp6
-rw-r--r--src/gpu/batches/GrAAConvexPathRenderer.cpp3
-rw-r--r--src/gpu/batches/GrAADistanceFieldPathRenderer.cpp33
-rw-r--r--src/gpu/batches/GrAAHairLinePathRenderer.cpp16
-rw-r--r--src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp26
-rw-r--r--src/gpu/batches/GrDashLinePathRenderer.cpp6
-rw-r--r--src/gpu/batches/GrDefaultPathRenderer.cpp34
-rw-r--r--src/gpu/batches/GrDefaultPathRenderer.h2
-rw-r--r--src/gpu/batches/GrMSAAPathRenderer.cpp44
-rw-r--r--src/gpu/batches/GrMSAAPathRenderer.h1
-rw-r--r--src/gpu/batches/GrPLSPathRenderer.cpp4
-rw-r--r--src/gpu/batches/GrStencilAndCoverPathRenderer.cpp20
-rw-r--r--src/gpu/batches/GrTessellatingPathRenderer.cpp99
-rw-r--r--src/gpu/effects/GrDashingEffect.cpp37
-rw-r--r--src/gpu/effects/GrDashingEffect.h6
-rw-r--r--src/gpu/gl/GrGLPath.cpp42
-rw-r--r--src/gpu/gl/GrGLPath.h5
-rw-r--r--src/gpu/gl/GrGLPathRange.cpp53
-rw-r--r--src/gpu/gl/GrGLPathRange.h8
-rw-r--r--src/gpu/gl/GrGLPathRendering.cpp8
-rw-r--r--src/gpu/gl/GrGLPathRendering.h5
-rw-r--r--src/gpu/text/GrStencilAndCoverTextContext.cpp77
-rw-r--r--src/gpu/text/GrStencilAndCoverTextContext.h4
-rw-r--r--tests/GpuDrawPathTest.cpp7
-rw-r--r--tests/TessellatingPathRendererTests.cpp4
49 files changed, 657 insertions, 893 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 6b4837a992..48f1c8526d 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -174,8 +174,6 @@
'<(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',
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 1c9a27e25f..44dfda65ee 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -43,7 +43,6 @@ class GrTextBlobCache;
class GrTextContext;
class GrTextureParams;
class GrVertexBuffer;
-class GrStrokeInfo;
class GrSwizzle;
class SkTraceMemoryDump;
diff --git a/include/gpu/GrDrawContext.h b/include/gpu/GrDrawContext.h
index 7bb9aafc78..458ee4f539 100644
--- a/include/gpu/GrDrawContext.h
+++ b/include/gpu/GrDrawContext.h
@@ -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.
diff --git a/include/gpu/GrTestUtils.h b/include/gpu/GrTestUtils.h
index 475e38a6a1..caaf5d9785 100644
--- a/include/gpu/GrTestUtils.h
+++ b/include/gpu/GrTestUtils.h
@@ -13,10 +13,12 @@
#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
diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp
index aee158113b..0a8351fd07 100644
--- a/src/gpu/GrBlurUtils.cpp
+++ b/src/gpu/GrBlurUtils.cpp
@@ -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);
}
}
diff --git a/src/gpu/GrBlurUtils.h b/src/gpu/GrBlurUtils.h
index a22239aa34..aef1bdba05 100644
--- a/src/gpu/GrBlurUtils.h
+++ b/src/gpu/GrBlurUtils.h
@@ -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);
};
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 654b315d52..56c0ee641b 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -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);
}
}
diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp
index 6c80f52bba..a7c7f6ae5f 100644
--- a/src/gpu/GrDrawContext.cpp
+++ b/src/gpu/GrDrawContext.cpp
@@ -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);
diff --git a/src/gpu/GrPath.cpp b/src/gpu/GrPath.cpp
index 04d93b10ae..91a245d854 100644
--- a/src/gpu/GrPath.cpp
+++ b/src/gpu/GrPath.cpp
@@ -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;
}
diff --git a/src/gpu/GrPath.h b/src/gpu/GrPath.h
index 4cb12f4325..ee3123f9b5 100644
--- a/src/gpu/GrPath.h
+++ b/src/gpu/GrPath.h
@@ -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:
diff --git a/src/gpu/GrPathRenderer.h b/src/gpu/GrPathRenderer.h
index 1072f69649..3bc02306e6 100644
--- a/src/gpu/GrPathRenderer.h
+++ b/src/gpu/GrPathRenderer.h
@@ -10,13 +10,12 @@
#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;
};
diff --git a/src/gpu/GrPathRendererChain.cpp b/src/gpu/GrPathRendererChain.cpp
index c9e21ad60c..899418659b 100644
--- a/src/gpu/GrPathRendererChain.cpp
+++ b/src/gpu/GrPathRendererChain.cpp
@@ -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;
}
}
diff --git a/src/gpu/GrPathRendering.cpp b/src/gpu/GrPathRendering.cpp
index a3bba4bc7f..d1345c9b06 100644
--- a/src/gpu/GrPathRendering.cpp
+++ b/src/gpu/GrPathRendering.cpp
@@ -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);
}
diff --git a/src/gpu/GrPathRendering.h b/src/gpu/GrPathRendering.h
index 8ee3d7b3e2..8eea3218ac 100644
--- a/src/gpu/GrPathRendering.h
+++ b/src/gpu/GrPathRendering.h
@@ -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 {
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index f57d7eb796..9fa202af6c 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -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,
diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h
index 9701bf1784..ea3a28adc9 100644
--- a/src/gpu/GrResourceProvider.h
+++ b/src/gpu/GrResourceProvider.h
@@ -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;
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index b69edab82c..937b34380b 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -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) {
diff --git a/src/gpu/GrSWMaskHelper.h b/src/gpu/GrSWMaskHelper.h
index d1e1265dba..ee38ab7976 100644
--- a/src/gpu/GrSWMaskHelper.h
+++ b/src/gpu/GrSWMaskHelper.h
@@ -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);
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index ca2ca64db8..dc0dbd2816 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -12,13 +12,7 @@
////////////////////////////////////////////////////////////////////////////////
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
index b37c660108..0000000000
--- a/src/gpu/GrStrokeInfo.cpp
+++ /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
index 9cf7d8302f..0000000000
--- a/src/gpu/GrStrokeInfo.h
+++ /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
diff --git a/src/gpu/GrStyle.h b/src/gpu/GrStyle.h
index 6166b56fb7..07efb40866 100644
--- a/src/gpu/GrStyle.h
+++ b/src/gpu/GrStyle.h
@@ -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
diff --git a/src/gpu/GrTestUtils.cpp b/src/gpu/GrTestUtils.cpp
index 86a84ceb0a..e962978fc3 100644
--- a/src/gpu/GrTestUtils.cpp
+++ b/src/gpu/GrTestUtils.cpp
@@ -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
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index ba5848b4b1..a0f81e7ed9 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -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"
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
index 9750c96f9d..156bb7e6bf 100644
--- a/src/gpu/SkGpuDevice_drawTexture.cpp
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -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);
}
diff --git a/src/gpu/batches/GrAAConvexPathRenderer.cpp b/src/gpu/batches/GrAAConvexPathRenderer.cpp
index 8c55de7e79..f557c9b9e9 100644
--- a/src/gpu/batches/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/batches/GrAAConvexPathRenderer.cpp
@@ -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());
}
diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
index f891b8d1f5..ba52bf9213 100644
--- a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
@@ -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;
diff --git a/src/gpu/batches/GrAAHairLinePathRenderer.cpp b/src/gpu/batches/GrAAHairLinePathRenderer.cpp
index effd8c3b0f..db4bbdfdb3 100644
--- a/src/gpu/batches/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/batches/GrAAHairLinePathRenderer.cpp
@@ -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
diff --git a/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
index 446f67f1c0..91d3338c32 100644
--- a/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
+++ b/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
@@ -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);
diff --git a/src/gpu/batches/GrDashLinePathRenderer.cpp b/src/gpu/batches/GrDashLinePathRenderer.cpp
index 9ee27c78dd..8cb8046af4 100644
--- a/src/gpu/batches/GrDashLinePathRenderer.cpp
+++ b/src/gpu/batches/GrDashLinePathRenderer.cpp
@@ -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;
}
diff --git a/src/gpu/batches/GrDefaultPathRenderer.cpp b/src/gpu/batches/GrDefaultPathRenderer.cpp
index 1de0bf771e..9994b26a1a 100644
--- a/src/gpu/batches/GrDefaultPathRenderer.cpp
+++ b/src/gpu/batches/GrDefaultPathRenderer.cpp
@@ -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
diff --git a/src/gpu/batches/GrDefaultPathRenderer.h b/src/gpu/batches/GrDefaultPathRenderer.h
index 8156462a51..8a74d3a011 100644
--- a/src/gpu/batches/GrDefaultPathRenderer.h
+++ b/src/gpu/batches/GrDefaultPathRenderer.h
@@ -35,7 +35,7 @@ private:
GrColor,
const SkMatrix& viewMatrix,
const SkPath&,
- const GrStrokeInfo&,
+ const GrStyle&,
bool stencilOnly);
bool fSeparateStencil;
diff --git a/src/gpu/batches/GrMSAAPathRenderer.cpp b/src/gpu/batches/GrMSAAPathRenderer.cpp
index a9ba06c5f4..6e0076c11f 100644
--- a/src/gpu/batches/GrMSAAPathRenderer.cpp
+++ b/src/gpu/batches/GrMSAAPathRenderer.cpp
@@ -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,36 @@ 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->strokeRec().isHairlineStyle() &&
+ !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 +739,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);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/batches/GrMSAAPathRenderer.h b/src/gpu/batches/GrMSAAPathRenderer.h
index a35536014e..434a962190 100644
--- a/src/gpu/batches/GrMSAAPathRenderer.h
+++ b/src/gpu/batches/GrMSAAPathRenderer.h
@@ -26,7 +26,6 @@ private:
GrColor,
const SkMatrix& viewMatrix,
const SkPath&,
- const GrStrokeInfo&,
bool stencilOnly);
typedef GrPathRenderer INHERITED;
diff --git a/src/gpu/batches/GrPLSPathRenderer.cpp b/src/gpu/batches/GrPLSPathRenderer.cpp
index 46993c7f33..c26b4c0243 100644
--- a/src/gpu/batches/GrPLSPathRenderer.cpp
+++ b/src/gpu/batches/GrPLSPathRenderer.cpp
@@ -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;
}
diff --git a/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp b/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
index 6933efebe3..9d8d07de84 100644
--- a/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
@@ -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(
diff --git a/src/gpu/batches/GrTessellatingPathRenderer.cpp b/src/gpu/batches/GrTessellatingPathRenderer.cpp
index 2c8520b28a..728ec74059 100644
--- a/src/gpu/batches/GrTessellatingPathRenderer.cpp
+++ b/src/gpu/batches/GrTessellatingPathRenderer.cpp
@@ -105,9 +105,11 @@ 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->strokeRec().isHairlineStyle() &&
+ !args.fStyle->hasNonDashPathEffect() && !args.fAntiAlias && !args.fPath->isConvex();
}
class TessellatingPathBatch : public GrVertexBatch {
@@ -116,10 +118,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 +144,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 +197,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 +245,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 +263,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 +295,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 +317,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
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index f1e8016eb9..8a38ebe573 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -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
diff --git a/src/gpu/effects/GrDashingEffect.h b/src/gpu/effects/GrDashingEffect.h
index d67a63eb4b..8899820114 100644
--- a/src/gpu/effects/GrDashingEffect.h
+++ b/src/gpu/effects/GrDashingEffect.h
@@ -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);
}
diff --git a/src/gpu/gl/GrGLPath.cpp b/src/gpu/gl/GrGLPath.cpp
index ed5a31d9d2..05460187ef 100644
--- a/src/gpu/gl/GrGLPath.cpp
+++ b/src/gpu/gl/GrGLPath.cpp
@@ -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);
}
}
diff --git a/src/gpu/gl/GrGLPath.h b/src/gpu/gl/GrGLPath.h
index 1ef1346133..ddcee533ee 100644
--- a/src/gpu/gl/GrGLPath.h
+++ b/src/gpu/gl/GrGLPath.h
@@ -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; }
diff --git a/src/gpu/gl/GrGLPathRange.cpp b/src/gpu/gl/GrGLPathRange.cpp
index 6ed7bcc425..da1e9fe709 100644
--- a/src/gpu/gl/GrGLPathRange.cpp
+++ b/src/gpu/gl/GrGLPathRange.cpp
@@ -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);
}
diff --git a/src/gpu/gl/GrGLPathRange.h b/src/gpu/gl/GrGLPathRange.h
index ed9766d958..7d920105a0 100644
--- a/src/gpu/gl/GrGLPathRange.h
+++ b/src/gpu/gl/GrGLPathRange.h
@@ -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;
diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
index 0ecf58a8e1..5616f9d58a 100644
--- a/src/gpu/gl/GrGLPathRendering.cpp
+++ b/src/gpu/gl/GrGLPathRendering.cpp
@@ -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) {
diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h
index b39c866c6f..8fb699deb3 100644
--- a/src/gpu/gl/GrGLPathRendering.h
+++ b/src/gpu/gl/GrGLPathRendering.h
@@ -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();
diff --git a/src/gpu/text/GrStencilAndCoverTextContext.cpp b/src/gpu/text/GrStencilAndCoverTextContext.cpp
index c2c1c569e8..cc018845f6 100644
--- a/src/gpu/text/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp
@@ -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,
diff --git a/src/gpu/text/GrStencilAndCoverTextContext.h b/src/gpu/text/GrStencilAndCoverTextContext.h
index b1faba11b0..2c13ca035c 100644
--- a/src/gpu/text/GrStencilAndCoverTextContext.h
+++ b/src/gpu/text/GrStencilAndCoverTextContext.h
@@ -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;
diff --git a/tests/GpuDrawPathTest.cpp b/tests/GpuDrawPathTest.cpp
index 2dc7702fff..dc8db0ff70 100644
--- a/tests/GpuDrawPathTest.cpp
+++ b/tests/GpuDrawPathTest.cpp
@@ -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);
}
diff --git a/tests/TessellatingPathRendererTests.cpp b/tests/TessellatingPathRendererTests.cpp
index 32973ee1c8..9d550775ba 100644
--- a/tests/TessellatingPathRendererTests.cpp
+++ b/tests/TessellatingPathRendererTests.cpp
@@ -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);
}