Cleanup of large text rendering, take 2.

* 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
* Set paint flags correctly for paths

Bug: skia:7562
Change-Id: I9455eda2867860a713fbdbbda79c74109e95f9f2
Reviewed-on: https://skia-review.googlesource.com/105020
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/gm/glyph_pos.cpp b/gm/glyph_pos.cpp
index cfc318d..ff2a432 100644
--- a/gm/glyph_pos.cpp
+++ b/gm/glyph_pos.cpp
@@ -26,7 +26,7 @@
 static void draw_gm(SkCanvas* canvas,
                     SkScalar strokeWidth,
                     SkPaint::Style strokeStyle) {
-        // There's a black pixel at 40, 40 for reference.
+    // There's a black pixel at 40, 40 for reference.
     canvas->drawPoint(40, 40, SkPaint());
 
     // Two reference images.
diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp
index 887addd..e805761 100644
--- a/src/gpu/text/GrAtlasTextBlob.cpp
+++ b/src/gpu/text/GrAtlasTextBlob.cpp
@@ -15,6 +15,7 @@
 #include "SkGlyphCache.h"
 #include "SkMaskFilterBase.h"
 #include "SkTextBlobRunIterator.h"
+#include "SkTextToPathIter.h"
 #include "ops/GrAtlasTextOp.h"
 
 sk_sp<GrAtlasTextBlob> GrAtlasTextBlob::Make(GrMemoryPool* pool, int glyphCount, int runCount) {
@@ -73,14 +74,22 @@
                                   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 +149,10 @@
     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 +275,6 @@
     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 +295,95 @@
     }
 }
 
-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);
+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) {
+
+    // 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;
+    GrTextUtils::RunPaint runPaint(&paint, nullptr, props);
+    for (int runIndex = 0; runIndex <= lastRun; runIndex++) {
+        Run& run = fRuns[runIndex];
+
+        // first flush any path glyphs
+        if (run.fPathGlyphs.count()) {
+            SkScalar transX, transY;
+            uint16_t paintFlags = run.fPaintFlags;
+            if (!runPaint.modifyForRun(
+                [paintFlags](SkPaint* p) {
+                    p->setFlags((p->getFlags() & ~Run::kPaintFlagsMask) | paintFlags);
+                })) {
+                continue;
+            }
+            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, runPaint, ctm, &pathMatrix, clipBounds);
+            }
         }
-        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();
-
-    GrTextUtils::RunPaint runPaint(&paint, drawFilter, props);
-    if (!runPaint.modifyForRun(it)) {
-        return;
-    }
-
-    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;
-    }
-}
-
-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);
+        // then flush each subrun, if any
+        if (!run.fInitialized) {
             continue;
         }
-        this->flushRun(target, clip, run, viewMatrix, x, y, paint, props, distanceAdjustTable,
-                       atlasGlyphCache);
+        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;
+            }
+
+            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);
+                    }
+                }
+            }
+
+            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));
+                    }
+                }
+            }
+        }
+
     }
-
-    // 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(
@@ -462,15 +409,6 @@
     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 +444,6 @@
         // 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 +470,15 @@
             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 12a80c4..9132684 100644
--- a/src/gpu/text/GrAtlasTextBlob.h
+++ b/src/gpu/text/GrAtlasTextBlob.h
@@ -142,8 +142,8 @@
         subRun.setHasWCoord(hasWCoord);
     }
 
