diff options
author | Jim Van Verth <jvanverth@google.com> | 2018-02-06 21:30:20 +0000 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-02-06 21:30:26 +0000 |
commit | 89737decb4965ec250f02af432884366945d2e53 (patch) | |
tree | 0fc0febed63db177d8643239d4728f9446306916 /src | |
parent | 74416048652002955302cf7bb62c9e01f281efee (diff) |
Revert "Cleanup of large text rendering."
This reverts commit 2fb7c8aef57e4b94d5215e618d8c3b4cccd35edf.
Reason for revert: Causing flakes and incorrect GMs on ChromeOS.
Original change's description:
> 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>
TBR=jvanverth@google.com,bsalomon@google.com,robertphillips@google.com
Change-Id: I103a7419df96db9859e0f6f4d0a8e5aea4ba8ddc
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:7562
Reviewed-on: https://skia-review.googlesource.com/104640
Reviewed-by: Jim Van Verth <jvanverth@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, 394 insertions, 281 deletions
diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp index 12ad89a62a..887addd25c 100644 --- a/src/gpu/text/GrAtlasTextBlob.cpp +++ b/src/gpu/text/GrAtlasTextBlob.cpp @@ -73,22 +73,14 @@ void GrAtlasTextBlob::appendGlyph(int runIndex, GrAtlasTextStrike* strike, GrGlyph* glyph, SkGlyphCache* cache, const SkGlyph& skGlyph, - SkScalar x, SkScalar y, SkScalar scale, bool preTransformed) { + SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP) { if (positions.isEmpty()) { return; } // If the glyph is too large we fall back to paths if (glyph->fTooLargeForAtlas) { - 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); + this->appendBigGlyph(glyph, cache, skGlyph, x, y, scale, treatAsBMP); return; } @@ -148,10 +140,17 @@ void GrAtlasTextBlob::appendGlyph(int runIndex, subRun->glyphAppended(); } -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)); +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)); } bool GrAtlasTextBlob::mustRegenerate(const GrTextUtils::Paint& paint, @@ -274,6 +273,62 @@ 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, @@ -294,81 +349,94 @@ static void calculate_translation(bool applyVM, } } -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) { +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); + } +} - // 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; - } +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(); - 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); - } - } - } + GrTextUtils::RunPaint runPaint(&paint, drawFilter, props); + if (!runPaint.modifyForRun(it)) { + return; + } - 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)); - } - } - } - } + 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; + } +} - // 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); +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; } + 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 big glyphs + this->flushBigGlyphs(target, clip, paint, viewMatrix, x, y, clipBounds); } std::unique_ptr<GrDrawOp> GrAtlasTextBlob::test_makeOp( @@ -394,6 +462,15 @@ 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); @@ -429,6 +506,7 @@ 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++) { @@ -455,15 +533,6 @@ 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 a75d9f2a38..12a80c49d3 100644 --- a/src/gpu/text/GrAtlasTextBlob.h +++ b/src/gpu/text/GrAtlasTextBlob.h @@ -142,6 +142,10 @@ 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); @@ -171,11 +175,7 @@ public: GrAtlasTextStrike* strike, GrGlyph* glyph, SkGlyphCache*, const SkGlyph& skGlyph, - 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); + SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP); static size_t GetVertexStride(GrMaskFormat maskFormat, bool isDistanceFieldWithWCoord) { switch (maskFormat) { @@ -193,11 +193,19 @@ public: bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilterBase::BlurRec& blurRec, const SkMatrix& viewMatrix, 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); + // 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 computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex, const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { @@ -277,6 +285,24 @@ 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 @@ -321,7 +347,9 @@ private: * would greatly increase the memory of these cached items. */ struct Run { - Run() : fInitialized(false) { + Run() + : fInitialized(false) + , fTooBigForAtlas(false) { // To ensure we always have one subrun, we push back a fresh run here fSubRunInfo.push_back(); } @@ -467,26 +495,8 @@ 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( @@ -496,6 +506,20 @@ 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; @@ -514,6 +538,7 @@ 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 3155153289..1dce4e0d44 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -11,15 +11,11 @@ #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 @@ -53,6 +49,15 @@ 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) { @@ -181,8 +186,8 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t viewMatrix, props, blob, x, y, drawFilter); } - cacheBlob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint, - clip, viewMatrix, clipBounds, x, y); + cacheBlob->flushCached(atlasGlyphCache, target, blob, props, fDistanceAdjustTable.get(), paint, + drawFilter, clip, viewMatrix, clipBounds, x, y); } void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, @@ -230,6 +235,8 @@ void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, break; } } + } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { + cacheBlob->setRunTooBigForAtlas(run); } else { switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: @@ -321,15 +328,23 @@ void GrAtlasTextContext::drawText(GrContext* context, GrTextUtils::Target* targe auto textBlobCache = context->contextPriv().getTextBlobCache(); GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo()); - 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); + 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; } + + // 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, @@ -346,15 +361,23 @@ void GrAtlasTextContext::drawPosText(GrContext* context, GrTextUtils::Target* ta auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache(); auto textBlobCache = context->contextPriv().getTextBlobCache(); - 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); + 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; } + + // 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, @@ -373,11 +396,8 @@ 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, @@ -412,15 +432,10 @@ 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, @@ -435,77 +450,6 @@ 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, @@ -523,7 +467,6 @@ void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, if (!glyph) { return; } - glyph->fTooLargeForAtlas = glyph->fTooLargeForAtlas; SkASSERT(skGlyph.fWidth == glyph->width()); SkASSERT(skGlyph.fHeight == glyph->height()); @@ -732,10 +675,11 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, SkTDArray<char> fallbackTxt; SkTDArray<SkScalar> fallbackPos; - bool useScaledFallback = false; + SkTDArray<char> bigFallbackTxt; + SkTDArray<SkScalar> bigFallbackPos; SkScalar textSize = paint.skPaint().getTextSize(); SkScalar maxTextSize = fontCache->getGlyphSizeLimit(); - SkScalar scaledFallbackTextSize = maxTextSize; + SkScalar bigFallbackTextSize = maxTextSize; SkScalar maxScale = viewMatrix.getMaxScale(); bool hasWCoord = viewMatrix.hasPerspective() || fDistanceFieldVerticesAlwaysHaveW; @@ -779,30 +723,19 @@ 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; - 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; - } - } - } + SkScalar scaledGlyphSize = maxDim*maxScale; - fallbackTxt.append(SkToInt(text - lastText), lastText); - if (useScaledFallback) { - *fallbackPos.append() = maxScale*pos[0]; + if (!viewMatrix.hasPerspective() && scaledGlyphSize > maxTextSize) { + bigFallbackTxt.append(SkToInt(text - lastText), lastText); + *bigFallbackPos.append() = maxScale*pos[0]; if (2 == scalarsPerPosition) { - *fallbackPos.append() = maxScale*pos[1]; + *bigFallbackPos.append() = maxScale*pos[1]; } SkScalar glyphTextSize = SkScalarFloorToScalar(maxTextSize*textSize/maxDim); - scaledFallbackTextSize = SkTMin(glyphTextSize, scaledFallbackTextSize); + bigFallbackTextSize = SkTMin(glyphTextSize, bigFallbackTextSize); } else { + fallbackTxt.append(SkToInt(text - lastText), lastText); *fallbackPos.append() = pos[0]; if (2 == scalarsPerPosition) { *fallbackPos.append() = pos[1]; @@ -814,35 +747,33 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, } SkGlyphCache::AttachCache(cache); - if (fallbackTxt.count()) { blob->initOverride(runIndex); - 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); - } + 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 360f6ddbec..36e83c4574 100644 --- a/src/gpu/text/GrAtlasTextContext.h +++ b/src/gpu/text/GrAtlasTextContext.h @@ -44,6 +44,9 @@ 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); @@ -107,16 +110,6 @@ 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 c2a7d1136f..d354619a43 100644 --- a/src/gpu/text/GrTextUtils.cpp +++ b/src/gpu/text/GrTextUtils.cpp @@ -8,10 +8,13 @@ #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 @@ -74,3 +77,82 @@ 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 1301b8457b..252cd7c626 100644 --- a/src/gpu/text/GrTextUtils.h +++ b/src/gpu/text/GrTextUtils.h @@ -127,6 +127,19 @@ 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 |