From 85d9667f59d4138438427bb2cdf67992d100e1a0 Mon Sep 17 00:00:00 2001 From: bsalomon Date: Tue, 10 May 2016 06:19:21 -0700 Subject: [PATCH] Revert of Replace GrStrokeInfo with GrStyle. (patchset #4 id:160001 of https://codereview.chromium.org/1957363002/ ) Reason for revert: Breaking some bots Original issue's description: > 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 TBR=egdaniel@google.com,robertphillips@google.com # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true Review-Url: https://codereview.chromium.org/1967513002 --- 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 | 43 ++-- src/gpu/batches/GrMSAAPathRenderer.h | 1 + src/gpu/batches/GrPLSPathRenderer.cpp | 4 +- .../batches/GrStencilAndCoverPathRenderer.cpp | 20 +- .../batches/GrTessellatingPathRenderer.cpp | 98 +++++---- 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, 900 insertions(+), 662 deletions(-) create mode 100644 src/gpu/GrStrokeInfo.cpp create mode 100644 src/gpu/GrStrokeInfo.h diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index 48f1c8526d..6b4837a992 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -174,6 +174,8 @@ '<(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 44dfda65ee..1c9a27e25f 100644 --- a/include/gpu/GrContext.h +++ b/include/gpu/GrContext.h @@ -43,6 +43,7 @@ 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 458ee4f539..7bb9aafc78 100644 --- a/include/gpu/GrDrawContext.h +++ b/include/gpu/GrDrawContext.h @@ -28,7 +28,7 @@ class GrPaint; class GrPathProcessor; class GrPipelineBuilder; class GrRenderTarget; -class GrStyle; +class GrStrokeInfo; 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 GrStyle (GrTextInfo?) + // akin to GrStrokeInfo (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,15 +90,19 @@ public: * Draw the rect using a paint. * @param paint describes how to color pixels. * @param viewMatrix transformation matrix - * @param style The style to apply. Null means fill. Currently path effects are not - * allowed. + * @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. * 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 GrStyle* style = nullptr); + const GrStrokeInfo* strokeInfo = nullptr); /** * Maps a rectangle of shader coordinates to a rectangle and fills that rectangle. @@ -129,13 +133,14 @@ public: * @param paint describes how to color pixels. * @param viewMatrix transformation matrix * @param rrect the roundrect to draw - * @param style style to apply to the rrect. Currently path effects are not allowed. + * @param strokeInfo the stroke information (width, join, cap) and + * the dash information (intervals, count, phase). */ void drawRRect(const GrClip&, const GrPaint&, const SkMatrix& viewMatrix, const SkRRect& rrect, - const GrStyle& style); + const GrStrokeInfo&); /** * Shortcut for drawing an SkPath consisting of nested rrects using a paint. @@ -159,13 +164,14 @@ public: * @param paint describes how to color pixels. * @param viewMatrix transformation matrix * @param path the path to draw - * @param style style to apply to the path. + * @param strokeInfo the stroke information (width, join, cap) and + * the dash information (intervals, count, phase). */ void drawPath(const GrClip&, const GrPaint&, const SkMatrix& viewMatrix, const SkPath&, - const GrStyle& style); + const GrStrokeInfo&); /** * Draws vertices with a paint. @@ -220,13 +226,14 @@ public: * @param paint describes how to color pixels. * @param viewMatrix transformation matrix * @param oval the bounding rect of the oval. - * @param style style to apply to the oval. Currently path effects are not allowed. + * @param strokeInfo the stroke information (width, join, cap) and + * the dash information (intervals, count, phase). */ void drawOval(const GrClip&, const GrPaint& paint, const SkMatrix& viewMatrix, const SkRect& oval, - const GrStyle& style); + const GrStrokeInfo& strokeInfo); /** * Draw the image stretched differentially to fit into dst. @@ -311,7 +318,7 @@ private: const GrPaint& paint, const SkMatrix& viewMatrix, const SkPath& path, - const GrStyle& style); + const GrStrokeInfo& strokeInfo); // 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 caaf5d9785..475e38a6a1 100644 --- a/include/gpu/GrTestUtils.h +++ b/include/gpu/GrTestUtils.h @@ -13,12 +13,10 @@ #ifdef GR_TEST_UTILS #include "GrColor.h" -#include "SkPathEffect.h" #include "SkRandom.h" #include "SkStrokeRec.h" -#include "../private/SkTemplates.h" -class GrStyle; +class GrStrokeInfo; class SkMatrix; class SkPath; class SkRRect; @@ -26,7 +24,7 @@ struct SkRect; namespace GrTest { /** - * Helpers for use in Test functions. + * A helper for use in Test functions. */ const SkMatrix& TestMatrix(SkRandom*); const SkMatrix& TestMatrixPreservesRightAngles(SkRandom*); @@ -38,34 +36,9 @@ const SkRRect& TestRRectSimple(SkRandom*); const SkPath& TestPath(SkRandom*); const SkPath& TestPathConvex(SkRandom*); SkStrokeRec TestStrokeRec(SkRandom*); -/** Creates styles with dash path effects and null path effects */ -void TestStyle(SkRandom*, GrStyle*); +GrStrokeInfo TestStrokeInfo(SkRandom*); -// 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 0a8351fd07..aee158113b 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 "GrStyle.h" +#include "GrStrokeInfo.h" #include "GrTexture.h" #include "GrTextureProvider.h" #include "SkDraw.h" @@ -54,10 +54,11 @@ static bool sw_draw_with_mask_filter(GrDrawContext* drawContext, const SkMaskFilter* filter, const SkIRect& clipBounds, GrPaint* grp, - SkStrokeRec::InitStyle fillOrHairline) { + SkStrokeRec::InitStyle style) { SkMask srcM, dstM; + if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM, - SkMask::kComputeBoundsAndRenderImage_CreateMode, fillOrHairline)) { + SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) { return false; } SkAutoMaskFreeImage autoSrc(srcM.fImage); @@ -95,7 +96,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 fillOrHairline, + SkStrokeRec::InitStyle style, bool doAA, int sampleCnt) { // This mask will ultimately be drawn as a non-AA rect (see draw_mask). @@ -138,7 +139,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, GrStyle(fillOrHairline)); + drawContext->drawPath(clip, tempPaint, translate, devPath, GrStrokeInfo(style)); return drawContext->asTexture();; } @@ -148,50 +149,52 @@ static void draw_path_with_mask_filter(GrContext* context, GrPaint* paint, const SkMatrix& viewMatrix, const SkMaskFilter* maskFilter, - const GrStyle& style, - const SkPath* path, + const SkPathEffect* pathEffect, + const GrStrokeInfo& strokeInfo, + SkPath* pathPtr, bool pathIsMutable) { SkASSERT(maskFilter); SkIRect clipBounds; clip.getConservativeBounds(drawContext->width(), drawContext->height(), &clipBounds); SkTLazy tmpPath; - SkStrokeRec::InitStyle fillOrHairline; - // 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; + static const SkRect* cullRect = nullptr; // TODO: what is our bounds? + + SkASSERT(strokeInfo.isDashed() || !pathEffect); + SkStrokeRec::InitStyle maskStyle; + if (strokeInfo.isHairlineStyle()) { + maskStyle = SkStrokeRec::kHairline_InitStyle; } else { - SkASSERT(style.isSimpleFill()); - fillOrHairline = SkStrokeRec::kFill_InitStyle; + 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); } // transform the path into device space - 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; - } + pathPtr->transform(viewMatrix, devPathPtr); SkRect maskRect; - if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(path->getBounds()), + if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(devPathPtr->getBounds()), clipBounds, viewMatrix, &maskRect)) { @@ -207,8 +210,8 @@ static void draw_path_with_mask_filter(GrContext* context, paint, clip, viewMatrix, - SkStrokeRec(fillOrHairline), - *path)) { + SkStrokeRec(maskStyle), + *devPathPtr)) { // the mask filter was able to draw itself directly, so there's nothing // left to do. return; @@ -216,8 +219,8 @@ static void draw_path_with_mask_filter(GrContext* context, sk_sp mask(create_mask_GPU(context, &maskRect, - *path, - fillOrHairline, + *devPathPtr, + maskStyle, paint->isAntiAlias(), drawContext->numColorSamples())); if (mask) { @@ -235,59 +238,96 @@ static void draw_path_with_mask_filter(GrContext* context, } sw_draw_with_mask_filter(drawContext, context->textureProvider(), - 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); + clip, viewMatrix, *devPathPtr, + maskFilter, clipBounds, paint, maskStyle); } 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 || origPath.isVolatile()); + 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)); - 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). - - const SkPath* path = &origPath; + SkPath* pathPtr = const_cast(&origSrcPath); SkTLazy tmpPath; + SkTLazy effectPath; + SkPathEffect* pathEffect = paint.getPathEffect(); SkMatrix viewMatrix = origViewMatrix; if (prePathMatrix) { - // Styling, blurs, and shading are supposed to be applied *after* the prePathMatrix. - if (!paint.getMaskFilter() && !paint.getShader() && !style.applies()) { + // 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())) { viewMatrix.preConcat(*prePathMatrix); } else { - SkPath* result = pathIsMutable ? const_cast(path) : tmpPath.init(); - pathIsMutable = true; - path->transform(*prePathMatrix, result); - path = result; - result->setIsVolatile(true); + 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; } } // 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)) { @@ -296,9 +336,9 @@ void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, if (paint.getMaskFilter()) { draw_path_with_mask_filter(context, drawContext, clip, &grPaint, viewMatrix, - paint.getMaskFilter(), style, - path, pathIsMutable); + paint.getMaskFilter(), pathEffect, strokeInfo, + pathPtr, pathIsMutable); } else { - drawContext->drawPath(clip, grPaint, viewMatrix, *path, style); + drawContext->drawPath(clip, grPaint, viewMatrix, *pathPtr, strokeInfo); } } diff --git a/src/gpu/GrBlurUtils.h b/src/gpu/GrBlurUtils.h index aef1bdba05..a22239aa34 100644 --- a/src/gpu/GrBlurUtils.h +++ b/src/gpu/GrBlurUtils.h @@ -13,7 +13,7 @@ class GrContext; class GrDrawContext; class GrPaint; class GrRenderTarget; -class GrStyle; +class GrStrokeInfo; struct SkIRect; class SkMaskFilter; class SkMatrix; @@ -50,7 +50,8 @@ namespace GrBlurUtils { GrPaint*, const SkMatrix& viewMatrix, const SkMaskFilter*, - const GrStyle&, + const SkPathEffect*, + const GrStrokeInfo&, bool pathIsMutable); }; diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index 56c0ee641b..654b315d52 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -85,6 +85,7 @@ bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context, if (path.isInverseFillType()) { path.toggleInverseFillType(); } + GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); GrPathRendererChain::DrawType type; @@ -102,7 +103,7 @@ bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context, canDrawArgs.fShaderCaps = context->caps()->shaderCaps(); canDrawArgs.fViewMatrix = &viewMatrix; canDrawArgs.fPath = &path; - canDrawArgs.fStyle = &GrStyle::SimpleFill(); + canDrawArgs.fStroke = &stroke; canDrawArgs.fAntiAlias = element->isAA(); canDrawArgs.fIsStencilDisabled = isStencilDisabled; canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled(); @@ -590,7 +591,7 @@ static void draw_element(GrDrawContext* dc, path.toggleInverseFillType(); } - dc->drawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill()); + dc->drawPath(clip, paint, viewMatrix, path, GrStrokeInfo::FillInfo()); break; } } @@ -784,6 +785,7 @@ 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; @@ -804,7 +806,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps(); canDrawArgs.fViewMatrix = &viewMatrix; canDrawArgs.fPath = &clipPath; - canDrawArgs.fStyle = &GrStyle::SimpleFill(); + canDrawArgs.fStroke = &stroke; canDrawArgs.fAntiAlias = false; canDrawArgs.fIsStencilDisabled = pipelineBuilder.getStencil().isDisabled(); canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled(); @@ -859,7 +861,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, args.fColor = GrColor_WHITE; args.fViewMatrix = &viewMatrix; args.fPath = &clipPath; - args.fStyle = &GrStyle::SimpleFill(); + args.fStroke = &stroke; args.fAntiAlias = false; args.fGammaCorrect = false; pr->drawPath(args); @@ -894,7 +896,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, args.fColor = GrColor_WHITE; args.fViewMatrix = &viewMatrix; args.fPath = &clipPath; - args.fStyle = &GrStyle::SimpleFill(); + args.fStroke = &stroke; args.fAntiAlias = false; args.fGammaCorrect = false; pr->drawPath(args); @@ -1098,6 +1100,7 @@ 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(); @@ -1116,8 +1119,7 @@ GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context, SkPath clipPath; element->asPath(&clipPath); clipPath.toggleInverseFillType(); - helper.draw(clipPath, GrStyle::SimpleFill(), SkRegion::kReplace_Op, element->isAA(), - 0x00); + helper.draw(clipPath, stroke, SkRegion::kReplace_Op, element->isAA(), 0x00); continue; } @@ -1128,7 +1130,7 @@ GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context, } else { SkPath path; element->asPath(&path); - helper.draw(path, GrStyle::SimpleFill(), op, element->isAA(), 0xFF); + helper.draw(path, stroke, op, element->isAA(), 0xFF); } } diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp index a7c7f6ae5f..6c80f52bba 100644 --- a/src/gpu/GrDrawContext.cpp +++ b/src/gpu/GrDrawContext.cpp @@ -279,22 +279,18 @@ void GrDrawContext::drawRect(const GrClip& clip, const GrPaint& paint, const SkMatrix& viewMatrix, const SkRect& rect, - const GrStyle* style) { - if (!style) { - style = &GrStyle::SimpleFill(); - } + const GrStrokeInfo* strokeInfo) { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRect"); - // Path effects should've been devolved to a path in SkGpuDevice - SkASSERT(!style->pathEffect()); + // Dashing should've been devolved to a path in SkGpuDevice + SkASSERT(!strokeInfo || !strokeInfo->isDashed()); AutoCheckFlush acf(fDrawingManager); - const SkStrokeRec& stroke = style->strokeRec(); - SkScalar width = stroke.getWidth(); + SkScalar width = !strokeInfo ? -1 : strokeInfo->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. @@ -341,7 +337,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, - stroke)); + *strokeInfo)); } } else { // Non-AA hairlines are snapped to pixel centers to make which pixels are hit @@ -371,7 +367,8 @@ void GrDrawContext::drawRect(const GrClip& clip, SkPath path; path.setIsVolatile(true); path.addRect(rect); - this->internalDrawPath(clip, paint, viewMatrix, path, *style); + this->internalDrawPath(clip, paint, viewMatrix, path, + strokeInfo ? *strokeInfo : GrStrokeInfo::FillInfo()); } bool GrDrawContextPriv::drawAndStencilRect(const SkIRect* scissorRect, @@ -539,7 +536,7 @@ void GrDrawContext::drawRRect(const GrClip& clip, const GrPaint& paint, const SkMatrix& viewMatrix, const SkRRect& rrect, - const GrStyle& style) { + const GrStrokeInfo& strokeInfo) { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) @@ -549,8 +546,8 @@ void GrDrawContext::drawRRect(const GrClip& clip, return; } - SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice - const SkStrokeRec stroke = style.strokeRec(); + SkASSERT(!strokeInfo.isDashed()); // this should've been devolved to a path in SkGpuDevice + AutoCheckFlush acf(fDrawingManager); if (should_apply_coverage_aa(paint, fRenderTarget.get())) { @@ -559,7 +556,7 @@ void GrDrawContext::drawRRect(const GrClip& clip, SkAutoTUnref batch(GrOvalRenderer::CreateRRectBatch(paint.getColor(), viewMatrix, rrect, - stroke, + strokeInfo, shaderCaps)); if (batch) { GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip); @@ -571,7 +568,7 @@ void GrDrawContext::drawRRect(const GrClip& clip, SkPath path; path.setIsVolatile(true); path.addRRect(rrect); - this->internalDrawPath(clip, paint, viewMatrix, path, style); + this->internalDrawPath(clip, paint, viewMatrix, path, strokeInfo); } bool GrDrawContext::drawFilledDRRect(const GrClip& clip, @@ -657,7 +654,7 @@ void GrDrawContext::drawDRRect(const GrClip& clip, path.setFillType(SkPath::kEvenOdd_FillType); GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip); - this->internalDrawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill()); + this->internalDrawPath(clip, paint, viewMatrix, path, GrStrokeInfo::FillInfo()); } /////////////////////////////////////////////////////////////////////////////// @@ -666,7 +663,7 @@ void GrDrawContext::drawOval(const GrClip& clip, const GrPaint& paint, const SkMatrix& viewMatrix, const SkRect& oval, - const GrStyle& style) { + const GrStrokeInfo& strokeInfo) { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) @@ -676,16 +673,16 @@ void GrDrawContext::drawOval(const GrClip& clip, return; } - SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice + SkASSERT(!strokeInfo.isDashed()); // 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, - stroke, + strokeInfo, shaderCaps)); if (batch) { GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip); @@ -697,7 +694,7 @@ void GrDrawContext::drawOval(const GrClip& clip, SkPath path; path.setIsVolatile(true); path.addOval(oval); - this->internalDrawPath(clip, paint, viewMatrix, path, style); + this->internalDrawPath(clip, paint, viewMatrix, path, strokeInfo); } void GrDrawContext::drawImageNine(const GrClip& clip, @@ -724,7 +721,11 @@ void GrDrawContext::drawImageNine(const GrClip& clip, // Can 'path' be drawn as a pair of filled nested rectangles? -static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) { +static bool is_nested_rects(const SkMatrix& viewMatrix, + const SkPath& path, + const SkStrokeRec& stroke, + SkRect rects[2]) { + SkASSERT(stroke.isFillStyle()); if (path.isInverseFillType()) { return false; @@ -798,7 +799,7 @@ void GrDrawContext::drawPath(const GrClip& clip, const GrPaint& paint, const SkMatrix& viewMatrix, const SkPath& path, - const GrStyle& style) { + const GrStrokeInfo& strokeInfo) { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) @@ -813,12 +814,12 @@ void GrDrawContext::drawPath(const GrClip& clip, AutoCheckFlush acf(fDrawingManager); - if (should_apply_coverage_aa(paint, fRenderTarget.get()) && !style.pathEffect()) { - if (style.isSimpleFill() && !path.isConvex()) { + if (should_apply_coverage_aa(paint, fRenderTarget.get()) && !strokeInfo.isDashed()) { + if (strokeInfo.getWidth() < 0 && !path.isConvex()) { // Concave AA paths are expensive - try to avoid them for special cases SkRect rects[2]; - if (fills_as_nested_rects(viewMatrix, path, rects)) { + if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) { SkAutoTUnref batch(GrRectBatchFactory::CreateAAFillNestedRects( paint.getColor(), viewMatrix, rects)); if (batch) { @@ -836,7 +837,7 @@ void GrDrawContext::drawPath(const GrClip& clip, SkAutoTUnref batch(GrOvalRenderer::CreateOvalBatch(paint.getColor(), viewMatrix, ovalRect, - style.strokeRec(), + strokeInfo, shaderCaps)); if (batch) { GrPipelineBuilder pipelineBuilder(paint, fRenderTarget.get(), clip); @@ -851,7 +852,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, style); + this->internalDrawPath(clip, paint, viewMatrix, path, strokeInfo); } bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect, @@ -891,7 +892,7 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect, canDrawArgs.fShaderCaps = fDrawContext->fDrawingManager->getContext()->caps()->shaderCaps(); canDrawArgs.fViewMatrix = &viewMatrix; canDrawArgs.fPath = &path; - canDrawArgs.fStyle = &GrStyle::SimpleFill(); + canDrawArgs.fStroke = &GrStrokeInfo::FillInfo(); canDrawArgs.fAntiAlias = useCoverageAA; canDrawArgs.fIsStencilDisabled = isStencilDisabled; canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA; @@ -922,7 +923,7 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect, args.fColor = GrColor_WHITE; args.fViewMatrix = &viewMatrix; args.fPath = &path; - args.fStyle = &GrStyle::SimpleFill(); + args.fStroke = &GrStrokeInfo::FillInfo(); args.fAntiAlias = useCoverageAA; args.fGammaCorrect = fDrawContext->isGammaCorrect(); pr->drawPath(args); @@ -932,12 +933,16 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect, void GrDrawContext::internalDrawPath(const GrClip& clip, const GrPaint& paint, const SkMatrix& viewMatrix, - const SkPath& origPath, - const GrStyle& origStyle) { + const SkPath& path, + const GrStrokeInfo& strokeInfo) { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED - SkASSERT(!origPath.isEmpty()); + SkASSERT(!path.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(); @@ -946,66 +951,62 @@ void GrDrawContext::internalDrawPath(const GrClip& clip, useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType : GrPathRendererChain::kColor_DrawType; + const SkPath* pathPtr = &path; SkTLazy tmpPath; - SkTLazy tmpStyle; + const GrStrokeInfo* strokeInfoPtr = &strokeInfo; GrPathRenderer::CanDrawPathArgs canDrawArgs; canDrawArgs.fShaderCaps = fDrawingManager->getContext()->caps()->shaderCaps(); canDrawArgs.fViewMatrix = &viewMatrix; - canDrawArgs.fPath = &origPath; - canDrawArgs.fStyle = &origStyle; + canDrawArgs.fPath = pathPtr; + canDrawArgs.fStroke = strokeInfoPtr; canDrawArgs.fAntiAlias = useCoverageAA; canDrawArgs.fIsStencilDisabled = isStencilDisabled; canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA; - // Try a 1st time without applying any of the style to the geometry (and barring sw) + // Try a 1st time without stroking the path and without allowing the SW renderer GrPathRenderer* pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type); - SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix); - if (!pr && canDrawArgs.fStyle->pathEffect()) { - // It didn't work above, so try again with the path effect applied. - SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); - if (!canDrawArgs.fStyle->applyPathEffectToPath(tmpPath.init(), &rec, *canDrawArgs.fPath, - styleScale)) { - GrStyle noPathEffect(canDrawArgs.fStyle->strokeRec(), nullptr); - this->internalDrawPath(clip, paint, viewMatrix, *canDrawArgs.fPath, noPathEffect); + 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)) { return; } - tmpStyle.init(rec, nullptr); - canDrawArgs.fPath = tmpPath.get(); - canDrawArgs.fStyle = tmpStyle.get(); - if (canDrawArgs.fPath->isEmpty()) { + pathPtr = tmpPath.get(); + if (pathPtr->isEmpty()) { return; } + strokeInfoPtr = &dashlessStrokeInfo; + + canDrawArgs.fPath = pathPtr; + canDrawArgs.fStroke = strokeInfoPtr; pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type); } - if (!pr) { - SkASSERT(!canDrawArgs.fStyle->pathEffect()); - if (canDrawArgs.fStyle->strokeRec().needToApply()) { + + 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 (!tmpPath.isValid()) { tmpPath.init(); } - // 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)) { + dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale())); + if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) { return; } - if (!tmpStyle.isValid()) { - tmpStyle.init(fillOrHairline); - } else { - tmpStyle.get()->resetToInitStyle(fillOrHairline); - } - canDrawArgs.fPath = tmpPath.get(); - canDrawArgs.fStyle = tmpStyle.get(); - if (canDrawArgs.fPath->isEmpty()) { + pathPtr = tmpPath.get(); + if (pathPtr->isEmpty()) { return; } - - pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type); + dashlessStrokeInfo.setFillStyle(); + strokeInfoPtr = &dashlessStrokeInfo; } + canDrawArgs.fPath = pathPtr; + canDrawArgs.fStroke = strokeInfoPtr; + // This time, allow SW renderer pr = fDrawingManager->getPathRenderer(canDrawArgs, true, type); } @@ -1025,8 +1026,8 @@ void GrDrawContext::internalDrawPath(const GrClip& clip, args.fPipelineBuilder = &pipelineBuilder; args.fColor = paint.getColor(); args.fViewMatrix = &viewMatrix; - args.fPath = canDrawArgs.fPath; - args.fStyle = canDrawArgs.fStyle; + args.fPath = pathPtr; + args.fStroke = strokeInfoPtr; args.fAntiAlias = useCoverageAA; args.fGammaCorrect = this->isGammaCorrect(); pr->drawPath(args); diff --git a/src/gpu/GrPath.cpp b/src/gpu/GrPath.cpp index 91a245d854..04d93b10ae 100644 --- a/src/gpu/GrPath.cpp +++ b/src/gpu/GrPath.cpp @@ -6,28 +6,13 @@ */ #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; -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, +inline static bool compute_key_for_line_path(const SkPath& path, const GrStrokeInfo& stroke, GrUniqueKey* key) { SkPoint pts[2]; if (!path.isLine(pts)) { @@ -35,37 +20,37 @@ inline static bool compute_key_for_line_path(const SkPath& path, const GrStyle& } 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 + styleDataCnt); + GrUniqueKey::Builder builder(key, kOvalPathDomain, kBaseData32Cnt + strokeDataCnt); builder[0] = path.getFillType(); memcpy(&builder[1], &pts, sizeof(pts)); - if (styleDataCnt > 0) { - write_style_key(&builder[kBaseData32Cnt], style); + if (strokeDataCnt > 0) { + stroke.asUniqueKeyFragment(&builder[kBaseData32Cnt]); } return true; } -inline static bool compute_key_for_oval_path(const SkPath& path, const GrStyle& style, +inline static bool compute_key_for_oval_path(const SkPath& path, const GrStrokeInfo& stroke, GrUniqueKey* key) { SkRect rect; // Point order is significant when dashing, so we cannot devolve to a rect key. - if (style.pathEffect() || !path.isOval(&rect)) { + if (stroke.isDashed() || !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 styleDataCnt = style_data_cnt(style); + int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt(); static const GrUniqueKey::Domain kOvalPathDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey::Builder builder(key, kOvalPathDomain, kBaseData32Cnt + styleDataCnt); + GrUniqueKey::Builder builder(key, kOvalPathDomain, kBaseData32Cnt + strokeDataCnt); builder[0] = path.getFillType(); memcpy(&builder[1], &rect, sizeof(rect)); - if (styleDataCnt > 0) { - write_style_key(&builder[kBaseData32Cnt], style); + if (strokeDataCnt > 0) { + stroke.asUniqueKeyFragment(&builder[kBaseData32Cnt]); } return true; } @@ -73,7 +58,7 @@ inline static bool compute_key_for_oval_path(const SkPath& path, const GrStyle& // 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 GrStyle& style, +inline static bool compute_key_for_simple_path(const SkPath& path, const GrStrokeInfo& stroke, GrUniqueKey* key) { if (!path.isVolatile()) { return false; @@ -124,9 +109,9 @@ inline static bool compute_key_for_simple_path(const SkPath& path, const GrStyle // 2) stroke data (varying size) const int baseData32Cnt = 2 + verbData32Cnt + pointData32Cnt + conicWeightData32Cnt; - const int styleDataCnt = style_data_cnt(style); + const int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt(); static const GrUniqueKey::Domain kSimpleVolatilePathDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey::Builder builder(key, kSimpleVolatilePathDomain, baseData32Cnt + styleDataCnt); + GrUniqueKey::Builder builder(key, kSimpleVolatilePathDomain, baseData32Cnt + strokeDataCnt); int i = 0; builder[i++] = path.getFillType(); @@ -168,68 +153,57 @@ inline static bool compute_key_for_simple_path(const SkPath& path, const GrStyle SkDEBUGCODE(i += conicWeightData32Cnt); } SkASSERT(i == baseData32Cnt); - if (styleDataCnt > 0) { - write_style_key(&builder[baseData32Cnt], style); + if (strokeDataCnt > 0) { + stroke.asUniqueKeyFragment(&builder[baseData32Cnt]); } return true; } -inline static void compute_key_for_general_path(const SkPath& path, const GrStyle& style, +inline static void compute_key_for_general_path(const SkPath& path, const GrStrokeInfo& stroke, GrUniqueKey* key) { const int kBaseData32Cnt = 2; - int styleDataCnt = style_data_cnt(style); + int strokeDataCnt = stroke.computeUniqueKeyFragmentData32Cnt(); static const GrUniqueKey::Domain kGeneralPathDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey::Builder builder(key, kGeneralPathDomain, kBaseData32Cnt + styleDataCnt); + GrUniqueKey::Builder builder(key, kGeneralPathDomain, kBaseData32Cnt + strokeDataCnt); builder[0] = path.getGenerationID(); builder[1] = path.getFillType(); - if (styleDataCnt > 0) { - write_style_key(&builder[kBaseData32Cnt], style); + if (strokeDataCnt > 0) { + stroke.asUniqueKeyFragment(&builder[kBaseData32Cnt]); } } } -void GrPath::ComputeKey(const SkPath& path, const GrStyle& style, GrUniqueKey* key, +void GrPath::ComputeKey(const SkPath& path, const GrStrokeInfo& stroke, GrUniqueKey* key, bool* outIsVolatile) { - if (compute_key_for_line_path(path, style, key)) { + if (compute_key_for_line_path(path, stroke, key)) { *outIsVolatile = false; return; } - if (compute_key_for_oval_path(path, style, key)) { + if (compute_key_for_oval_path(path, stroke, key)) { *outIsVolatile = false; return; } - if (compute_key_for_simple_path(path, style, key)) { + if (compute_key_for_simple_path(path, stroke, key)) { *outIsVolatile = false; return; } - compute_key_for_general_path(path, style, key); + compute_key_for_general_path(path, stroke, key); *outIsVolatile = path.isVolatile(); } #ifdef SK_DEBUG -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) { +bool GrPath::isEqualTo(const SkPath& path, const GrStrokeInfo& stroke) const { + if (!fStroke.hasEqualEffect(stroke)) { 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 (!fStyle.isDashed() && fSkPath.isOval(&ovalBounds)) { + if (!fStroke.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 ee3123f9b5..4cb12f4325 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 GrStyle& style) + GrPath(GrGpu* gpu, const SkPath& skPath, const GrStrokeInfo& stroke) : INHERITED(gpu) , fBounds(SkRect::MakeEmpty()) , fFillType(GrPathRendering::kWinding_FillType) #ifdef SK_DEBUG , fSkPath(skPath) - , fStyle(style) + , fStroke(stroke) #endif { } - static void ComputeKey(const SkPath& path, const GrStyle& style, GrUniqueKey* key, + static void ComputeKey(const SkPath& path, const GrStrokeInfo& stroke, 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 GrStyle& style) const; + bool isEqualTo(const SkPath& path, const GrStrokeInfo& stroke) const; #endif protected: @@ -46,7 +46,7 @@ protected: GrPathRendering::FillType fFillType; #ifdef SK_DEBUG SkPath fSkPath; - GrStyle fStyle; + GrStrokeInfo fStroke; #endif private: diff --git a/src/gpu/GrPathRenderer.h b/src/gpu/GrPathRenderer.h index 3bc02306e6..1072f69649 100644 --- a/src/gpu/GrPathRenderer.h +++ b/src/gpu/GrPathRenderer.h @@ -10,12 +10,13 @@ #include "GrDrawTarget.h" #include "GrStencil.h" -#include "GrStyle.h" +#include "GrStrokeInfo.h" #include "SkDrawProcs.h" #include "SkTArray.h" class SkPath; + struct GrPoint; /** @@ -71,14 +72,14 @@ public: * fPipelineBuilder The pipelineBuilder * fViewMatrix The viewMatrix * fPath The path to draw - * fStyle The styling info (path effect, stroking info) + * fStroke The stroke information (width, join, cap) * fAntiAlias True if anti-aliasing is required. */ struct CanDrawPathArgs { const GrShaderCaps* fShaderCaps; const SkMatrix* fViewMatrix; const SkPath* fPath; - const GrStyle* fStyle; + const GrStrokeInfo* fStroke; bool fAntiAlias; // These next two are only used by GrStencilAndCoverPathRenderer @@ -89,7 +90,7 @@ public: SkASSERT(fShaderCaps); SkASSERT(fViewMatrix); SkASSERT(fPath); - SkASSERT(fStyle); + SkASSERT(fStroke); SkASSERT(!fPath->isEmpty()); } }; @@ -115,7 +116,7 @@ public: * fColor Color to render with * fViewMatrix The viewMatrix * fPath the path to draw. - * fStyle the style information (path effect, stroke info) + * fStroke the stroke information (width, join, cap) * fAntiAlias true if anti-aliasing is required. * fGammaCorrect true if gamma-correct rendering is to be used. */ @@ -126,7 +127,7 @@ public: GrColor fColor; const SkMatrix* fViewMatrix; const SkPath* fPath; - const GrStyle* fStyle; + const GrStrokeInfo* fStroke; bool fAntiAlias; bool fGammaCorrect; @@ -136,7 +137,7 @@ public: SkASSERT(fPipelineBuilder); SkASSERT(fViewMatrix); SkASSERT(fPath); - SkASSERT(fStyle); + SkASSERT(fStroke); SkASSERT(!fPath->isEmpty()); } }; @@ -152,7 +153,7 @@ public: canArgs.fShaderCaps = args.fTarget->caps()->shaderCaps(); canArgs.fViewMatrix = args.fViewMatrix; canArgs.fPath = args.fPath; - canArgs.fStyle = args.fStyle; + canArgs.fStroke = args.fStroke; canArgs.fAntiAlias = args.fAntiAlias; canArgs.fIsStencilDisabled = args.fPipelineBuilder->getStencil().isDisabled(); @@ -161,7 +162,8 @@ public: SkASSERT(this->canDrawPath(canArgs)); if (!args.fPipelineBuilder->getStencil().isDisabled()) { SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fPath)); - SkASSERT(args.fStyle->isSimpleFill()); + SkASSERT(!args.fStroke->isDashed()); + SkASSERT(args.fStroke->isFillStyle()); } #endif return this->onDrawPath(args); @@ -195,21 +197,22 @@ 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 GrStyle& style, const SkMatrix& matrix, + static bool IsStrokeHairlineOrEquivalent(const GrStrokeInfo& stroke, const SkMatrix& matrix, SkScalar* outCoverage) { - if (style.pathEffect()) { + if (stroke.isDashed()) { return false; } - const SkStrokeRec& stroke = style.strokeRec(); if (stroke.isHairlineStyle()) { if (outCoverage) { *outCoverage = SK_Scalar1; @@ -276,12 +279,13 @@ private: drawArgs.fColor = 0xFFFFFFFF; drawArgs.fViewMatrix = args.fViewMatrix; drawArgs.fPath = args.fPath; - drawArgs.fStyle = &GrStyle::SimpleFill(); + drawArgs.fStroke = &GrStrokeInfo::FillInfo(); 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 899418659b..c9e21ad60c 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.fStyle->isSimpleFill()) { + if (!args.fStroke->isFillStyle() || args.fStroke->isDashed()) { return nullptr; } } diff --git a/src/gpu/GrPathRendering.cpp b/src/gpu/GrPathRendering.cpp index d1345c9b06..a3bba4bc7f 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 GrStyle& style) { + const GrStrokeInfo& stroke) { 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, style); + return this->createPathRange(generator, stroke); } 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, style); + return this->createPathRange(generator, stroke); } diff --git a/src/gpu/GrPathRendering.h b/src/gpu/GrPathRendering.h index 8eea3218ac..8ee3d7b3e2 100644 --- a/src/gpu/GrPathRendering.h +++ b/src/gpu/GrPathRendering.h @@ -17,7 +17,7 @@ class SkDescriptor; class SkTypeface; class GrPath; class GrStencilSettings; -class GrStyle; +class GrStrokeInfo; /** * Abstract class wrapping HW path rendering API. @@ -81,23 +81,21 @@ 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 geometry. - * @param GrStyle the style applied to the path. Styles with non-dash path effects are not - * allowed. - * @return a new GPU path object. + * @param skPath the path geometry. + * @param stroke the path stroke. + * @return a new path. */ - virtual GrPath* createPath(const SkPath&, const GrStyle&) = 0; + virtual GrPath* createPath(const SkPath&, const GrStrokeInfo&) = 0; /** - * Creates a range of gpu paths with a common style. The caller owns a ref on the + * Creates a range of gpu paths with a common stroke. 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 GrStyle the common style applied to each path in the range. Styles with non-dash - * path effects are not allowed. + * @param GrStrokeInfo the common stroke applied to each path in the range. * @return a new path range. */ - virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStyle&) = 0; + virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStrokeInfo&) = 0; /** * Creates a range of glyph paths, indexed by glyph id. The glyphs will have an @@ -120,15 +118,15 @@ public: * including with the stroke information baked directly into * the outlines. * - * @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 + * @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 * outlines. * * @return a new path range populated with glyphs. */ GrPathRange* createGlyphs(const SkTypeface*, const SkScalerContextEffects&, - const SkDescriptor*, const GrStyle&); + const SkDescriptor*, const GrStrokeInfo&); /** 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 9fa202af6c..f57d7eb796 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 GrStyle& style) { +GrPath* GrResourceProvider::createPath(const SkPath& path, const GrStrokeInfo& stroke) { SkASSERT(this->gpu()->pathRendering()); - return this->gpu()->pathRendering()->createPath(path, style); + return this->gpu()->pathRendering()->createPath(path, stroke); } GrPathRange* GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen, - const GrStyle& style) { + const GrStrokeInfo& stroke) { SkASSERT(this->gpu()->pathRendering()); - return this->gpu()->pathRendering()->createPathRange(gen, style); + return this->gpu()->pathRendering()->createPathRange(gen, stroke); } GrPathRange* GrResourceProvider::createGlyphs(const SkTypeface* tf, const SkScalerContextEffects& effects, const SkDescriptor* desc, - const GrStyle& style) { + const GrStrokeInfo& stroke) { SkASSERT(this->gpu()->pathRendering()); - return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, style); + return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, stroke); } GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType, diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h index ea3a28adc9..9701bf1784 100644 --- a/src/gpu/GrResourceProvider.h +++ b/src/gpu/GrResourceProvider.h @@ -18,7 +18,7 @@ class GrPath; class GrRenderTarget; class GrSingleOwner; class GrStencilAttachment; -class GrStyle; +class GrStrokeInfo; 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 GrStyle&); - GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStyle&); + GrPath* createPath(const SkPath&, const GrStrokeInfo&); + GrPathRange* createPathRange(GrPathRange::PathGenerator*, const GrStrokeInfo&); GrPathRange* createGlyphs(const SkTypeface*, const SkScalerContextEffects&, - const SkDescriptor*, const GrStyle&); + const SkDescriptor*, const GrStrokeInfo&); using GrTextureProvider::assignUniqueKeyToResource; using GrTextureProvider::findAndRefResourceByUniqueKey; diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp index 937b34380b..b69edab82c 100644 --- a/src/gpu/GrSWMaskHelper.cpp +++ b/src/gpu/GrSWMaskHelper.cpp @@ -11,7 +11,6 @@ #include "GrDrawTarget.h" #include "GrGpu.h" #include "GrPipelineBuilder.h" -#include "GrStyle.h" #include "SkData.h" #include "SkDistanceFieldGen.h" @@ -118,11 +117,22 @@ 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 GrStyle& style, SkRegion::Op op, +void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op, bool antiAlias, uint8_t alpha) { + SkPaint paint; - paint.setPathEffect(sk_ref_sp(style.pathEffect())); - style.strokeRec().applyToPaint(&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.setAntiAlias(antiAlias); SkTBlitterAllocator allocator; @@ -297,7 +307,7 @@ void GrSWMaskHelper::toSDF(unsigned char* sdf) { */ GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context, const SkPath& path, - const GrStyle& style, + const SkStrokeRec& stroke, const SkIRect& resultBounds, bool antiAlias, const SkMatrix* matrix) { @@ -307,7 +317,7 @@ GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context, return nullptr; } - helper.draw(path, style, SkRegion::kReplace_Op, antiAlias, 0xFF); + helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF); GrTexture* texture(helper.createTexture()); if (!texture) { diff --git a/src/gpu/GrSWMaskHelper.h b/src/gpu/GrSWMaskHelper.h index ee38ab7976..d1e1265dba 100644 --- a/src/gpu/GrSWMaskHelper.h +++ b/src/gpu/GrSWMaskHelper.h @@ -55,10 +55,11 @@ 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 GrStyle& style, SkRegion::Op op, + void draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op, bool antiAlias, uint8_t alpha); // Move the mask generation results from the internal bitmap to the gpu. @@ -76,7 +77,7 @@ public: // to the GPU. The result is returned. static GrTexture* DrawPathMaskToTexture(GrContext* context, const SkPath& path, - const GrStyle& style, + const SkStrokeRec& stroke, const SkIRect& resultBounds, bool antiAlias, const SkMatrix* matrix); diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp index dc0dbd2816..ca2ca64db8 100644 --- a/src/gpu/GrSoftwarePathRenderer.cpp +++ b/src/gpu/GrSoftwarePathRenderer.cpp @@ -12,7 +12,13 @@ //////////////////////////////////////////////////////////////////////////////// bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - return SkToBool(fContext); + if (nullptr == fContext) { + return false; + } + if (args.fStroke->isDashed()) { + return false; + } + return true; } namespace { @@ -124,7 +130,7 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) { } SkAutoTUnref texture( - GrSWMaskHelper::DrawPathMaskToTexture(fContext, *args.fPath, *args.fStyle, + GrSWMaskHelper::DrawPathMaskToTexture(fContext, *args.fPath, *args.fStroke, devPathBounds, args.fAntiAlias, args.fViewMatrix)); if (nullptr == texture) { diff --git a/src/gpu/GrStrokeInfo.cpp b/src/gpu/GrStrokeInfo.cpp new file mode 100644 index 0000000000..b37c660108 --- /dev/null +++ b/src/gpu/GrStrokeInfo.cpp @@ -0,0 +1,93 @@ +/* + * 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 new file mode 100644 index 0000000000..9cf7d8302f --- /dev/null +++ b/src/gpu/GrStrokeInfo.h @@ -0,0 +1,191 @@ +/* + * 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 07efb40866..6166b56fb7 100644 --- a/src/gpu/GrStyle.h +++ b/src/gpu/GrStyle.h @@ -85,11 +85,6 @@ 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; @@ -138,12 +133,6 @@ 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 e962978fc3..86a84ceb0a 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,53 +237,26 @@ SkStrokeRec TestStrokeRec(SkRandom* random) { return rec; } -void TestStyle(SkRandom* random, GrStyle* style) { - SkStrokeRec::InitStyle initStyle = +GrStrokeInfo TestStrokeInfo(SkRandom* random) { + SkStrokeRec::InitStyle style = SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1)); - 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); + 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]; } - *style = GrStyle(stroke, pe.get()); + dashInfo.fPhase = random->nextRangeScalar(0, sum); + strokeInfo.setDashInfo(dashInfo); + delete[] dashInfo.fIntervals; + return strokeInfo; } -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 a0f81e7ed9..ba5848b4b1 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 "GrStyle.h" +#include "GrStrokeInfo.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) { - GrStyle style(paint, SkPaint::kStroke_Style); + GrStrokeInfo strokeInfo(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, style); + fDrawContext->drawPath(fClip, grPaint, *draw.fMatrix, path, strokeInfo); return; } @@ -535,8 +535,9 @@ void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint return; } - GrStyle style(paint); - fDrawContext->drawRect(fClip, grPaint, *draw.fMatrix, rect, &style); + GrStrokeInfo strokeInfo(paint); + + fDrawContext->drawRect(fClip, grPaint, *draw.fMatrix, rect, &strokeInfo); } /////////////////////////////////////////////////////////////////////////////// @@ -553,7 +554,7 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect, return; } - GrStyle style(paint); + GrStrokeInfo strokeInfo(paint); if (paint.getMaskFilter()) { // try to hit the fast path for drawing filtered round rects @@ -576,7 +577,7 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect, &grPaint, fClip, *draw.fMatrix, - style.strokeRec(), + strokeInfo, devRRect)) { return; } @@ -586,7 +587,7 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect, } } - if (paint.getMaskFilter() || style.pathEffect()) { + if (paint.getMaskFilter() || paint.getPathEffect()) { // 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. @@ -600,9 +601,9 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect, return; } - SkASSERT(!style.pathEffect()); + SkASSERT(!strokeInfo.isDashed()); - fDrawContext->drawRRect(fClip, grPaint, *draw.fMatrix, rect, style); + fDrawContext->drawRRect(fClip, grPaint, *draw.fMatrix, rect, strokeInfo); } @@ -674,7 +675,10 @@ void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint return; } - fDrawContext->drawOval(fClip, grPaint, *draw.fMatrix, oval, GrStyle(paint)); + GrStrokeInfo strokeInfo(paint); + SkASSERT(!strokeInfo.isDashed()); + + fDrawContext->drawOval(fClip, grPaint, *draw.fMatrix, oval, strokeInfo); } #include "SkMaskFilter.h" diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp index 156bb7e6bf..9750c96f9d 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 "GrStyle.h" +#include "GrStrokeInfo.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, GrStyle::SimpleFill(), - true); + rectPath, &grPaint, viewMatrix, mf, paint.getPathEffect(), + GrStrokeInfo::FillInfo(), true); } diff --git a/src/gpu/batches/GrAAConvexPathRenderer.cpp b/src/gpu/batches/GrAAConvexPathRenderer.cpp index f557c9b9e9..8c55de7e79 100644 --- a/src/gpu/batches/GrAAConvexPathRenderer.cpp +++ b/src/gpu/batches/GrAAConvexPathRenderer.cpp @@ -18,6 +18,7 @@ #include "GrPathUtils.h" #include "GrProcessor.h" #include "GrPipelineBuilder.h" +#include "GrStrokeInfo.h" #include "SkGeometry.h" #include "SkPathPriv.h" #include "SkString.h" @@ -681,7 +682,7 @@ const GrGeometryProcessor* QuadEdgeEffect::TestCreate(GrProcessorTestData* d) { bool GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { return (args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias && - args.fStyle->isSimpleFill() && !args.fPath->isInverseFillType() && + args.fStroke->isFillStyle() && !args.fPath->isInverseFillType() && args.fPath->isConvex()); } diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp index ba52bf9213..f891b8d1f5 100644 --- a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp +++ b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp @@ -81,14 +81,13 @@ 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 || - args.fStyle->isSimpleHairline() || args.fPath->isInverseFillType() || - args.fPath->isVolatile()) { + 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()) { return false; } @@ -101,23 +100,16 @@ 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 (!stroke.isFillStyle()) { - SkScalar extraWidth = stroke.getWidth(); - if (SkPaint::kMiter_Join == stroke.getJoin()) { - extraWidth = SkTMax(extraWidth, 2.0f*stroke.getMiter()); + if (!args.fStroke->isFillStyle()) { + SkScalar extraWidth = args.fStroke->getWidth(); + if (SkPaint::kMiter_Join == args.fStroke->getJoin()) { + extraWidth = SkTMax(extraWidth, 2.0f*args.fStroke->getMiter()); } maxDim += extraWidth; } -#endif return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; } @@ -560,12 +552,11 @@ bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) { } } - // 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()) { + AADistanceFieldPathBatch::Geometry geometry(*args.fStroke); + if (SkStrokeRec::kFill_Style == args.fStroke->getStyle()) { geometry.fPath = *args.fPath; } else { - args.fStyle->strokeRec().applyToPath(&geometry.fPath, *args.fPath); + args.fStroke->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 db4bbdfdb3..effd8c3b0f 100644 --- a/src/gpu/batches/GrAAHairLinePathRenderer.cpp +++ b/src/gpu/batches/GrAAHairLinePathRenderer.cpp @@ -618,12 +618,7 @@ bool GrAAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const return false; } - 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()) { + if (!IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullptr)) { return false; } @@ -944,11 +939,11 @@ void AAHairlineBatch::onPrepareDraws(Target* target) const { static GrDrawBatch* create_hairline_batch(GrColor color, const SkMatrix& viewMatrix, const SkPath& path, - const GrStyle& style, + const GrStrokeInfo& stroke, const SkIRect& devClipBounds) { SkScalar hairlineCoverage; uint8_t newCoverage = 0xff; - if (GrPathRenderer::IsStrokeHairlineOrEquivalent(style, viewMatrix, &hairlineCoverage)) { + if (GrPathRenderer::IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) { newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); } @@ -969,7 +964,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.fStyle, devClipBounds)); + *args.fStroke, devClipBounds)); args.fTarget->drawBatch(*args.fPipelineBuilder, batch); return true; @@ -982,10 +977,11 @@ 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, GrStyle::SimpleHairline(), devClipBounds); + return create_hairline_batch(color, viewMatrix, path, stroke, devClipBounds); } #endif diff --git a/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp index 91d3338c32..446f67f1c0 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 "GrStyle.h" +#include "GrStrokeInfo.h" #include "SkGeometry.h" #include "SkString.h" #include "SkTraceEvent.h" @@ -46,20 +46,16 @@ bool GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& arg if (!args.fPath->isConvex()) { return false; } - if (args.fStyle->pathEffect()) { - return false; - } - const SkStrokeRec& stroke = args.fStyle->strokeRec(); - if (stroke.getStyle() == SkStrokeRec::kStroke_Style) { + if (args.fStroke->getStyle() == SkStrokeRec::kStroke_Style) { if (!args.fViewMatrix->isSimilarity()) { return false; } - SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth(); - return strokeWidth >= 1.0f && strokeWidth <= kMaxStrokeWidth && - SkPathPriv::IsClosedSingleContour(*args.fPath) && - stroke.getJoin() != SkPaint::Join::kRound_Join; + 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; } - return stroke.getStyle() == SkStrokeRec::kFill_Style; + return args.fStroke->getStyle() == SkStrokeRec::kFill_Style; } // extract the result vertices and indices from the GrAAConvexTessellator @@ -329,10 +325,10 @@ bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { geometry.fColor = args.fColor; geometry.fViewMatrix = *args.fViewMatrix; geometry.fPath = *args.fPath; - 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(); + 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(); 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 8cb8046af4..9ee27c78dd 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.fStyle->isDashed() && args.fPath->isLine(pts)) { - return GrDashingEffect::CanDrawDashLine(pts, *args.fStyle, *args.fViewMatrix); + if (args.fStroke->isDashed() && args.fPath->isLine(pts)) { + return GrDashingEffect::CanDrawDashLine(pts, *args.fStroke, *args.fViewMatrix); } return false; } @@ -28,7 +28,7 @@ bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) { pts, args.fAntiAlias, msaaIsEnabled, - *args.fStyle)); + *args.fStroke)); if (!batch) { return false; } diff --git a/src/gpu/batches/GrDefaultPathRenderer.cpp b/src/gpu/batches/GrDefaultPathRenderer.cpp index 9994b26a1a..1de0bf771e 100644 --- a/src/gpu/batches/GrDefaultPathRenderer.cpp +++ b/src/gpu/batches/GrDefaultPathRenderer.cpp @@ -422,21 +422,22 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, GrColor color, const SkMatrix& viewMatrix, const SkPath& path, - const GrStyle& origStyle, + const GrStrokeInfo& origStroke, bool stencilOnly) { - const GrStyle* style = &origStyle; + SkTCopyOnFirstWrite stroke(origStroke); SkScalar hairlineCoverage; uint8_t newCoverage = 0xff; - bool isHairline = false; - if (IsStrokeHairlineOrEquivalent(*style, viewMatrix, &hairlineCoverage)) { + if (IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, &hairlineCoverage)) { newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); - style = &GrStyle::SimpleHairline(); - isHairline = true; - } else { - SkASSERT(style->isSimpleFill()); + + if (!stroke->isHairlineStyle()) { + stroke.writable()->setHairlineStyle(); + } } + 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)); @@ -459,7 +460,7 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, lastPassIsBounds = false; drawFace[0] = GrPipelineBuilder::kBoth_DrawFace; } else { - if (single_pass_path(path, style->strokeRec())) { + if (single_pass_path(path, *stroke)) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; @@ -595,11 +596,10 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target, } bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - // 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)); + // 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)); } bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) { @@ -609,7 +609,7 @@ bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) { args.fColor, *args.fViewMatrix, *args.fPath, - *args.fStyle, + *args.fStroke, 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, GrStyle::SimpleFill(), true); + *args.fPath, GrStrokeInfo::FillInfo(), 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 - GrStyle style(SkStrokeRec::kHairline_InitStyle); + GrStrokeInfo stroke(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 8a74d3a011..8156462a51 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 GrStyle&, + const GrStrokeInfo&, bool stencilOnly); bool fSeparateStencil; diff --git a/src/gpu/batches/GrMSAAPathRenderer.cpp b/src/gpu/batches/GrMSAAPathRenderer.cpp index a382c42054..a9ba06c5f4 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) { +static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& stroke) { if (!path.isInverseFillType()) { return path.isConvex(); } @@ -38,7 +38,7 @@ static inline bool single_pass_path(const SkPath& path) { GrPathRenderer::StencilSupport GrMSAAPathRenderer::onGetStencilSupport(const SkPath& path) const { - if (single_pass_path(path)) { + if (single_pass_path(path, SkStrokeRec(SkStrokeRec::kFill_InitStyle))) { return GrPathRenderer::kNoRestriction_StencilSupport; } else { return GrPathRenderer::kStencilOnly_StencilSupport; @@ -571,7 +571,9 @@ 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)); @@ -584,7 +586,7 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawTarget* target, bool reverse = false; bool lastPassIsBounds; - if (single_pass_path(path)) { + if (single_pass_path(path, *stroke)) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; @@ -701,35 +703,34 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawTarget* target, } bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - // This path renderer does not support hairlines. We defer on anything that could be handled - // as a hairline by another path renderer. Also, arbitrary path effects could produce - // a hairline result. - return !IsStrokeHairlineOrEquivalent(*args.fStyle, *args.fViewMatrix, nullptr) && - !args.fStyle->hasNonDashPathEffect() && !args.fAntiAlias; + return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullptr) && + !args.fAntiAlias; } bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) { GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrMSAAPathRenderer::onDrawPath"); - 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)) { + SkPath path; + GrStrokeInfo stroke(*args.fStroke); + if (stroke.isDashed()) { + if (!stroke.applyDashToPath(&path, &stroke, *args.fPath)) { 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; + path = *args.fPath; + } + if (!stroke.isFillStyle()) { + stroke.setResScale(SkScalarAbs(args.fViewMatrix->getMaxScale())); + if (!stroke.applyToPath(&path, path)) { + return false; + } + stroke.setFillStyle(); } return this->internalDrawPath(args.fTarget, args.fPipelineBuilder, args.fColor, *args.fViewMatrix, - *path, + path, + stroke, false); } @@ -738,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, true); + *args.fPath, GrStrokeInfo::FillInfo(), true); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/batches/GrMSAAPathRenderer.h b/src/gpu/batches/GrMSAAPathRenderer.h index 434a962190..a35536014e 100644 --- a/src/gpu/batches/GrMSAAPathRenderer.h +++ b/src/gpu/batches/GrMSAAPathRenderer.h @@ -26,6 +26,7 @@ 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 c26b4c0243..46993c7f33 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 "GrStyle.h" +#include "GrStrokeInfo.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.fStyle->isSimpleFill() && !args.fPath->isInverseFillType() && + args.fStroke->isFillStyle() && !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 9d8d07de84..6933efebe3 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 "GrStyle.h" +#include "GrStrokeInfo.h" #include "batches/GrRectBatchFactory.h" GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider, @@ -31,9 +31,7 @@ GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* } bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - // 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()) { + if (args.fStroke->isHairlineStyle()) { return false; } if (!args.fIsStencilDisabled) { @@ -47,19 +45,19 @@ bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c } static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const SkPath& skPath, - const GrStyle& style) { + const GrStrokeInfo& stroke) { GrUniqueKey key; bool isVolatile; - GrPath::ComputeKey(skPath, style, &key, &isVolatile); + GrPath::ComputeKey(skPath, stroke, &key, &isVolatile); SkAutoTUnref path( static_cast(resourceProvider->findAndRefResourceByUniqueKey(key))); if (!path) { - path.reset(resourceProvider->createPath(skPath, style)); + path.reset(resourceProvider->createPath(skPath, stroke)); if (!isVolatile) { resourceProvider->assignUniqueKeyToResource(key, path); } } else { - SkASSERT(path->isEqualTo(skPath, style)); + SkASSERT(path->isEqualTo(skPath, stroke)); } return path.release(); } @@ -68,14 +66,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, GrStyle::SimpleFill())); + SkAutoTUnref p(get_gr_path(fResourceProvider, *args.fPath, GrStrokeInfo::FillInfo())); 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.fStyle->strokeRec().isHairlineStyle()); + SkASSERT(!args.fStroke->isHairlineStyle()); const SkPath& path = *args.fPath; GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder; const SkMatrix& viewMatrix = *args.fViewMatrix; @@ -87,7 +85,7 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag); } - SkAutoTUnref p(get_gr_path(fResourceProvider, path, *args.fStyle)); + SkAutoTUnref p(get_gr_path(fResourceProvider, path, *args.fStroke)); if (path.isInverseFillType()) { static constexpr GrStencilSettings kInvertedStencilPass( diff --git a/src/gpu/batches/GrTessellatingPathRenderer.cpp b/src/gpu/batches/GrTessellatingPathRenderer.cpp index d2cfb6e9cb..2c8520b28a 100644 --- a/src/gpu/batches/GrTessellatingPathRenderer.cpp +++ b/src/gpu/batches/GrTessellatingPathRenderer.cpp @@ -105,10 +105,9 @@ 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. Similary, we skip the non-hairlines that can be treated as hairline. - // An arbitrary path effect could produce a hairline result so we pass on those. - return !IsStrokeHairlineOrEquivalent(*args.fStyle, *args.fViewMatrix, nullptr) && - !args.fStyle->hasNonDashPathEffect() && !args.fAntiAlias && !args.fPath->isConvex(); + // simpler algorithms. + return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullptr) && + !args.fAntiAlias && !args.fPath->isConvex(); } class TessellatingPathBatch : public GrVertexBatch { @@ -117,10 +116,10 @@ public: static GrDrawBatch* Create(const GrColor& color, const SkPath& path, - const GrStyle& style, + const GrStrokeInfo& stroke, const SkMatrix& viewMatrix, SkRect clipBounds) { - return new TessellatingPathBatch(color, path, style, viewMatrix, clipBounds); + return new TessellatingPathBatch(color, path, stroke, viewMatrix, clipBounds); } const char* name() const override { return "TessellatingPathBatch"; } @@ -143,51 +142,48 @@ 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 clipBoundsCnt = + int clipBoundsSize32 = fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) : 0; - 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; - } + 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; } SkPath path; - if (fStyle.applies()) { - SkStrokeRec::InitStyle fill; - SkAssertResult(fStyle.applyToPath(&path, &fill, fPath, styleScale)); - SkASSERT(SkStrokeRec::kFill_InitStyle == fill); + GrStrokeInfo stroke(fStroke); + if (stroke.isDashed()) { + if (!stroke.applyDashToPath(&path, &stroke, fPath)) { + return; + } } 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); @@ -196,7 +192,7 @@ private: return; } this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count); - if (!fPath.isVolatile() && styleDataCnt >= 0) { + if (!fPath.isVolatile()) { TessInfo info; info.fTolerance = isLinear ? 0 : tol; info.fCount = count; @@ -244,13 +240,13 @@ private: TessellatingPathBatch(const GrColor& color, const SkPath& path, - const GrStyle& style, + const GrStrokeInfo& stroke, const SkMatrix& viewMatrix, const SkRect& clipBounds) : INHERITED(ClassID()) , fColor(color) , fPath(path) - , fStyle(style) + , fStroke(stroke) , fViewMatrix(viewMatrix) { const SkRect& pathBounds = path.getBounds(); fClipBounds = clipBounds; @@ -262,13 +258,14 @@ private: } else { fBounds = path.getBounds(); } - style.adjustBounds(&fBounds, fBounds); + SkScalar radius = stroke.getInflationRadius(); + fBounds.outset(radius, radius); viewMatrix.mapRect(&fBounds); } GrColor fColor; SkPath fPath; - GrStyle fStyle; + GrStrokeInfo fStroke; SkMatrix fViewMatrix; SkRect fClipBounds; // in source space GrXPOverridesForBatch fPipelineInfo; @@ -294,7 +291,7 @@ bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { } vmi.mapRect(&clipBounds); SkAutoTUnref batch(TessellatingPathBatch::Create(args.fColor, *args.fPath, - *args.fStyle, *args.fViewMatrix, + *args.fStroke, *args.fViewMatrix, clipBounds)); args.fTarget->drawBatch(*args.fPipelineBuilder, batch); @@ -316,11 +313,8 @@ DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) { SkFAIL("Cannot invert matrix\n"); } vmi.mapRect(&clipBounds); - GrStyle style; - do { - GrTest::TestStyle(random, &style); - } while (style.strokeRec().isHairlineStyle()); - return TessellatingPathBatch::Create(color, path, style, viewMatrix, clipBounds); + GrStrokeInfo strokeInfo = GrTest::TestStrokeInfo(random); + return TessellatingPathBatch::Create(color, path, strokeInfo, viewMatrix, clipBounds); } #endif diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp index 8a38ebe573..f1e8016eb9 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 "GrStyle.h" +#include "GrStrokeInfo.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 GrStyle& style, +bool GrDashingEffect::CanDrawDashLine(const SkPoint pts[2], const GrStrokeInfo& strokeInfo, 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 GrStyle& style return false; } - if (!style.isDashed() || 2 != style.dashIntervalCnt()) { + if (!strokeInfo.isDashed() || 2 != strokeInfo.getDashCount()) { return false; } - const SkScalar* intervals = style.dashIntervals(); + const SkScalar* intervals = strokeInfo.getDashIntervals(); if (0 == intervals[0] && 0 == intervals[1]) { return false; } - SkPaint::Cap cap = style.strokeRec().getCap(); + SkPaint::Cap cap = strokeInfo.getCap(); // Current we do don't handle Round or Square cap dashes if (SkPaint::kRound_Cap == cap && intervals[0] != 0.f) { return false; @@ -690,15 +690,14 @@ private: }; static GrDrawBatch* create_batch(GrColor color, const SkMatrix& viewMatrix, const SkPoint pts[2], - bool useAA, const GrStyle& style, bool msaaRT) { - SkASSERT(GrDashingEffect::CanDrawDashLine(pts, style, viewMatrix)); - const SkScalar* intervals = style.dashIntervals(); - SkScalar phase = style.dashPhase(); + bool useAA, const GrStrokeInfo& strokeInfo, bool msaaRT) { + const SkScalar* intervals = strokeInfo.getDashIntervals(); + SkScalar phase = strokeInfo.getDashPhase(); - SkPaint::Cap cap = style.strokeRec().getCap(); + SkPaint::Cap cap = strokeInfo.getCap(); DashBatch::Geometry geometry; - geometry.fSrcStrokeWidth = style.strokeRec().getWidth(); + geometry.fSrcStrokeWidth = strokeInfo.getWidth(); // the phase should be normalized to be [0, sum of all intervals) SkASSERT(phase >= 0 && phase < intervals[0] + intervals[1]); @@ -748,8 +747,8 @@ GrDrawBatch* GrDashingEffect::CreateDashLineBatch(GrColor color, const SkPoint pts[2], bool useAA, bool msaaIsEnabled, - const GrStyle& style) { - return create_batch(color, viewMatrix, pts, useAA, style, msaaIsEnabled); + const GrStrokeInfo& strokeInfo) { + return create_batch(color, viewMatrix, pts, useAA, strokeInfo, msaaIsEnabled); } ////////////////////////////////////////////////////////////////////////////// @@ -1290,11 +1289,17 @@ 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)); - GrStyle style(p); + GrStrokeInfo strokeInfo(p); - return create_batch(color, viewMatrix, pts, useAA, style, msaaRT); + 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); } #endif diff --git a/src/gpu/effects/GrDashingEffect.h b/src/gpu/effects/GrDashingEffect.h index 8899820114..d67a63eb4b 100644 --- a/src/gpu/effects/GrDashingEffect.h +++ b/src/gpu/effects/GrDashingEffect.h @@ -14,7 +14,7 @@ class GrClip; class GrDrawBatch; -class GrStyle; +class GrStrokeInfo; namespace GrDashingEffect { GrDrawBatch* CreateDashLineBatch(GrColor, @@ -22,8 +22,8 @@ namespace GrDashingEffect { const SkPoint pts[2], bool useAA, bool msaaIsEnabled, - const GrStyle& style); - bool CanDrawDashLine(const SkPoint pts[2], const GrStyle& style, + const GrStrokeInfo& strokeInfo); + bool CanDrawDashLine(const SkPoint pts[2], const GrStrokeInfo& strokeInfo, const SkMatrix& viewMatrix); } diff --git a/src/gpu/gl/GrGLPath.cpp b/src/gpu/gl/GrGLPath.cpp index 05460187ef..ed5a31d9d2 100644 --- a/src/gpu/gl/GrGLPath.cpp +++ b/src/gpu/gl/GrGLPath.cpp @@ -8,7 +8,6 @@ #include "GrGLPath.h" #include "GrGLPathRendering.h" #include "GrGLGpu.h" -#include "GrStyle.h" namespace { inline GrGLubyte verb_to_gl_path_cmd(SkPath::Verb verb) { @@ -252,7 +251,9 @@ void GrGLPath::InitPathObjectPathData(GrGLGpu* gpu, SkAssertResult(init_path_object_for_general_path(gpu, pathID, skPath)); } -void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const SkStrokeRec& stroke) { +void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const GrStrokeInfo& stroke) { + SkASSERT(stroke.needToApply()); + SkASSERT(!stroke.isDashed()); SkASSERT(!stroke.isHairlineStyle()); GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth()))); @@ -269,8 +270,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 GrStyle& style) - : INHERITED(gpu, origSkPath, style), +GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& origStroke) + : INHERITED(gpu, origSkPath, origStroke), fPathID(gpu->glPathRendering()->genPaths(1)) { if (origSkPath.isEmpty()) { @@ -280,21 +281,21 @@ GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStyle& style) } else { const SkPath* skPath = &origSkPath; SkTLazy tmpPath; - SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); + const GrStrokeInfo* stroke = &origStroke; + GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle); - if (style.pathEffect()) { + if (stroke->isDashed()) { // Skia stroking and NVPR stroking differ with respect to dashing // pattern. - // Convert a dashing (or other path effect) to either a stroke or a fill. - if (style.applyPathEffectToPath(tmpPath.init(), &stroke, *skPath, SK_Scalar1)) { + // Convert a dashing to either a stroke or a fill. + if (stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) { 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. @@ -303,9 +304,10 @@ GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStyle& style) if (!tmpPath.isValid()) { tmpPath.init(); } - SkAssertResult(stroke.applyToPath(tmpPath.get(), *skPath)); + SkAssertResult(stroke->applyToPath(tmpPath.get(), *skPath)); skPath = tmpPath.get(); - stroke.setFillStyle(); + tmpStroke.setFillStyle(); + stroke = &tmpStroke; } } @@ -313,16 +315,18 @@ GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStyle& style) 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); + InitPathObjectStroke(gpu, fPathID, *stroke); + + // FIXME: try to account for stroking, without rasterizing the stroke. + fBounds.outset(stroke->getWidth(), stroke->getWidth()); } } diff --git a/src/gpu/gl/GrGLPath.h b/src/gpu/gl/GrGLPath.h index ddcee533ee..1ef1346133 100644 --- a/src/gpu/gl/GrGLPath.h +++ b/src/gpu/gl/GrGLPath.h @@ -12,7 +12,6 @@ #include "gl/GrGLTypes.h" class GrGLGpu; -class GrStyle; /** * Currently this represents a path built using GL_NV_path_rendering. If we @@ -28,12 +27,12 @@ public: static void InitPathObjectPathData(GrGLGpu*, GrGLuint pathID, const SkPath&); - static void InitPathObjectStroke(GrGLGpu*, GrGLuint pathID, const SkStrokeRec&); + static void InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const GrStrokeInfo& stroke); static void InitPathObjectEmptyPath(GrGLGpu*, GrGLuint pathID); - GrGLPath(GrGLGpu*, const SkPath&, const GrStyle&); + GrGLPath(GrGLGpu* gpu, const SkPath& path, const GrStrokeInfo& stroke); 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 da1e9fe709..6ed7bcc425 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 GrStyle& style) +GrGLPathRange::GrGLPathRange(GrGLGpu* gpu, PathGenerator* pathGenerator, const GrStrokeInfo& stroke) : INHERITED(gpu, pathGenerator), - fStyle(style), + fStroke(stroke), 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 GrStyle& style) + const GrStrokeInfo& stroke) : INHERITED(gpu, numPaths), - fStyle(style), + fStroke(stroke), fBasePathID(basePathID), fGpuMemorySize(gpuMemorySize) { this->init(); @@ -33,20 +33,19 @@ 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 = fStyle.pathEffect() || - (stroke.needToApply() && stroke.getCap() != SkPaint::kButt_Cap); + bool forceFill = fStroke.isDashed() || + (fStroke.needToApply() && fStroke.getCap() != SkPaint::kButt_Cap); if (forceFill) { fShouldStroke = false; fShouldFill = true; } else { - fShouldStroke = stroke.needToApply(); - fShouldFill = stroke.isFillStyle() || - stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style; + fShouldStroke = fStroke.needToApply(); + fShouldFill = fStroke.isFillStyle() || + fStroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style; } } @@ -55,6 +54,7 @@ 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,25 +65,32 @@ 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, fStyle.strokeRec()); + GrGLPath::InitPathObjectStroke(gpu, fBasePathID + index, fStroke); } else { const SkPath* skPath = &origSkPath; SkTLazy tmpPath; - 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)) { + 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)) { 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 7d920105a0..ed9766d958 100644 --- a/src/gpu/gl/GrGLPathRange.h +++ b/src/gpu/gl/GrGLPathRange.h @@ -9,7 +9,7 @@ #define GrGLPathRange_DEFINED #include "../GrPathRange.h" -#include "GrStyle.h" +#include "GrStrokeInfo.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 GrStyle&); + GrGLPathRange(GrGLGpu*, PathGenerator*, const GrStrokeInfo&); /** * 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 GrStyle&); + const GrStrokeInfo&); GrGLuint basePathID() const { return fBasePathID; } @@ -54,7 +54,7 @@ private: void init(); size_t onGpuMemorySize() const override { return fGpuMemorySize; } - const GrStyle fStyle; + const GrStrokeInfo fStroke; GrGLuint fBasePathID; mutable size_t fGpuMemorySize; bool fShouldStroke; diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp index 5616f9d58a..0ecf58a8e1 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 GrStyle& style) { - return new GrGLPath(this->gpu(), inPath, style); +GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStrokeInfo& stroke) { + return new GrGLPath(this->gpu(), inPath, stroke); } GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator, - const GrStyle& style) { - return new GrGLPathRange(this->gpu(), pathGenerator, style); + const GrStrokeInfo& stroke) { + return new GrGLPathRange(this->gpu(), pathGenerator, stroke); } void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) { diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h index 8fb699deb3..b39c866c6f 100644 --- a/src/gpu/gl/GrGLPathRendering.h +++ b/src/gpu/gl/GrGLPathRendering.h @@ -16,7 +16,6 @@ class GrGLNameAllocator; class GrGLGpu; -class GrStyle; /** * This class wraps the NV_path_rendering extension and manages its various @@ -34,9 +33,9 @@ public: virtual ~GrGLPathRendering(); // GrPathRendering implementations. - GrPath* createPath(const SkPath&, const GrStyle&) override; + GrPath* createPath(const SkPath&, const GrStrokeInfo&) override; virtual GrPathRange* createPathRange(GrPathRange::PathGenerator*, - const GrStyle&) override; + const GrStrokeInfo&) 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 cc018845f6..c2c1c569e8 100644 --- a/src/gpu/text/GrStencilAndCoverTextContext.cpp +++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp @@ -235,18 +235,6 @@ 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) { @@ -265,11 +253,11 @@ GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob, fCacheSize += blob->cpuMemorySize(); return *blob; } else { - GrStyle style(skPaint); + GrStrokeInfo stroke(skPaint); SkSTArray<4, uint32_t, true> key; - key.reset(1 + style_key_cnt(style)); + key.reset(1 + stroke.computeUniqueKeyFragmentData32Cnt()); key[0] = skBlob->uniqueID(); - write_style_key(&key[1], style); + stroke.asUniqueKeyFragment(&key[1]); if (TextBlob** found = fBlobKeyCache.find(key)) { fLRUList.remove(*found); fLRUList.addToTail(*found); @@ -365,48 +353,41 @@ private: //////////////////////////////////////////////////////////////////////////////////////////////////// GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) - : fStyle(fontAndStroke), + : fStroke(fontAndStroke), fFont(fontAndStroke), fTotalGlyphCount(0), fFallbackGlyphCount(0), fDetachedGlyphCache(nullptr), fLastDrawnGlyphsID(SK_InvalidUniqueID) { SkASSERT(fFont.getTextSize() > 0); - SkASSERT(!fStyle.hasNonDashPathEffect()); // Arbitrary path effects not supported. - SkASSERT(!fStyle.isSimpleHairline()); // Hairlines are not supported. + SkASSERT(!fStroke.isHairlineStyle()); // 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() && fStyle.isSimpleFill()) { - const SkStrokeRec& stroke = fStyle.strokeRec(); + if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle()) { // 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() && !fStyle.isDashed()) { - const SkStrokeRec& stroke = fStyle.strokeRec(); + if (!fFont.getPathEffect() && !fStroke.isDashed()) { // 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 (!fStyle.isSimpleFill()) { - SkStrokeRec strokeRec(SkStrokeRec::kFill_InitStyle); - strokeRec.setStrokeStyle(stroke.getWidth() / fTextRatio, - SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()); - fStyle = GrStyle(strokeRec, fStyle.pathEffect()); + if (!fStroke.isFillStyle()) { + fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio, + SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle()); } fFont.setLinearText(true); @@ -426,7 +407,7 @@ GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) } // Generate the key that will be used to cache the GPU glyph path objects. - if (fUsingRawGlyphPaths && fStyle.isSimpleFill()) { + if (fUsingRawGlyphPaths && fStroke.isFillStyle()) { static const GrUniqueKey::Domain kRawFillPathGlyphDomain = GrUniqueKey::GenerateDomain(); const SkTypeface* typeface = fFont.getTypeface(); @@ -435,30 +416,24 @@ GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) } else { static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain(); - int styleDataCount = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectAndStrokeRec); - // Key should be valid since we opted out of drawing arbitrary path effects. - SkASSERT(styleDataCount >= 0); + int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt(); if (fUsingRawGlyphPaths) { const SkTypeface* typeface = fFont.getTypeface(); - GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + styleDataCount); + GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + strokeDataCount); reinterpret_cast(builder[0]) = typeface ? typeface->uniqueID() : 0; - reinterpret_cast(builder[1]) = styleDataCount; - if (styleDataCount) { - write_style_key(&builder[2], fStyle); - } + reinterpret_cast(builder[1]) = strokeDataCount; + fStroke.asUniqueKeyFragment(&builder[2]); } 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 + styleDataCount + descDataCount); + 2 + strokeDataCount + descDataCount); reinterpret_cast(builder[0]) = typeface ? typeface->uniqueID() : 0; - reinterpret_cast(builder[1]) = styleDataCount | (descDataCount << 16); - if (styleDataCount) { - write_style_key(&builder[2], fStyle); - } - memcpy(&builder[2 + styleDataCount], desc, desc->getLength()); + reinterpret_cast(builder[1]) = strokeDataCount | (descDataCount << 16); + fStroke.asUniqueKeyFragment(&builder[2]); + memcpy(&builder[2 + strokeDataCount], desc, desc->getLength()); } } } @@ -566,13 +541,13 @@ GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx) if (fUsingRawGlyphPaths) { SkScalerContextEffects noeffects; glyphs = ctx->resourceProvider()->createGlyphs(fFont.getTypeface(), noeffects, - nullptr, fStyle); + nullptr, fStroke); } else { SkGlyphCache* cache = this->getGlyphCache(); glyphs = ctx->resourceProvider()->createGlyphs(cache->getScalerContext()->getTypeface(), cache->getScalerContext()->getEffects(), &cache->getDescriptor(), - fStyle); + fStroke); } ctx->resourceProvider()->assignUniqueKeyToResource(fGlyphPathsKey, glyphs); } @@ -646,9 +621,9 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, if (fFallbackTextBlob) { SkPaint fallbackSkPaint(originalSkPaint); - fStyle.strokeRec().applyToPaint(&fallbackSkPaint); - if (!fStyle.isSimpleFill()) { - fallbackSkPaint.setStrokeWidth(fStyle.strokeRec().getWidth() * fTextRatio); + fStroke.applyToPaint(&fallbackSkPaint); + if (!fStroke.isFillStyle()) { + fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); } fallbackTextContext->drawTextBlob(ctx, dc, pipelineBuilder->clip(), fallbackSkPaint, diff --git a/src/gpu/text/GrStencilAndCoverTextContext.h b/src/gpu/text/GrStencilAndCoverTextContext.h index 2c13ca035c..b1faba11b0 100644 --- a/src/gpu/text/GrStencilAndCoverTextContext.h +++ b/src/gpu/text/GrStencilAndCoverTextContext.h @@ -9,7 +9,7 @@ #define GrStencilAndCoverTextContext_DEFINED #include "GrDrawContext.h" -#include "GrStyle.h" +#include "GrStrokeInfo.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*); - GrStyle fStyle; + GrStrokeInfo fStroke; SkPaint fFont; SkScalar fTextRatio; float fTextInverseRatio; diff --git a/tests/GpuDrawPathTest.cpp b/tests/GpuDrawPathTest.cpp index dc8db0ff70..2dc7702fff 100644 --- a/tests/GpuDrawPathTest.cpp +++ b/tests/GpuDrawPathTest.cpp @@ -11,7 +11,7 @@ #include "GrContext.h" #include "GrPath.h" -#include "GrStyle.h" +#include "GrStrokeInfo.h" #include "SkBitmap.h" #include "SkCanvas.h" #include "SkColor.h" @@ -104,8 +104,9 @@ DEF_GPUTEST(GrPathKeys, reporter, /*factory*/) { bool isVolatile; GrUniqueKey key1, key2; - GrPath::ComputeKey(path1, GrStyle::SimpleFill(), &key1, &isVolatile); - GrPath::ComputeKey(path2, GrStyle::SimpleFill(), &key2, &isVolatile); + GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle); + GrPath::ComputeKey(path1, stroke, &key1, &isVolatile); + GrPath::ComputeKey(path2, stroke, &key2, &isVolatile); REPORTER_ASSERT(reporter, key1 != key2); } diff --git a/tests/TessellatingPathRendererTests.cpp b/tests/TessellatingPathRendererTests.cpp index 9d550775ba..32973ee1c8 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); - GrStyle style(SkStrokeRec::kFill_InitStyle); + GrStrokeInfo stroke(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.fStyle = &style; + args.fStroke = &stroke; args.fAntiAlias = false; tess.drawPath(args); }