-    void setRunTooBigForAtlas(int runIndex) {
-        fRuns[runIndex].fTooBigForAtlas = true;
+    void setRunPaintFlags(int runIndex, uint16_t paintFlags) {
+        fRuns[runIndex].fPaintFlags = paintFlags & Run::kPaintFlagsMask;
     }
 
     void setMinAndMaxScale(SkScalar scaledMax, SkScalar scaledMin) {
@@ -175,7 +175,11 @@
                      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 +197,11 @@
     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 +281,6 @@
         , 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 +325,8 @@
      * would greatly increase the memory of these cached items.
      */
     struct Run {
-        Run()
-            : fInitialized(false)
-            , fTooBigForAtlas(false) {
+        Run() : fPaintFlags(0)
+              , fInitialized(false) {
             // To ensure we always have one subrun, we push back a fresh run here
             fSubRunInfo.push_back();
         }
@@ -495,8 +472,31 @@
         // 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
-        bool fInitialized;
-        bool fTooBigForAtlas;
+
+        // 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;
+
+        struct {
+            unsigned fPaintFlags : 16;   // needed mainly for rendering paths
+            bool fInitialized : 1;
+        };
+        // the only flags we need to set
+        static constexpr auto kPaintFlagsMask = SkPaint::kAntiAlias_Flag;
     };  // Run
 
     inline std::unique_ptr<GrAtlasTextOp> makeOp(
@@ -506,20 +506,6 @@
             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 +524,6 @@
     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 1dce4e0..63b3d3d 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 @@
     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 @@
                                  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,
@@ -209,9 +204,11 @@
         size_t textLen = glyphCount * sizeof(uint16_t);
         const SkPoint& offset = it.offset();
         cacheBlob->push_back_run(run);
-        if (!runPaint.modifyForRun(it)) {
+        if (!runPaint.modifyForRun([it](SkPaint* p) { it.applyFontToPaint(p); })) {
             continue;
         }
+        cacheBlob->setRunPaintFlags(run, runPaint.skPaint().getFlags());
+
         if (this->canDrawAsDistanceFields(runPaint, viewMatrix, props, shaderCaps)) {
             switch (it.positioning()) {
                 case SkTextBlob::kDefault_Positioning: {
@@ -235,8 +232,6 @@
                     break;
                 }
             }
-        } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) {
-            cacheBlob->setRunTooBigForAtlas(run);
         } else {
             switch (it.positioning()) {
                 case SkTextBlob::kDefault_Positioning:
@@ -275,6 +270,7 @@
     }
     sk_sp<GrAtlasTextBlob> blob = blobCache->makeBlob(glyphCount, 1);
     blob->initThrowawayBlob(viewMatrix, x, y);
+    blob->setRunPaintFlags(0, paint.skPaint().getFlags());
 
     if (this->canDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) {
         this->drawDFText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix,
@@ -304,6 +300,7 @@
 
     sk_sp<GrAtlasTextBlob> blob = blobCache->makeBlob(glyphCount, 1);
     blob->initThrowawayBlob(viewMatrix, offset.x(), offset.y());
+    blob->setRunPaintFlags(0, paint.skPaint().getFlags());
 
     if (this->canDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) {
         this->drawDFPosText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix,
@@ -328,23 +325,15 @@
     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 +350,15 @@
     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 +377,11 @@
     // 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 +416,15 @@
     // 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 +439,77 @@
     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 +527,7 @@
     if (!glyph) {
         return;
     }
+    glyph->fTooLargeForAtlas = glyph->fTooLargeForAtlas;
 
     SkASSERT(skGlyph.fWidth == glyph->width());
     SkASSERT(skGlyph.fHeight == glyph->height());
@@ -675,11 +736,10 @@
     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 +783,30 @@
                               y - advanceY, paint.filteredPremulColor(), cache, textRatio);
             } else {
                 // can't append color glyph to SDF batch, send to fallback
-                SkScalar maxDim = SkTMax(glyph.fWidth, glyph.fHeight)*textRatio;
-                SkScalar scaledGlyphSize = maxDim*maxScale;
 
-                if (!viewMatrix.hasPerspective() && scaledGlyphSize > maxTextSize) {
-                    bigFallbackTxt.append(SkToInt(text - lastText), lastText);
-                    *bigFallbackPos.append() = maxScale*pos[0];
+                // 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;
+                        }
+                    }
+                }
+
+                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 +818,35 @@
     }
 
     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 36e83c4..360f6dd 100644
--- a/src/gpu/text/GrAtlasTextContext.h
+++ b/src/gpu/text/GrAtlasTextContext.h
@@ -44,9 +44,6 @@
 
     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 @@
                                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 d354619..56c1d33 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
@@ -35,7 +32,8 @@
     }
 }
 
-bool GrTextUtils::RunPaint::modifyForRun(const SkTextBlobRunIterator& run) {
+
+bool GrTextUtils::RunPaint::modifyForRun(std::function<void(SkPaint*)> paintModFunc) {
     if (!fModifiedPaint.isValid()) {
         fModifiedPaint.init(fOriginalPaint->skPaint());
         fPaint = fModifiedPaint.get();
@@ -44,7 +42,7 @@
         // changed the paint.
         *fModifiedPaint.get() = fOriginalPaint->skPaint();
     }
-    run.applyFontToPaint(fModifiedPaint.get());
+    paintModFunc(fModifiedPaint.get());
 
     if (fFilter) {
         if (!fFilter->filter(fModifiedPaint.get(), SkDrawFilter::kText_Type)) {
@@ -77,82 +75,3 @@
     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 252cd7c..58318e8 100644
--- a/src/gpu/text/GrTextUtils.h
+++ b/src/gpu/text/GrTextUtils.h
@@ -115,7 +115,7 @@
             fFilteredPremulColor = fOriginalPaint->filteredPremulColor();
         }
 
-        bool modifyForRun(const SkTextBlobRunIterator&);
+        bool modifyForRun(std::function<void(SkPaint*)> paintModFunc);
 
     private:
         SkTLazy<SkPaint> fModifiedPaint;
@@ -127,19 +127,6 @@
     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