diff --git a/include/core/SkFont.h b/include/core/SkFont.h index cfecf53aea..7cef8241a4 100644 --- a/include/core/SkFont.h +++ b/include/core/SkFont.h @@ -511,6 +511,7 @@ private: bool hasSomeAntiAliasing() const; friend class GrAtlasSubRun; + friend class GrTextBlob; friend class SkFontPriv; friend class SkGlyphRunListPainter; friend class SkTextBlobCacheDiffCanvas; diff --git a/src/gpu/text/GrTextBlob.cpp b/src/gpu/text/GrTextBlob.cpp index b78715fdcb..c990744429 100644 --- a/src/gpu/text/GrTextBlob.cpp +++ b/src/gpu/text/GrTextBlob.cpp @@ -39,11 +39,91 @@ bool GrTextBlob::Key::operator==(const GrTextBlob::Key& other) const { return 0 == memcmp(this, &other, sizeof(Key)); } -// -- GrTextBlob::PathGlyph ------------------------------------------------------------------------ -GrTextBlob::PathGlyph::PathGlyph(const SkPath& path, SkPoint origin) +// -- GrPathSubRun::PathGlyph ---------------------------------------------------------------------- +GrPathSubRun::PathGlyph::PathGlyph(const SkPath& path, SkPoint origin) : fPath(path) , fOrigin(origin) {} +// -- GrPathSubRun --------------------------------------------------------------------------------- +GrPathSubRun::GrPathSubRun(bool isAntiAliased, + const SkStrikeSpec& strikeSpec, + SkSpan paths) + : fIsAntiAliased{isAntiAliased} + , fStrikeSpec{strikeSpec} + , fPaths{paths} {} + +void GrPathSubRun::draw(const GrClip* clip, + const SkMatrixProvider& viewMatrix, + const SkGlyphRunList& glyphRunList, + GrRenderTargetContext* rtc) { + SkASSERT(!fPaths.empty()); + SkPoint drawOrigin = glyphRunList.origin(); + const SkPaint& drawPaint = glyphRunList.paint(); + SkPaint runPaint{drawPaint}; + runPaint.setAntiAlias(fIsAntiAliased); + // If there are shaders, blurs or styles, the path must be scaled into source + // space independently of the CTM. This allows the CTM to be correct for the + // different effects. + GrStyle style(runPaint); + + bool needsExactCTM = runPaint.getShader() + || style.applies() + || runPaint.getMaskFilter(); + + // Calculate the matrix that maps the path glyphs from their size in the strike to + // the graphics source space. + SkScalar scale = this->fStrikeSpec.strikeToSourceRatio(); + SkMatrix strikeToSource = SkMatrix::Scale(scale, scale); + strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y()); + if (!needsExactCTM) { + for (const auto& pathPos : fPaths) { + const SkPath& path = pathPos.fPath; + const SkPoint pos = pathPos.fOrigin; // Transform the glyph to source space. + SkMatrix pathMatrix = strikeToSource; + pathMatrix.postTranslate(pos.x(), pos.y()); + SkPreConcatMatrixProvider strikeToDevice(viewMatrix, pathMatrix); + + GrStyledShape shape(path, drawPaint); + GrBlurUtils::drawShapeWithMaskFilter( + rtc->priv().getContext(), rtc, clip, runPaint, strikeToDevice, shape); + } + } else { + // Transform the path to device because the deviceMatrix must be unchanged to + // draw effect, filter or shader paths. + for (const auto& pathPos : fPaths) { + const SkPath& path = pathPos.fPath; + const SkPoint pos = pathPos.fOrigin; + // Transform the glyph to source space. + SkMatrix pathMatrix = strikeToSource; + pathMatrix.postTranslate(pos.x(), pos.y()); + + SkPath deviceOutline; + path.transform(pathMatrix, &deviceOutline); + deviceOutline.setIsVolatile(true); + GrStyledShape shape(deviceOutline, drawPaint); + GrBlurUtils::drawShapeWithMaskFilter( + rtc->priv().getContext(), rtc, clip, runPaint, viewMatrix, shape); + } + } +} + + +auto GrPathSubRun::MakePaths( + const SkZip& drawables, + bool isAntiAliased, + const SkStrikeSpec& strikeSpec, + SkArenaAlloc* alloc) -> GrSubRun* { + PathGlyph* pathData = alloc->makeInitializedArray( + drawables.size(), + [&](size_t i) -> PathGlyph { + auto [variant, pos] = drawables[i]; + return {*variant.path(), pos}; + }); + + return alloc->make( + isAntiAliased, strikeSpec, SkMakeSpan(pathData, drawables.size())); +}; + // -- GrAtlasSubRun -------------------------------------------------------------------------------- GrAtlasSubRun::GrAtlasSubRun(SubRunType type, GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec, GrMaskFormat format, SkRect vertexBounds, @@ -54,17 +134,8 @@ GrAtlasSubRun::GrAtlasSubRun(SubRunType type, GrTextBlob* textBlob, const SkStri , fStrikeSpec{strikeSpec} , fVertexBounds{vertexBounds} , fVertexData{vertexData} { - SkASSERT(fType != kTransformedPath); } -GrAtlasSubRun::GrAtlasSubRun(GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec) - : fBlob{textBlob} - , fType{kTransformedPath} - , fMaskFormat{kA8_GrMaskFormat} - , fStrikeSpec{strikeSpec} - , fVertexBounds{SkRect::MakeEmpty()} - , fVertexData{SkSpan{}} { } - static SkPMColor4f generate_filtered_color(const SkPaint& paint, const GrColorInfo& colorInfo) { SkColor4f c = paint.getColor4f(); if (auto* xform = colorInfo.colorSpaceXformFromSRGB()) { @@ -189,72 +260,13 @@ GrAtlasSubRun::makeAtlasTextOp(const GrClip* clip, return {clip, std::move(op)}; } -void GrAtlasSubRun::drawPaths(const GrClip* clip, - const SkMatrixProvider& viewMatrix, - const SkGlyphRunList& glyphRunList, - GrRenderTargetContext* rtc) { - SkASSERT(!this->paths().empty()); - SkPoint drawOrigin = glyphRunList.origin(); - const SkPaint& drawPaint = glyphRunList.paint(); - SkPaint runPaint{drawPaint}; - runPaint.setAntiAlias(this->isAntiAliased()); - // If there are shaders, blurs or styles, the path must be scaled into source - // space independently of the CTM. This allows the CTM to be correct for the - // different effects. - GrStyle style(runPaint); - - bool needsExactCTM = runPaint.getShader() - || style.applies() - || runPaint.getMaskFilter(); - - // Calculate the matrix that maps the path glyphs from their size in the strike to - // the graphics source space. - SkScalar scale = this->strikeSpec().strikeToSourceRatio(); - SkMatrix strikeToSource = SkMatrix::Scale(scale, scale); - strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y()); - if (!needsExactCTM) { - for (const auto& pathPos : this->paths()) { - const SkPath& path = pathPos.fPath; - const SkPoint pos = pathPos.fOrigin; // Transform the glyph to source space. - SkMatrix pathMatrix = strikeToSource; - pathMatrix.postTranslate(pos.x(), pos.y()); - SkPreConcatMatrixProvider strikeToDevice(viewMatrix, pathMatrix); - - GrStyledShape shape(path, drawPaint); - GrBlurUtils::drawShapeWithMaskFilter( - rtc->priv().getContext(), rtc, clip, runPaint, strikeToDevice, shape); - } - } else { - // Transform the path to device because the deviceMatrix must be unchanged to - // draw effect, filter or shader paths. - for (const auto& pathPos : this->paths()) { - const SkPath& path = pathPos.fPath; - const SkPoint pos = pathPos.fOrigin; - // Transform the glyph to source space. - SkMatrix pathMatrix = strikeToSource; - pathMatrix.postTranslate(pos.x(), pos.y()); - - SkPath deviceOutline; - path.transform(pathMatrix, &deviceOutline); - deviceOutline.setIsVolatile(true); - GrStyledShape shape(deviceOutline, drawPaint); - GrBlurUtils::drawShapeWithMaskFilter( - rtc->priv().getContext(), rtc, clip, runPaint, viewMatrix, shape); - } - } -} - void GrAtlasSubRun::draw(const GrClip* clip, const SkMatrixProvider& viewMatrix, const SkGlyphRunList& glyphRunList, GrRenderTargetContext* rtc) { - if (this->drawAsPaths()) { - this->drawPaths(clip, viewMatrix, glyphRunList, rtc); - } else { - auto[drawingClip, op] = this->makeAtlasTextOp(clip, viewMatrix, glyphRunList, rtc); - if (op != nullptr) { - rtc->priv().addDrawOp(drawingClip, std::move(op)); - } + auto[drawingClip, op] = this->makeAtlasTextOp(clip, viewMatrix, glyphRunList, rtc); + if (op != nullptr) { + rtc->priv().addDrawOp(drawingClip, std::move(op)); } } @@ -517,8 +529,6 @@ void GrAtlasSubRun::fillVertexData( } break; } - case kTransformedPath: - SK_ABORT("Paths don't generate vertex data."); } } @@ -528,16 +538,13 @@ int GrAtlasSubRun::glyphCount() const { bool GrAtlasSubRun::drawAsDistanceFields() const { return fType == kTransformedSDFT; } -bool GrAtlasSubRun::drawAsPaths() const { return fType == kTransformedPath; } - bool GrAtlasSubRun::needsTransform() const { - return fType == kTransformedPath || - fType == kTransformedMask || + return fType == kTransformedMask || fType == kTransformedSDFT; } bool GrAtlasSubRun::needsPadding() const { - return fType == kTransformedPath || fType == kTransformedMask; + return fType == kTransformedMask; } int GrAtlasSubRun::atlasPadding() const { @@ -549,7 +556,7 @@ auto GrAtlasSubRun::vertexData() const -> SkSpan { } bool GrAtlasSubRun::hasW() const { - if (fType == kTransformedSDFT || fType == kTransformedMask || fType == kTransformedPath) { + if (fType == kTransformedSDFT || fType == kTransformedMask) { return fBlob->hasPerspective(); } @@ -597,20 +604,6 @@ void GrAtlasSubRun::setAntiAliased(bool antiAliased) { fAntiAliased = antiAliase bool GrAtlasSubRun::isAntiAliased() const { return fAntiAliased; } const SkStrikeSpec& GrAtlasSubRun::strikeSpec() const { return fStrikeSpec; } -auto GrAtlasSubRun::MakePaths( - const SkZip& drawables, - const SkFont& runFont, - const SkStrikeSpec& strikeSpec, - GrTextBlob* blob, - SkArenaAlloc* alloc) -> GrSubRun* { - GrAtlasSubRun* subRun = alloc->make(blob, strikeSpec); - subRun->setAntiAliased(runFont.hasSomeAntiAliasing()); - for (auto [variant, pos] : drawables) { - subRun->fPaths.emplace_back(*variant.path(), pos); - } - return subRun; -}; - auto GrAtlasSubRun::MakeSDFT( const SkZip& drawables, const SkFont& runFont, @@ -877,7 +870,10 @@ void GrTextBlob::processSourcePaths(const SkZip& drawab const SkFont& runFont, const SkStrikeSpec& strikeSpec) { this->setHasBitmap(); - GrSubRun* subRun = GrAtlasSubRun::MakePaths(drawables, runFont, strikeSpec, this, &fAlloc); + GrSubRun* subRun = GrPathSubRun::MakePaths(drawables, + runFont.hasSomeAntiAliasing(), + strikeSpec, + &fAlloc); this->insertSubRun(subRun); } diff --git a/src/gpu/text/GrTextBlob.h b/src/gpu/text/GrTextBlob.h index 17537094d4..ba1bcd8a64 100644 --- a/src/gpu/text/GrTextBlob.h +++ b/src/gpu/text/GrTextBlob.h @@ -72,14 +72,6 @@ public: bool operator==(const Key& other) const; }; - // Any glyphs that can't be rendered with the base or override descriptor - // are rendered as paths - struct PathGlyph { - PathGlyph(const SkPath& path, SkPoint origin); - SkPath fPath; - SkPoint fOrigin; - }; - SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrTextBlob); // Change memory management to handle the data after GrTextBlob, but in the same allocation @@ -200,6 +192,34 @@ public: private: SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrSubRun); }; +// -- GrPathSubRun --------------------------------------------------------------------------------- +class GrPathSubRun : public GrSubRun { + struct PathGlyph; + +public: + GrPathSubRun(bool isAntiAliased, const SkStrikeSpec& strikeSpec, SkSpan paths); + + void draw(const GrClip* clip, + const SkMatrixProvider& viewMatrix, + const SkGlyphRunList& glyphRunList, + GrRenderTargetContext* rtc) override; + + static GrSubRun* MakePaths(const SkZip& drawables, + bool isAntiAliased, + const SkStrikeSpec& strikeSpec, + SkArenaAlloc* alloc); + +private: + struct PathGlyph { + PathGlyph(const SkPath& path, SkPoint origin); + SkPath fPath; + SkPoint fOrigin; + }; + + const bool fIsAntiAliased; + const SkStrikeSpec fStrikeSpec; + const SkSpan fPaths; +}; // -- GrAtlasSubRun -------------------------------------------------------------------------------- // Hold data to draw the different types of sub run. SubRuns are produced knowing all the @@ -208,7 +228,6 @@ class GrAtlasSubRun : public GrSubRun { enum SubRunType { kDirectMask, kTransformedMask, - kTransformedPath, kTransformedSDFT }; @@ -234,20 +253,12 @@ public: SkRect vertexBounds, const SkSpan& vertexData); - // SubRun for paths - GrAtlasSubRun(GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec); - std::tuple> makeAtlasTextOp(const GrClip* clip, const SkMatrixProvider& viewMatrix, const SkGlyphRunList& glyphRunList, GrRenderTargetContext* rtc); - void drawPaths(const GrClip* clip, - const SkMatrixProvider& viewMatrix, - const SkGlyphRunList& glyphRunList, - GrRenderTargetContext* rtc); - void draw(const GrClip* clip, const SkMatrixProvider& viewMatrix, const SkGlyphRunList& glyphRunList, @@ -277,12 +288,6 @@ public: const SkStrikeSpec& strikeSpec() const; - static GrSubRun* MakePaths(const SkZip& drawables, - const SkFont& runFont, - const SkStrikeSpec& strikeSpec, - GrTextBlob* blob, - SkArenaAlloc* alloc); - static GrSubRun* MakeSDFT(const SkZip& drawables, const SkFont& runFont, const SkStrikeSpec& strikeSpec, @@ -342,8 +347,6 @@ private: bool hasW() const; void setUseLCDText(bool useLCDText); void setAntiAliased(bool antiAliased); - SkSpan paths() const { return SkMakeSpan(fPaths); } - bool drawAsPaths() const; // df properties bool hasUseLCDText() const; @@ -373,7 +376,6 @@ private: // source space. The bounds are the joined rectangles of all the glyphs. const SkRect fVertexBounds; const SkSpan fVertexData; - std::vector fPaths; uint64_t fAtlasGeneration{GrDrawOpAtlas::kInvalidAtlasGeneration}; }; // SubRun