From 6663acff010ce752e4bf778da81fa97448c9db31 Mon Sep 17 00:00:00 2001 From: bsalomon Date: Tue, 10 May 2016 09:14:17 -0700 Subject: [PATCH] Replace GrStrokeInfo with GrStyle. A side effect is that arbitrary path effects can no be pushed deeper into the Ganesh flow for paths. They may be applied by path renderers. GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1957363002 Committed: https://skia.googlesource.com/skia/+/33595bdf4b64a745f6340338d307e806e96c587f Review-Url: https://codereview.chromium.org/1957363002 --- gyp/gpu.gypi | 2 - include/gpu/GrContext.h | 1 - include/gpu/GrDrawContext.h | 31 ++- include/gpu/GrTestUtils.h | 35 +++- src/gpu/GrBlurUtils.cpp | 178 +++++++--------- src/gpu/GrBlurUtils.h | 5 +- src/gpu/GrClipMaskManager.cpp | 18 +- src/gpu/GrDrawContext.cpp | 137 +++++++------ src/gpu/GrPath.cpp | 86 +++++--- src/gpu/GrPath.h | 12 +- src/gpu/GrPathRenderer.h | 30 ++- src/gpu/GrPathRendererChain.cpp | 2 +- src/gpu/GrPathRendering.cpp | 6 +- src/gpu/GrPathRendering.h | 26 +-- src/gpu/GrResourceProvider.cpp | 12 +- src/gpu/GrResourceProvider.h | 8 +- src/gpu/GrSWMaskHelper.cpp | 22 +- src/gpu/GrSWMaskHelper.h | 7 +- src/gpu/GrSoftwarePathRenderer.cpp | 10 +- src/gpu/GrStrokeInfo.cpp | 93 --------- src/gpu/GrStrokeInfo.h | 191 ------------------ src/gpu/GrStyle.h | 11 + src/gpu/GrTestUtils.cpp | 65 ++++-- src/gpu/SkGpuDevice.cpp | 26 +-- src/gpu/SkGpuDevice_drawTexture.cpp | 6 +- src/gpu/batches/GrAAConvexPathRenderer.cpp | 3 +- .../batches/GrAADistanceFieldPathRenderer.cpp | 33 +-- src/gpu/batches/GrAAHairLinePathRenderer.cpp | 16 +- .../GrAALinearizingConvexPathRenderer.cpp | 26 ++- src/gpu/batches/GrDashLinePathRenderer.cpp | 6 +- src/gpu/batches/GrDefaultPathRenderer.cpp | 34 ++-- src/gpu/batches/GrDefaultPathRenderer.h | 2 +- src/gpu/batches/GrMSAAPathRenderer.cpp | 44 ++-- src/gpu/batches/GrMSAAPathRenderer.h | 1 - src/gpu/batches/GrPLSPathRenderer.cpp | 4 +- .../batches/GrStencilAndCoverPathRenderer.cpp | 20 +- .../batches/GrTessellatingPathRenderer.cpp | 99 ++++----- src/gpu/effects/GrDashingEffect.cpp | 37 ++-- src/gpu/effects/GrDashingEffect.h | 6 +- src/gpu/gl/GrGLPath.cpp | 42 ++-- src/gpu/gl/GrGLPath.h | 5 +- src/gpu/gl/GrGLPathRange.cpp | 53 +++-- src/gpu/gl/GrGLPathRange.h | 8 +- src/gpu/gl/GrGLPathRendering.cpp | 8 +- src/gpu/gl/GrGLPathRendering.h | 5 +- src/gpu/text/GrStencilAndCoverTextContext.cpp | 77 ++++--- src/gpu/text/GrStencilAndCoverTextContext.h | 4 +- tests/GpuDrawPathTest.cpp | 7 +- tests/TessellatingPathRendererTests.cpp | 4 +- 49 files changed, 664 insertions(+), 900 deletions(-) delete mode 100644 src/gpu/GrStrokeInfo.cpp delete mode 100644 src/gpu/GrStrokeInfo.h 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 Make(const SkScalar* intervals, int count, SkScalar phase) { + return sk_sp(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 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 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 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 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; + // We just fully apply the style here. + if (style.applies()) { + if (!style.applyToPath(tmpPath.init(), &fillOrHairline, *path, + GrStyle::MatrixToScaleFactor(viewMatrix))) { + return; + } + pathIsMutable = true; + path = tmpPath.get(); + } else if (style.isSimpleHairline()) { + fillOrHairline = 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; - } - 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); + 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(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 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& path, + GrPaint* paint, + const SkMatrix& viewMatrix, + const SkMaskFilter* mf, + const GrStyle& style, + bool 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& origPath, - GrPaint* paint, - const SkMatrix& viewMatrix, - const SkMaskFilter* mf, - const SkPathEffect* pathEffect, - const GrStrokeInfo& origStrokeInfo, - bool pathIsMutable) { - SkPath* pathPtr = const_cast(&origPath); - - SkTLazy 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); -} - -void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, - GrDrawContext* drawContext, - const GrClip& clip, - const SkPath& origSrcPath, 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(&origSrcPath); + + const SkPath* path = &origPath; SkTLazy tmpPath; - SkTLazy 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(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 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 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 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 batch(GrRectBatchFactory::CreateAAFillNestedRects( paint.getColor(), viewMatrix, rects)); if (batch) { @@ -837,7 +836,7 @@ void GrDrawContext::drawPath(const GrClip& clip, SkAutoTUnref 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 tmpPath; - const GrStrokeInfo* strokeInfoPtr = &strokeInfo; + SkTLazy 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); + SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix); - 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)) { + 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 key0(cnt0); + SkAutoTArray 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 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 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 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(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(~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 pe; + if (random->nextBool()) { + int cnt = random->nextRangeU(1, 50) * 2; + SkAutoTDeleteArray 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 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 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 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 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 stroke(origStroke); const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory(); SkAutoTUnref 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 path( static_cast(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 p(get_gr_path(fResourceProvider, *args.fPath, GrStrokeInfo::FillInfo())); + SkAutoTUnref 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 p(get_gr_path(fResourceProvider, path, *args.fStroke)); + SkAutoTUnref 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 cachedVertexBuffer(rp->findAndRefTByUniqueKey(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 cachedVertexBuffer(rp->findAndRefTByUniqueKey(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 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(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 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 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(builder[0]) = typeface ? typeface->uniqueID() : 0; - reinterpret_cast(builder[1]) = strokeDataCount; - fStroke.asUniqueKeyFragment(&builder[2]); + reinterpret_cast(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(builder[0]) = typeface ? typeface->uniqueID() : 0; - reinterpret_cast(builder[1]) = strokeDataCount | (descDataCount << 16); - fStroke.asUniqueKeyFragment(&builder[2]); - memcpy(&builder[2 + strokeDataCount], desc, desc->getLength()); + reinterpret_cast(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); }