diff options
author | Jim Van Verth <jvanverth@google.com> | 2018-02-06 11:14:20 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-02-06 17:28:16 +0000 |
commit | 2fb7c8aef57e4b94d5215e618d8c3b4cccd35edf (patch) | |
tree | f9d56b011d402a858e3c69717605f6f78cb2693e /src | |
parent | e1ddce57ea78ed1ec1a7297cb9799b5a64aaa937 (diff) |
Cleanup of large text rendering.
* Switch all path glyphs to be rendered as part of the fBigGlyphs
(now fPathGlyphs) system
* Use one flush command for both cached and throwaway blobs
* Store and render path glyphs per run rather than one list for the
entire blob (fixes a layering bug)
* Fix bug with scaled fallback glyphs, where fallback glyphs were
trying to use more than one descriptor
Bug: skia:7562
Change-Id: Ic3d01887e2203a844102a04afe8674a16149b4bb
Reviewed-on: https://skia-review.googlesource.com/102400
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/text/GrAtlasTextBlob.cpp | 253 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextBlob.h | 85 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextContext.cpp | 229 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextContext.h | 13 | ||||
-rw-r--r-- | src/gpu/text/GrTextUtils.cpp | 82 | ||||
-rw-r--r-- | src/gpu/text/GrTextUtils.h | 13 |
6 files changed, 281 insertions, 394 deletions
diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp index 887addd25c..12ad89a62a 100644 --- a/src/gpu/text/GrAtlasTextBlob.cpp +++ b/src/gpu/text/GrAtlasTextBlob.cpp @@ -73,14 +73,22 @@ void GrAtlasTextBlob::appendGlyph(int runIndex, GrAtlasTextStrike* strike, GrGlyph* glyph, SkGlyphCache* cache, const SkGlyph& skGlyph, - SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP) { + SkScalar x, SkScalar y, SkScalar scale, bool preTransformed) { if (positions.isEmpty()) { return; } // If the glyph is too large we fall back to paths if (glyph->fTooLargeForAtlas) { - this->appendBigGlyph(glyph, cache, skGlyph, x, y, scale, treatAsBMP); + if (nullptr == glyph->fPath) { + const SkPath* glyphPath = cache->findPath(skGlyph); + if (!glyphPath) { + return; + } + + glyph->fPath = new SkPath(*glyphPath); + } + this->appendPathGlyph(runIndex, *glyph->fPath, x, y, scale, preTransformed); return; } @@ -140,17 +148,10 @@ void GrAtlasTextBlob::appendGlyph(int runIndex, subRun->glyphAppended(); } -void GrAtlasTextBlob::appendBigGlyph(GrGlyph* glyph, SkGlyphCache* cache, const SkGlyph& skGlyph, - SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP) { - if (nullptr == glyph->fPath) { - const SkPath* glyphPath = cache->findPath(skGlyph); - if (!glyphPath) { - return; - } - - glyph->fPath = new SkPath(*glyphPath); - } - fBigGlyphs.push_back(GrAtlasTextBlob::BigGlyph(*glyph->fPath, x, y, scale, treatAsBMP)); +void GrAtlasTextBlob::appendPathGlyph(int runIndex, const SkPath& path, SkScalar x, SkScalar y, + SkScalar scale, bool preTransformed) { + Run& run = fRuns[runIndex]; + run.fPathGlyphs.push_back(GrAtlasTextBlob::Run::PathGlyph(path, x, y, scale, preTransformed)); } bool GrAtlasTextBlob::mustRegenerate(const GrTextUtils::Paint& paint, @@ -273,62 +274,6 @@ inline std::unique_ptr<GrAtlasTextOp> GrAtlasTextBlob::makeOp( return op; } -inline void GrAtlasTextBlob::flushRun(GrTextUtils::Target* target, const GrClip& clip, int run, - const SkMatrix& viewMatrix, SkScalar x, SkScalar y, - const GrTextUtils::Paint& paint, const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - GrAtlasGlyphCache* cache) { - // GrAtlasTextBlob::makeOp only takes uint16_t values for run and subRun indices. - // Encountering something larger than this is highly unlikely, so we'll just not draw it. - if (run >= (1 << 16)) { - return; - } - int lastRun = SkTMin(fRuns[run].fSubRunInfo.count(), 1 << 16) - 1; - for (int subRun = 0; subRun <= lastRun; subRun++) { - const Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun]; - int glyphCount = info.glyphCount(); - if (0 == glyphCount) { - continue; - } - - bool skipClip = false; - bool submitOp = true; - SkIRect clipRect = SkIRect::MakeEmpty(); - SkRect rtBounds = SkRect::MakeWH(target->width(), target->height()); - SkRRect clipRRect; - GrAA aa; - // We can clip geometrically if we're not using SDFs, - // and we have an axis-aligned rectangular non-AA clip - if (!info.drawAsDistanceFields() && clip.isRRect(rtBounds, &clipRRect, &aa) && - clipRRect.isRect() && GrAA::kNo == aa) { - skipClip = true; - // We only need to do clipping work if the subrun isn't contained by the clip - SkRect subRunBounds; - this->computeSubRunBounds(&subRunBounds, run, subRun, viewMatrix, x, y); - if (!clipRRect.getBounds().contains(subRunBounds)) { - // If the subrun is completely outside, don't add an op for it - if (!clipRRect.getBounds().intersects(subRunBounds)) { - submitOp = false; - } else { - clipRRect.getBounds().round(&clipRect); - } - } - } - - if (submitOp) { - auto op = this->makeOp(info, glyphCount, run, subRun, viewMatrix, x, y, clipRect, - std::move(paint), props, distanceAdjustTable, cache, target); - if (op) { - if (skipClip) { - target->addDrawOp(GrNoClip(), std::move(op)); - } else { - target->addDrawOp(clip, std::move(op)); - } - } - } - } -} - static void calculate_translation(bool applyVM, const SkMatrix& newViewMatrix, SkScalar newX, SkScalar newY, const SkMatrix& currentViewMatrix, SkScalar currentX, @@ -349,94 +294,81 @@ static void calculate_translation(bool applyVM, } } -void GrAtlasTextBlob::flushBigGlyphs(GrTextUtils::Target* target, - const GrClip& clip, const SkPaint& paint, - const SkMatrix& viewMatrix, SkScalar x, SkScalar y, - const SkIRect& clipBounds) { - SkScalar transX, transY; - for (int i = 0; i < fBigGlyphs.count(); i++) { - GrAtlasTextBlob::BigGlyph& bigGlyph = fBigGlyphs[i]; - calculate_translation(bigGlyph.fTreatAsBMP, viewMatrix, x, y, - fInitialViewMatrix, fInitialX, fInitialY, &transX, &transY); - SkMatrix ctm; - ctm.setScale(bigGlyph.fScale, bigGlyph.fScale); - ctm.postTranslate(bigGlyph.fX + transX, bigGlyph.fY + transY); - if (!bigGlyph.fTreatAsBMP) { - ctm.postConcat(viewMatrix); - } - target->drawPath(clip, bigGlyph.fPath, paint, ctm, nullptr, clipBounds); - } -} - -void GrAtlasTextBlob::flushBigRun(GrTextUtils::Target* target, - const SkSurfaceProps& props, const SkTextBlobRunIterator& it, - const GrClip& clip, const GrTextUtils::Paint& paint, - SkDrawFilter* drawFilter, const SkMatrix& viewMatrix, - const SkIRect& clipBounds, SkScalar x, SkScalar y) { - size_t textLen = it.glyphCount() * sizeof(uint16_t); - const SkPoint& offset = it.offset(); +void GrAtlasTextBlob::flush(GrAtlasGlyphCache* atlasGlyphCache, GrTextUtils::Target* target, + const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + const GrTextUtils::Paint& paint, const GrClip& clip, + const SkMatrix& viewMatrix, const SkIRect& clipBounds, + SkScalar x, SkScalar y) { - GrTextUtils::RunPaint runPaint(&paint, drawFilter, props); - if (!runPaint.modifyForRun(it)) { - return; - } + // GrAtlasTextBlob::makeOp only takes uint16_t values for run and subRun indices. + // Encountering something larger than this is highly unlikely, so we'll just not draw it. + int lastRun = SkTMin(fRunCount, (1 << 16)) - 1; + for (int runIndex = 0; runIndex <= lastRun; runIndex++) { + Run& run = fRuns[runIndex]; + + // first flush each subrun + int lastSubRun = SkTMin(run.fSubRunInfo.count(), 1 << 16) - 1; + for (int subRun = 0; subRun <= lastSubRun; subRun++) { + const Run::SubRunInfo& info = run.fSubRunInfo[subRun]; + int glyphCount = info.glyphCount(); + if (0 == glyphCount) { + continue; + } - switch (it.positioning()) { - case SkTextBlob::kDefault_Positioning: - GrTextUtils::DrawBigText(target, clip, runPaint, viewMatrix, - (const char*)it.glyphs(), textLen, x + offset.x(), - y + offset.y(), clipBounds); - break; - case SkTextBlob::kHorizontal_Positioning: - GrTextUtils::DrawBigPosText(target, props, clip, runPaint, viewMatrix, - (const char*)it.glyphs(), textLen, it.pos(), 1, - SkPoint::Make(x, y + offset.y()), clipBounds); - break; - case SkTextBlob::kFull_Positioning: - GrTextUtils::DrawBigPosText(target, props, clip, runPaint, viewMatrix, - (const char*)it.glyphs(), textLen, it.pos(), 2, - SkPoint::Make(x, y), clipBounds); - break; - } -} + bool skipClip = false; + bool submitOp = true; + SkIRect clipRect = SkIRect::MakeEmpty(); + SkRect rtBounds = SkRect::MakeWH(target->width(), target->height()); + SkRRect clipRRect; + GrAA aa; + // We can clip geometrically if we're not using SDFs, + // and we have an axis-aligned rectangular non-AA clip + if (!info.drawAsDistanceFields() && clip.isRRect(rtBounds, &clipRRect, &aa) && + clipRRect.isRect() && GrAA::kNo == aa) { + skipClip = true; + // We only need to do clipping work if the subrun isn't contained by the clip + SkRect subRunBounds; + this->computeSubRunBounds(&subRunBounds, runIndex, subRun, viewMatrix, x, y); + if (!clipRRect.getBounds().contains(subRunBounds)) { + // If the subrun is completely outside, don't add an op for it + if (!clipRRect.getBounds().intersects(subRunBounds)) { + submitOp = false; + } + else { + clipRRect.getBounds().round(&clipRect); + } + } + } -void GrAtlasTextBlob::flushCached(GrAtlasGlyphCache* atlasGlyphCache, GrTextUtils::Target* target, - const SkTextBlob* blob, const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - const GrTextUtils::Paint& paint, SkDrawFilter* drawFilter, - const GrClip& clip, const SkMatrix& viewMatrix, - const SkIRect& clipBounds, SkScalar x, SkScalar y) { - // We loop through the runs of the blob, flushing each. If any run is too large, then we flush - // it as paths - SkTextBlobRunIterator it(blob); - for (int run = 0; !it.done(); it.next(), run++) { - if (fRuns[run].fTooBigForAtlas) { - this->flushBigRun(target, props, it, clip, paint, drawFilter, viewMatrix, - clipBounds, x, y); - continue; + if (submitOp) { + auto op = this->makeOp(info, glyphCount, runIndex, subRun, viewMatrix, x, y, + clipRect, std::move(paint), props, distanceAdjustTable, + atlasGlyphCache, target); + if (op) { + if (skipClip) { + target->addDrawOp(GrNoClip(), std::move(op)); + } + else { + target->addDrawOp(clip, std::move(op)); + } + } + } } - this->flushRun(target, clip, run, viewMatrix, x, y, paint, props, distanceAdjustTable, - atlasGlyphCache); - } - - // Now flush big glyphs - this->flushBigGlyphs(target, clip, paint, viewMatrix, x, y, clipBounds); -} -void GrAtlasTextBlob::flushThrowaway(GrAtlasGlyphCache* atlasGlyphCache, - GrTextUtils::Target* target, - const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - const GrTextUtils::Paint& paint, const GrClip& clip, - const SkMatrix& viewMatrix, const SkIRect& clipBounds, - SkScalar x, SkScalar y) { - for (int run = 0; run < fRunCount; run++) { - this->flushRun(target, clip, run, viewMatrix, x, y, paint, props, distanceAdjustTable, - atlasGlyphCache); + // now flush any path glyphs + SkScalar transX, transY; + for (int i = 0; i < run.fPathGlyphs.count(); i++) { + GrAtlasTextBlob::Run::PathGlyph& pathGlyph = run.fPathGlyphs[i]; + calculate_translation(pathGlyph.fPreTransformed, viewMatrix, x, y, + fInitialViewMatrix, fInitialX, fInitialY, &transX, &transY); + const SkMatrix& ctm = pathGlyph.fPreTransformed ? SkMatrix::I() : viewMatrix; + SkMatrix pathMatrix; + pathMatrix.setScale(pathGlyph.fScale, pathGlyph.fScale); + pathMatrix.postTranslate(pathGlyph.fX + transX, pathGlyph.fY + transY); + target->drawPath(clip, pathGlyph.fPath, paint, ctm, &pathMatrix, clipBounds); + } } - - // Now flush big glyphs - this->flushBigGlyphs(target, clip, paint, viewMatrix, x, y, clipBounds); } std::unique_ptr<GrDrawOp> GrAtlasTextBlob::test_makeOp( @@ -462,15 +394,6 @@ void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlo SkASSERT_RELEASE(l.fStrokeInfo.fMiterLimit == r.fStrokeInfo.fMiterLimit); SkASSERT_RELEASE(l.fStrokeInfo.fJoin == r.fStrokeInfo.fJoin); - SkASSERT_RELEASE(l.fBigGlyphs.count() == r.fBigGlyphs.count()); - for (int i = 0; i < l.fBigGlyphs.count(); i++) { - const BigGlyph& lBigGlyph = l.fBigGlyphs[i]; - const BigGlyph& rBigGlyph = r.fBigGlyphs[i]; - - SkASSERT_RELEASE(lBigGlyph.fPath == rBigGlyph.fPath); - // We can't assert that these have the same translations - } - SkASSERT_RELEASE(l.fKey == r.fKey); //SkASSERT_RELEASE(l.fPaintColor == r.fPaintColor); // Colors might not actually be identical SkASSERT_RELEASE(l.fMaxMinScale == r.fMaxMinScale); @@ -506,7 +429,6 @@ void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlo // color can be changed //SkASSERT(lRun.fColor == rRun.fColor); SkASSERT_RELEASE(lRun.fInitialized == rRun.fInitialized); - SkASSERT_RELEASE(lRun.fTooBigForAtlas == rRun.fTooBigForAtlas); SkASSERT_RELEASE(lRun.fSubRunInfo.count() == rRun.fSubRunInfo.count()); for(int j = 0; j < lRun.fSubRunInfo.count(); j++) { @@ -533,6 +455,15 @@ void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlo SkASSERT_RELEASE(lSubRun.drawAsDistanceFields() == rSubRun.drawAsDistanceFields()); SkASSERT_RELEASE(lSubRun.hasUseLCDText() == rSubRun.hasUseLCDText()); } + + SkASSERT_RELEASE(lRun.fPathGlyphs.count() == rRun.fPathGlyphs.count()); + for (int i = 0; i < lRun.fPathGlyphs.count(); i++) { + const Run::PathGlyph& lPathGlyph = lRun.fPathGlyphs[i]; + const Run::PathGlyph& rPathGlyph = rRun.fPathGlyphs[i]; + + SkASSERT_RELEASE(lPathGlyph.fPath == rPathGlyph.fPath); + // We can't assert that these have the same translations + } } } diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h index 12a80c49d3..a75d9f2a38 100644 --- a/src/gpu/text/GrAtlasTextBlob.h +++ b/src/gpu/text/GrAtlasTextBlob.h @@ -142,10 +142,6 @@ public: subRun.setHasWCoord(hasWCoord); } - void setRunTooBigForAtlas(int runIndex) { - fRuns[runIndex].fTooBigForAtlas = true; - } - void setMinAndMaxScale(SkScalar scaledMax, SkScalar scaledMin) { // we init fMaxMinScale and fMinMaxScale in the constructor fMaxMinScale = SkMaxScalar(scaledMax, fMaxMinScale); @@ -175,7 +171,11 @@ public: GrAtlasTextStrike* strike, GrGlyph* glyph, SkGlyphCache*, const SkGlyph& skGlyph, - SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP); + SkScalar x, SkScalar y, SkScalar scale, bool preTransformed); + + // Appends a glyph to the blob as a path only. + void appendPathGlyph(int runIndex, const SkPath& path, + SkScalar x, SkScalar y, SkScalar scale, bool preTransformed); static size_t GetVertexStride(GrMaskFormat maskFormat, bool isDistanceFieldWithWCoord) { switch (maskFormat) { @@ -193,19 +193,11 @@ public: bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilterBase::BlurRec& blurRec, const SkMatrix& viewMatrix, SkScalar x, SkScalar y); - // flush a GrAtlasTextBlob associated with a SkTextBlob - void flushCached(GrAtlasGlyphCache*, GrTextUtils::Target*, const SkTextBlob* blob, - const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - const GrTextUtils::Paint&, SkDrawFilter* drawFilter, const GrClip& clip, - const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y); - - // flush a throwaway GrAtlasTextBlob *not* associated with an SkTextBlob - void flushThrowaway(GrAtlasGlyphCache*, GrTextUtils::Target*, const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - const GrTextUtils::Paint& paint, const GrClip& clip, - const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, - SkScalar y); + void flush(GrAtlasGlyphCache*, GrTextUtils::Target*, const SkSurfaceProps& props, + const GrDistanceFieldAdjustTable* distanceAdjustTable, + const GrTextUtils::Paint& paint, const GrClip& clip, + const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, + SkScalar y); void computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex, const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { @@ -285,24 +277,6 @@ private: , fMinMaxScale(SK_ScalarMax) , fTextType(0) {} - void appendBigGlyph(GrGlyph* glyph, SkGlyphCache* cache, const SkGlyph& skGlyph, - SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP); - - inline void flushRun(GrTextUtils::Target*, const GrClip&, int run, const SkMatrix& viewMatrix, - SkScalar x, SkScalar y, const GrTextUtils::Paint& paint, - const SkSurfaceProps& props, - const GrDistanceFieldAdjustTable* distanceAdjustTable, - GrAtlasGlyphCache* cache); - - void flushBigGlyphs(GrTextUtils::Target*, const GrClip& clip, - const SkPaint& paint, const SkMatrix& viewMatrix, SkScalar x, SkScalar y, - const SkIRect& clipBounds); - - void flushBigRun(GrTextUtils::Target*, const SkSurfaceProps& props, - const SkTextBlobRunIterator& it, const GrClip& clip, - const GrTextUtils::Paint& paint, SkDrawFilter* drawFilter, - const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, - SkScalar y); // This function will only be called when we are generating a blob from scratch. We record the // initial view matrix and initial offsets(x,y), because we record vertex bounds relative to @@ -347,9 +321,7 @@ private: * would greatly increase the memory of these cached items. */ struct Run { - Run() - : fInitialized(false) - , fTooBigForAtlas(false) { + Run() : fInitialized(false) { // To ensure we always have one subrun, we push back a fresh run here fSubRunInfo.push_back(); } @@ -495,8 +467,26 @@ private: // will have different descriptors. If fOverrideDescriptor is non-nullptr, then it // will be used in place of the run's descriptor to regen texture coords std::unique_ptr<SkAutoDescriptor> fOverrideDescriptor; // df properties + + // Any glyphs that can't be rendered with the base or override descriptor + // are rendered as paths + struct PathGlyph { + PathGlyph(const SkPath& path, SkScalar x, SkScalar y, SkScalar scale, bool preXformed) + : fPath(path) + , fX(x) + , fY(y) + , fScale(scale) + , fPreTransformed(preXformed) {} + SkPath fPath; + SkScalar fX; + SkScalar fY; + SkScalar fScale; + bool fPreTransformed; + }; + + SkTArray<PathGlyph> fPathGlyphs; + bool fInitialized; - bool fTooBigForAtlas; }; // Run inline std::unique_ptr<GrAtlasTextOp> makeOp( @@ -506,20 +496,6 @@ private: const GrDistanceFieldAdjustTable* distanceAdjustTable, GrAtlasGlyphCache* cache, GrTextUtils::Target*); - struct BigGlyph { - BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy, SkScalar scale, bool treatAsBMP) - : fPath(path) - , fScale(scale) - , fX(vx) - , fY(vy) - , fTreatAsBMP(treatAsBMP) {} - SkPath fPath; - SkScalar fScale; - SkScalar fX; - SkScalar fY; - bool fTreatAsBMP; - }; - struct StrokeInfo { SkScalar fFrameWidth; SkScalar fMiterLimit; @@ -538,7 +514,6 @@ private: GrMemoryPool* fPool; SkMaskFilterBase::BlurRec fBlurRec; StrokeInfo fStrokeInfo; - SkTArray<BigGlyph> fBigGlyphs; Key fKey; SkMatrix fInitialViewMatrix; SkMatrix fInitialViewMatrixInverse; diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp index 1dce4e0d44..3155153289 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -11,11 +11,15 @@ #include "SkDistanceFieldGen.h" #include "SkDraw.h" #include "SkDrawFilter.h" +#include "SkDrawProcs.h" #include "SkFindAndPlaceGlyph.h" #include "SkGr.h" #include "SkGraphics.h" #include "SkMakeUnique.h" #include "SkMaskFilterBase.h" +#include "SkTextMapStateProc.h" +#include "SkTextToPathIter.h" + #include "ops/GrMeshDrawOp.h" // DF sizes and thresholds for usage of the small and medium sizes. For example, above @@ -49,15 +53,6 @@ std::unique_ptr<GrAtlasTextContext> GrAtlasTextContext::Make(const Options& opti return std::unique_ptr<GrAtlasTextContext>(new GrAtlasTextContext(options)); } -bool GrAtlasTextContext::canDraw(const GrAtlasGlyphCache* fontCache, - const SkPaint& skPaint, - const SkMatrix& viewMatrix, - const SkSurfaceProps& props, - const GrShaderCaps& shaderCaps) { - return this->canDrawAsDistanceFields(skPaint, viewMatrix, props, shaderCaps) || - !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix, fontCache->getGlyphSizeLimit()); -} - SkColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd) { SkColor canonicalColor = paint.computeLuminanceColor(); if (lcd) { @@ -186,8 +181,8 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t viewMatrix, props, blob, x, y, drawFilter); } - cacheBlob->flushCached(atlasGlyphCache, target, blob, props, fDistanceAdjustTable.get(), paint, - drawFilter, clip, viewMatrix, clipBounds, x, y); + cacheBlob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, + clip, viewMatrix, clipBounds, x, y); } void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, @@ -235,8 +230,6 @@ void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, break; } } - } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { - cacheBlob->setRunTooBigForAtlas(run); } else { switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: @@ -328,23 +321,15 @@ void GrAtlasTextContext::drawText(GrContext* context, GrTextUtils::Target* targe auto textBlobCache = context->contextPriv().getTextBlobCache(); GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo()); - if (this->canDraw(atlasGlyphCache, skPaint, viewMatrix, props, - *context->caps()->shaderCaps())) { - sk_sp<GrAtlasTextBlob> blob( - this->makeDrawTextBlob(textBlobCache, atlasGlyphCache, - *context->caps()->shaderCaps(), paint, - ComputeScalerContextFlags(target->colorSpaceInfo()), - viewMatrix, props, text, byteLength, x, y)); - if (blob) { - blob->flushThrowaway(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, - clip, viewMatrix, regionClipBounds, x, y); - } - return; + sk_sp<GrAtlasTextBlob> blob( + this->makeDrawTextBlob(textBlobCache, atlasGlyphCache, + *context->caps()->shaderCaps(), paint, + ComputeScalerContextFlags(target->colorSpaceInfo()), + viewMatrix, props, text, byteLength, x, y)); + if (blob) { + blob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, + clip, viewMatrix, regionClipBounds, x, y); } - - // fall back to drawing as a path or scaled glyph - GrTextUtils::DrawBigText(target, clip, paint, viewMatrix, text, byteLength, x, y, - regionClipBounds); } void GrAtlasTextContext::drawPosText(GrContext* context, GrTextUtils::Target* target, @@ -361,23 +346,15 @@ void GrAtlasTextContext::drawPosText(GrContext* context, GrTextUtils::Target* ta auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache(); auto textBlobCache = context->contextPriv().getTextBlobCache(); - if (this->canDraw(atlasGlyphCache, skPaint, viewMatrix, props, - *context->caps()->shaderCaps())) { - sk_sp<GrAtlasTextBlob> blob(this->makeDrawPosTextBlob( - textBlobCache, atlasGlyphCache, - *context->caps()->shaderCaps(), paint, - ComputeScalerContextFlags(target->colorSpaceInfo()), viewMatrix, props, text, - byteLength, pos, scalarsPerPosition, offset)); - if (blob) { - blob->flushThrowaway(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, - clip, viewMatrix, regionClipBounds, offset.fX, offset.fY); - } - return; + sk_sp<GrAtlasTextBlob> blob(this->makeDrawPosTextBlob( + textBlobCache, atlasGlyphCache, + *context->caps()->shaderCaps(), paint, + ComputeScalerContextFlags(target->colorSpaceInfo()), viewMatrix, props, text, + byteLength, pos, scalarsPerPosition, offset)); + if (blob) { + blob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, + clip, viewMatrix, regionClipBounds, offset.fX, offset.fY); } - - // fall back to drawing as a path or scaled glyph - GrTextUtils::DrawBigPosText(target, props, clip, paint, viewMatrix, text, - byteLength, pos, scalarsPerPosition, offset, regionClipBounds); } void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, @@ -396,8 +373,11 @@ void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, // Ensure the blob is set for bitmaptext blob->setHasBitmap(); + if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) { + DrawBmpTextAsPaths(blob, runIndex, paint, text, byteLength, x, y); + return; + } GrAtlasTextStrike* currStrike = nullptr; - SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix); SkFindAndPlaceGlyph::ProcessText(paint.skPaint().getTextEncoding(), text, byteLength, {x, y}, viewMatrix, paint.skPaint().getTextAlign(), cache, @@ -432,10 +412,15 @@ void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, // Ensure the blob is set for bitmaptext blob->setHasBitmap(); + if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) { + DrawBmpPosTextAsPaths(blob, runIndex, props, paint, text, byteLength, + pos, scalarsPerPosition, offset, textRatio); + return; + } + GrAtlasTextStrike* currStrike = nullptr; SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix); - SkFindAndPlaceGlyph::ProcessPosText( paint.skPaint().getTextEncoding(), text, byteLength, offset, viewMatrix, pos, scalarsPerPosition, paint.skPaint().getTextAlign(), cache, @@ -450,6 +435,77 @@ void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, SkGlyphCache::AttachCache(cache); } +void GrAtlasTextContext::DrawBmpTextAsPaths(GrAtlasTextBlob* blob, int runIndex, + const GrTextUtils::Paint& origPaint, const char text[], + size_t byteLength, SkScalar x, SkScalar y) { + // nothing to draw + if (text == nullptr || byteLength == 0) { + return; + } + + // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. + SkPaint paint(origPaint); + paint.setStyle(SkPaint::kFill_Style); + paint.setPathEffect(nullptr); + + SkTextToPathIter iter(text, byteLength, paint, true); + const SkPath* iterPath; + SkScalar xpos = 0; + while (iter.next(&iterPath, &xpos)) { + if (iterPath) { + blob->appendPathGlyph(runIndex, *iterPath, xpos + x, y, iter.getPathScale(), false); + } + } +} + +void GrAtlasTextContext::DrawBmpPosTextAsPaths(GrAtlasTextBlob* blob, int runIndex, + const SkSurfaceProps& props, + const GrTextUtils::Paint& origPaint, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset, SkScalar textRatio) { + SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); + + // nothing to draw + if (text == nullptr || byteLength == 0) { + return; + } + + // setup our std paint, in hopes of getting hits in the cache + SkPaint paint(origPaint); + SkScalar matrixScale = paint.setupForAsPaths(); + matrixScale *= textRatio; + + // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. + paint.setStyle(SkPaint::kFill_Style); + paint.setPathEffect(nullptr); + + SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), + paint.isDevKernText(), + true); + SkAutoGlyphCache autoCache(paint, &props, nullptr); + SkGlyphCache* cache = autoCache.getCache(); + + const char* stop = text + byteLength; + SkTextAlignProc alignProc(paint.getTextAlign()); + SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); + + while (text < stop) { + const SkGlyph& glyph = glyphCacheProc(cache, &text); + if (glyph.fWidth) { + const SkPath* path = cache->findPath(glyph); + if (path) { + SkPoint tmsLoc; + tmsProc(pos, &tmsLoc); + SkPoint loc; + alignProc(tmsLoc, glyph, &loc); + blob->appendPathGlyph(runIndex, *path, loc.fX, loc.fY, matrixScale, false); + } + } + pos += scalarsPerPosition; + } +} + void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphCache* fontCache, GrAtlasTextStrike** strike, const SkGlyph& skGlyph, SkScalar sx, SkScalar sy, @@ -467,6 +523,7 @@ void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, if (!glyph) { return; } + glyph->fTooLargeForAtlas = glyph->fTooLargeForAtlas; SkASSERT(skGlyph.fWidth == glyph->width()); SkASSERT(skGlyph.fHeight == glyph->height()); @@ -675,11 +732,10 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkTDArray<char> fallbackTxt; SkTDArray<SkScalar> fallbackPos; - SkTDArray<char> bigFallbackTxt; - SkTDArray<SkScalar> bigFallbackPos; + bool useScaledFallback = false; SkScalar textSize = paint.skPaint().getTextSize(); SkScalar maxTextSize = fontCache->getGlyphSizeLimit(); - SkScalar bigFallbackTextSize = maxTextSize; + SkScalar scaledFallbackTextSize = maxTextSize; SkScalar maxScale = viewMatrix.getMaxScale(); bool hasWCoord = viewMatrix.hasPerspective() || fDistanceFieldVerticesAlwaysHaveW; @@ -723,19 +779,30 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, y - advanceY, paint.filteredPremulColor(), cache, textRatio); } else { // can't append color glyph to SDF batch, send to fallback + + // all fallback glyphs need to use the same descriptor, so once + // we have to scale one, we have to scale all of them SkScalar maxDim = SkTMax(glyph.fWidth, glyph.fHeight)*textRatio; - SkScalar scaledGlyphSize = maxDim*maxScale; + if (!useScaledFallback) { + SkScalar scaledGlyphSize = maxDim * maxScale; + if (!viewMatrix.hasPerspective() && scaledGlyphSize > maxTextSize) { + useScaledFallback = true; + // rescale previous glyph positions to match text scale + for (int i = 0; i < fallbackPos.count(); ++i) { + fallbackPos[i] *= maxScale; + } + } + } - if (!viewMatrix.hasPerspective() && scaledGlyphSize > maxTextSize) { - bigFallbackTxt.append(SkToInt(text - lastText), lastText); - *bigFallbackPos.append() = maxScale*pos[0]; + fallbackTxt.append(SkToInt(text - lastText), lastText); + if (useScaledFallback) { + *fallbackPos.append() = maxScale*pos[0]; if (2 == scalarsPerPosition) { - *bigFallbackPos.append() = maxScale*pos[1]; + *fallbackPos.append() = maxScale*pos[1]; } SkScalar glyphTextSize = SkScalarFloorToScalar(maxTextSize*textSize/maxDim); - bigFallbackTextSize = SkTMin(glyphTextSize, bigFallbackTextSize); + scaledFallbackTextSize = SkTMin(glyphTextSize, scaledFallbackTextSize); } else { - fallbackTxt.append(SkToInt(text - lastText), lastText); *fallbackPos.append() = pos[0]; if (2 == scalarsPerPosition) { *fallbackPos.append() = pos[1]; @@ -747,33 +814,35 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, } SkGlyphCache::AttachCache(cache); + if (fallbackTxt.count()) { blob->initOverride(runIndex); - GrAtlasTextContext::DrawBmpPosText(blob, runIndex, fontCache, props, paint, - scalerContextFlags, viewMatrix, fallbackTxt.begin(), - fallbackTxt.count(), fallbackPos.begin(), - scalarsPerPosition, offset, SK_Scalar1); + if (useScaledFallback) { + // Set up paint and matrix to scale glyphs + SkPaint scaledPaint(paint); + scaledPaint.setTextSize(scaledFallbackTextSize); + // remove maxScale from viewMatrix and move it into textRatio + // this keeps the base glyph size consistent regardless of matrix scale + SkMatrix modMatrix(viewMatrix); + SkScalar invScale = SkScalarInvert(maxScale); + modMatrix.preScale(invScale, invScale); + SkScalar scaledFallbackTextRatio = textSize * maxScale / scaledFallbackTextSize; + SkPoint modOffset(offset); + modOffset *= maxScale; + GrTextUtils::Paint textPaint(&scaledPaint, paint.dstColorSpaceInfo()); + GrAtlasTextContext::DrawBmpPosText(blob, runIndex, fontCache, props, textPaint, + scalerContextFlags, modMatrix, fallbackTxt.begin(), + fallbackTxt.count(), fallbackPos.begin(), + scalarsPerPosition, modOffset, + scaledFallbackTextRatio); + } else { + GrAtlasTextContext::DrawBmpPosText(blob, runIndex, fontCache, props, paint, + scalerContextFlags, viewMatrix, fallbackTxt.begin(), + fallbackTxt.count(), fallbackPos.begin(), + scalarsPerPosition, offset, SK_Scalar1); + } } - if (bigFallbackTxt.count()) { - // Set up paint and matrix to scale glyphs - blob->initOverride(runIndex); - SkPaint largePaint(paint); - largePaint.setTextSize(bigFallbackTextSize); - // remove maxScale from viewMatrix and move it into textRatio - // this keeps the base glyph size consistent regardless of matrix scale - SkMatrix modMatrix(viewMatrix); - SkScalar invScale = SkScalarInvert(maxScale); - modMatrix.preScale(invScale, invScale); - SkScalar bigFallbackTextRatio = textSize*maxScale/bigFallbackTextSize; - SkPoint modOffset(offset); - modOffset *= maxScale; - GrTextUtils::Paint textPaint(&largePaint, paint.dstColorSpaceInfo()); - GrAtlasTextContext::DrawBmpPosText(blob, runIndex, fontCache, props, textPaint, - scalerContextFlags, modMatrix, bigFallbackTxt.begin(), - bigFallbackTxt.count(), bigFallbackPos.begin(), - scalarsPerPosition, modOffset, bigFallbackTextRatio); - } } // TODO: merge with BmpAppendGlyph diff --git a/src/gpu/text/GrAtlasTextContext.h b/src/gpu/text/GrAtlasTextContext.h index 36e83c4574..360f6ddbec 100644 --- a/src/gpu/text/GrAtlasTextContext.h +++ b/src/gpu/text/GrAtlasTextContext.h @@ -44,9 +44,6 @@ public: static std::unique_ptr<GrAtlasTextContext> Make(const Options& options); - bool canDraw(const GrAtlasGlyphCache* fontCache, const SkPaint&, const SkMatrix& viewMatrix, - const SkSurfaceProps&, const GrShaderCaps&); - void drawText(GrContext*, GrTextUtils::Target*, const GrClip&, const SkPaint&, const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds); @@ -110,6 +107,16 @@ private: int scalarsPerPosition, const SkPoint& offset, SkScalar textRatio); + static void DrawBmpTextAsPaths(GrAtlasTextBlob* blob, int runIndex, + const GrTextUtils::Paint& paint, const char text[], + size_t byteLength, SkScalar x, SkScalar y); + + static void DrawBmpPosTextAsPaths(GrAtlasTextBlob*, int runIndex, + const SkSurfaceProps& props, const GrTextUtils::Paint& paint, + const char text[], size_t byteLength, + const SkScalar pos[], int scalarsPerPosition, + const SkPoint& offset, SkScalar textRatio); + // functions for appending distance field text bool canDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const GrShaderCaps& caps) const; diff --git a/src/gpu/text/GrTextUtils.cpp b/src/gpu/text/GrTextUtils.cpp index d354619a43..c2a7d1136f 100644 --- a/src/gpu/text/GrTextUtils.cpp +++ b/src/gpu/text/GrTextUtils.cpp @@ -8,13 +8,10 @@ #include "GrTextUtils.h" #include "GrContext.h" #include "SkDrawFilter.h" -#include "SkDrawProcs.h" #include "SkGlyphCache.h" #include "SkGr.h" #include "SkPaint.h" #include "SkTextBlobRunIterator.h" -#include "SkTextMapStateProc.h" -#include "SkTextToPathIter.h" void GrTextUtils::Paint::initFilteredColor() { // This mirrors the logic in skpaint_to_grpaint_impl for handling paint colors @@ -77,82 +74,3 @@ bool GrTextUtils::ShouldDisableLCD(const SkPaint& paint) { return paint.getMaskFilter() || paint.getPathEffect() || paint.isFakeBoldText() || paint.getStyle() != SkPaint::kFill_Style; } - -void GrTextUtils::DrawBigText(GrTextUtils::Target* target, - const GrClip& clip, const SkPaint& paint, - const SkMatrix& viewMatrix, const char text[], size_t byteLength, - SkScalar x, SkScalar y, const SkIRect& clipBounds) { - if (!paint.countText(text, byteLength)) { - return; - } - SkTextToPathIter iter(text, byteLength, paint, true); - - SkMatrix matrix; - matrix.setScale(iter.getPathScale(), iter.getPathScale()); - matrix.postTranslate(x, y); - - const SkPath* iterPath; - SkScalar xpos, prevXPos = 0; - - while (iter.next(&iterPath, &xpos)) { - matrix.postTranslate(xpos - prevXPos, 0); - if (iterPath) { - const SkPaint& pnt = iter.getPaint(); - target->drawPath(clip, *iterPath, pnt, viewMatrix, &matrix, clipBounds); - } - prevXPos = xpos; - } -} - -void GrTextUtils::DrawBigPosText(GrTextUtils::Target* target, - const SkSurfaceProps& props, const GrClip& clip, - const SkPaint& origPaint, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, const SkScalar pos[], - int scalarsPerPosition, const SkPoint& offset, - const SkIRect& clipBounds) { - if (!origPaint.countText(text, byteLength)) { - return; - } - // setup our std paint, in hopes of getting hits in the cache - SkPaint paint(origPaint); - SkScalar matrixScale = paint.setupForAsPaths(); - - SkMatrix matrix; - matrix.setScale(matrixScale, matrixScale); - - // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. - paint.setStyle(SkPaint::kFill_Style); - paint.setPathEffect(nullptr); - - SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), - paint.isDevKernText(), - true); - SkAutoGlyphCache autoCache(paint, &props, nullptr); - SkGlyphCache* cache = autoCache.getCache(); - - const char* stop = text + byteLength; - SkTextAlignProc alignProc(paint.getTextAlign()); - SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); - - // Now restore the original settings, so we "draw" with whatever style/stroking. - paint.setStyle(origPaint.getStyle()); - paint.setPathEffect(origPaint.refPathEffect()); - - while (text < stop) { - const SkGlyph& glyph = glyphCacheProc(cache, &text); - if (glyph.fWidth) { - const SkPath* path = cache->findPath(glyph); - if (path) { - SkPoint tmsLoc; - tmsProc(pos, &tmsLoc); - SkPoint loc; - alignProc(tmsLoc, glyph, &loc); - - matrix[SkMatrix::kMTransX] = loc.fX; - matrix[SkMatrix::kMTransY] = loc.fY; - target->drawPath(clip, *path, paint, viewMatrix, &matrix, clipBounds); - } - } - pos += scalarsPerPosition; - } -} diff --git a/src/gpu/text/GrTextUtils.h b/src/gpu/text/GrTextUtils.h index 252cd7c626..1301b8457b 100644 --- a/src/gpu/text/GrTextUtils.h +++ b/src/gpu/text/GrTextUtils.h @@ -127,19 +127,6 @@ public: static uint32_t FilterTextFlags(const SkSurfaceProps& surfaceProps, const SkPaint& paint); static bool ShouldDisableLCD(const SkPaint& paint); - - // Functions for drawing large text either as paths or (for color emoji) as scaled glyphs - static void DrawBigText(GrTextUtils::Target*, const GrClip& clip, - const SkPaint& paint, const SkMatrix& viewMatrix, const char text[], - size_t byteLength, SkScalar x, SkScalar y, - const SkIRect& clipBounds); - - static void DrawBigPosText(GrTextUtils::Target*, - const SkSurfaceProps& props, const GrClip& clip, - const SkPaint& paint, const SkMatrix& viewMatrix, - const char text[], size_t byteLength, const SkScalar pos[], - int scalarsPerPosition, const SkPoint& offset, - const SkIRect& clipBounds); }; #endif |