Remove runIndex as a concept for GrTextBlob

Change-Id: I8ac756a088c1dddf475bf96f9a4a84ec2cb500be
Reviewed-on: https://skia-review.googlesource.com/c/169763
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
diff --git a/src/core/SkGlyphRunPainter.cpp b/src/core/SkGlyphRunPainter.cpp
index 1fb42cb..3efda7b 100644
--- a/src/core/SkGlyphRunPainter.cpp
+++ b/src/core/SkGlyphRunPainter.cpp
@@ -317,29 +317,6 @@
     }
 }
 
-static SkRect rect_to_draw(
-        const SkGlyph& glyph, SkPoint origin, SkScalar textScale, bool isDFT) {
-
-    SkScalar dx = SkIntToScalar(glyph.fLeft);
-    SkScalar dy = SkIntToScalar(glyph.fTop);
-    SkScalar width = SkIntToScalar(glyph.fWidth);
-    SkScalar height = SkIntToScalar(glyph.fHeight);
-
-    if (isDFT) {
-        dx += SK_DistanceFieldInset;
-        dy += SK_DistanceFieldInset;
-        width -= 2 * SK_DistanceFieldInset;
-        height -= 2 * SK_DistanceFieldInset;
-    }
-
-    dx *= textScale;
-    dy *= textScale;
-    width *= textScale;
-    height *= textScale;
-
-    return SkRect::MakeXYWH(origin.x() + dx, origin.y() + dy, width, height);
-}
-
 // Beware! The following code will end up holding two glyph caches at the same time, but they
 // will not be the same cache (which would cause two separate caches to be created).
 template <typename PerPathT>
@@ -395,15 +372,7 @@
         if (SkScalarsAreFinite(mappedPt.x(), mappedPt.y())) {
             const SkGlyph& glyph = cache->getGlyphMetrics(glyphID, mappedPt);
             if (SkGlyphCacheCommon::GlyphTooBigForAtlas(glyph)) {
-                SkScalar sx = SkScalarFloorToScalar(mappedPt.fX),
-                        sy = SkScalarFloorToScalar(mappedPt.fY);
-
-                SkRect glyphRect =
-                        rect_to_draw(glyph, {sx, sy}, SK_Scalar1, false);
-
-                if (!glyphRect.isEmpty()) {
-                    perPath(glyph, mappedPt);
-                }
+                perPath(glyph, mappedPt);
             } else {
                 perGlyph(glyph, mappedPt);
             }
@@ -552,34 +521,6 @@
                      clip, viewMatrix, origin.x(), origin.y());
 }
 
-static void append_glyph(GrTextBlob* blob, int runIndex,
-                                const sk_sp<GrTextStrike>& strike,
-                                const SkGlyph& skGlyph, GrGlyph::MaskStyle maskStyle,
-                                SkScalar sx, SkScalar sy,
-                                const SkPMColor4f& color, SkGlyphCache* skGlyphCache,
-                                SkScalar textRatio, bool needsTransform) {
-    GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
-                                         skGlyph.getSubXFixed(),
-                                         skGlyph.getSubYFixed(),
-                                         maskStyle);
-    GrGlyph* glyph = strike->getGlyph(skGlyph, id, skGlyphCache);
-    if (!glyph) {
-        return;
-    }
-
-    SkASSERT(skGlyph.fWidth == glyph->width());
-    SkASSERT(skGlyph.fHeight == glyph->height());
-
-    bool isDFT = maskStyle == GrGlyph::kDistance_MaskStyle;
-
-    SkRect glyphRect = rect_to_draw(skGlyph, {sx, sy}, textRatio, isDFT);
-
-    if (!glyphRect.isEmpty()) {
-        blob->appendGlyph(runIndex, glyphRect, color, strike, glyph, !needsTransform);
-    }
-}
-
-
 void GrTextBlob::generateFromGlyphRunList(GrGlyphCache* glyphCache,
                                           const GrShaderCaps& shaderCaps,
                                           const GrTextContext::Options& options,
@@ -595,26 +536,25 @@
                     SkSpan<const SkPoint> positions, SkScalar textScale,
                     const SkMatrix& glyphCacheMatrix,
                     SkGlyphRunListPainter::NeedsTransform needsTransform) const {
-            fBlob->initOverride(fRunIndex);
+            fRun->initOverride();
             fBlob->setHasBitmap();
-            fBlob->setSubRunHasW(fRunIndex, glyphCacheMatrix.hasPerspective());
+            fRun->setSubRunHasW(glyphCacheMatrix.hasPerspective());
             SkExclusiveStrikePtr fallbackCache =
-                    fBlob->setupCache(fRunIndex,
-                                      fallbackPaint, fProps, fScalerContextFlags, glyphCacheMatrix);
+                    fRun->setupCache(fallbackPaint, fProps, fScalerContextFlags, glyphCacheMatrix);
             sk_sp<GrTextStrike> strike = fGlyphCache->getStrike(fallbackCache.get());
             const SkPoint* glyphPos = positions.data();
             for (auto glyphID : glyphIDs) {
                 const SkGlyph& glyph = fallbackCache->getGlyphIDMetrics(glyphID);
-                append_glyph(fBlob, fRunIndex, strike, glyph,
-                             GrGlyph::kCoverage_MaskStyle,
-                             glyphPos->fX, glyphPos->fY, fFilteredColor,
-                             fallbackCache.get(), textScale, needsTransform);
+                fRun->appendGlyph(fBlob, strike, glyph,
+                                 GrGlyph::kCoverage_MaskStyle,
+                                 *glyphPos, fFilteredColor,
+                                 fallbackCache.get(), textScale, needsTransform);
                 glyphPos++;
             }
         }
 
         GrTextBlob* const fBlob;
-        const int fRunIndex;
+        GrTextBlob::Run* fRun;
         const SkSurfaceProps& fProps;
         const SkScalerContextFlags fScalerContextFlags;
         GrGlyphCache* const fGlyphCache;
@@ -625,12 +565,11 @@
     this->initReusableBlob(
             glyphRunList.paint().computeLuminanceColor(), viewMatrix, origin.x(), origin.y());
 
-    int runIndex = 0;
     for (const auto& glyphRun : glyphRunList) {
         const SkPaint& runPaint = glyphRun.paint();
-        this->pushBackRun(runIndex);
+        Run* run = this->pushBackRun();
 
-        this->setRunPaintFlags(runIndex, runPaint.getFlags());
+        run->setRunPaintFlags(runPaint.getFlags());
 
         if (GrTextContext::CanDrawAsDistanceFields(runPaint, viewMatrix, props,
                                     shaderCaps.supportsDistanceFieldText(), options)) {
@@ -644,42 +583,36 @@
             GrTextContext::InitDistanceFieldPaint(this, &distanceFieldPaint, viewMatrix,
                                                   options, &textRatio, &flags);
             this->setHasDistanceField();
-            this->setSubRunHasDistanceFields(runIndex, runPaint.isLCDRenderText(),
-                                                  runPaint.isAntiAlias(), hasWCoord);
+            run->setSubRunHasDistanceFields(runPaint.isLCDRenderText(),
+                                            runPaint.isAntiAlias(), hasWCoord);
 
             {
-                auto cache = this->setupCache(
-                        runIndex, distanceFieldPaint, props, flags, SkMatrix::I());
+                auto cache = run->setupCache(distanceFieldPaint, props, flags, SkMatrix::I());
 
                 sk_sp<GrTextStrike> currStrike = glyphCache->getStrike(cache.get());
 
                 auto perSDF =
-                    [this, runIndex, &currStrike, filteredColor, cache{cache.get()}, textRatio]
+                    [this, run, &currStrike, filteredColor, cache{cache.get()}, textRatio]
                     (const SkGlyph& glyph, SkPoint position) {
                         if (!glyph.isEmpty()) {
-                            SkScalar sx = position.fX,
-                                     sy = position.fY;
-                            append_glyph(this, runIndex, currStrike,
-                                        glyph, GrGlyph::kDistance_MaskStyle, sx, sy,
+                            run->appendGlyph(this, currStrike,
+                                        glyph, GrGlyph::kDistance_MaskStyle, position,
                                         filteredColor,
                                         cache, textRatio, true);
                         }
                     };
 
                 auto perPath =
-                    [this, runIndex, textRatio, cache{cache.get()}]
+                    [run, textRatio, cache{cache.get()}]
                     (const SkGlyph& glyph, SkPoint position) {
                         if (!glyph.isEmpty()) {
                             if (const SkPath* glyphPath = cache->findPath(glyph)) {
-                                SkScalar sx = position.fX,
-                                         sy = position.fY;
-                                this->appendPathGlyph(
-                                        runIndex, *glyphPath, sx, sy, textRatio, false);
+                                run->appendPathGlyph(*glyphPath, position, textRatio, false);
                             }
                         }
                     };
 
-                ARGBFallbackHelper argbFallback{this, runIndex, props, scalerContextFlags,
+                ARGBFallbackHelper argbFallback{this, run, props, scalerContextFlags,
                                                 glyphCache, filteredColor};
 
                 glyphPainter->drawGlyphRunAsSDFWithARGBFallback(
@@ -701,18 +634,17 @@
                     pathPaint, props, scalerContextFlags, SkMatrix::I());
 
             // Given a glyph that is not ARGB, draw it.
-            auto perPath = [textScale, runIndex, this, &pathCache]
+            auto perPath = [textScale, run, &pathCache]
                            (const SkGlyph& glyph, SkPoint position) {
                 if (!glyph.isEmpty()) {
                     const SkPath* path = pathCache->findPath(glyph);
                     if (path != nullptr) {
-                        this->appendPathGlyph(
-                                runIndex, *path, position.fX, position.fY, textScale, false);
+                        run->appendPathGlyph(*path, position, textScale, false);
                     }
                 }
             };
 
-            ARGBFallbackHelper argbFallback{this, runIndex, props, scalerContextFlags,
+            ARGBFallbackHelper argbFallback{this, run, props, scalerContextFlags,
                                             glyphCache, filteredColor};
 
             glyphPainter->drawGlyphRunAsPathWithARGBFallback(
@@ -722,35 +654,33 @@
             // Ensure the blob is set for bitmaptext
             this->setHasBitmap();
 
-            auto cache = this->setupCache(
-                    runIndex, runPaint, props, scalerContextFlags, viewMatrix);
+            auto cache = run->setupCache(runPaint, props, scalerContextFlags, viewMatrix);
 
             sk_sp<GrTextStrike> currStrike = glyphCache->getStrike(cache.get());
 
             auto perGlyph =
-                [this, runIndex, &currStrike, filteredColor, cache{cache.get()}]
+                [this, run, &currStrike, filteredColor, cache{cache.get()}]
                 (const SkGlyph& glyph, SkPoint mappedPt) {
                     if (!glyph.isEmpty()) {
                         const void* glyphImage = cache->findImage(glyph);
                         if (glyphImage != nullptr) {
-                            SkScalar sx = SkScalarFloorToScalar(mappedPt.fX),
-                                     sy = SkScalarFloorToScalar(mappedPt.fY);
-                            append_glyph(this, runIndex, currStrike,
-                                        glyph, GrGlyph::kCoverage_MaskStyle, sx, sy,
-                                        filteredColor, cache, SK_Scalar1, false);
+                            SkPoint pt{SkScalarFloorToScalar(mappedPt.fX),
+                                       SkScalarFloorToScalar(mappedPt.fY)};
+                            run->appendGlyph(this, currStrike,
+                                             glyph, GrGlyph::kCoverage_MaskStyle, pt,
+                                             filteredColor, cache, SK_Scalar1, false);
                         }
                     }
                 };
 
             auto perPath =
-                [this, runIndex, cache{cache.get()}]
+                [run, cache{cache.get()}]
                 (const SkGlyph& glyph, SkPoint position) {
                     const SkPath* glyphPath = cache->findPath(glyph);
                     if (glyphPath != nullptr) {
-                        SkScalar sx = SkScalarFloorToScalar(position.fX),
-                                 sy = SkScalarFloorToScalar(position.fY);
-                        this->appendPathGlyph(
-                                runIndex, *glyphPath, sx, sy, SK_Scalar1, true);
+                        SkPoint pt{SkScalarFloorToScalar(position.fX),
+                                   SkScalarFloorToScalar(position.fY)};
+                        run->appendPathGlyph(*glyphPath, pt, SK_Scalar1, true);
                     }
                 };
 
@@ -758,7 +688,6 @@
                     cache.get(), glyphRun, origin, viewMatrix,
                     std::move(perGlyph), std::move(perPath));
         }
-        runIndex += 1;
     }
 }
 
diff --git a/src/core/SkGlyphRunPainter.h b/src/core/SkGlyphRunPainter.h
index 948a5d2..c41262b 100644
--- a/src/core/SkGlyphRunPainter.h
+++ b/src/core/SkGlyphRunPainter.h
@@ -40,7 +40,6 @@
     static bool GlyphTooBigForAtlas(const SkGlyph& glyph);
 };
 
-
 class SkGlyphRunListPainter {
 public:
     // Constructor for SkBitmpapDevice.
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index 5d0f81e..bc1b6d0 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -126,7 +126,7 @@
                     fGeoData[i].fColor.toBytes_RGBA(),
                     fGeoData[i].fX,
                     fGeoData[i].fY,
-                    fGeoData[i].fBlob->runCount());
+                    fGeoData[i].fBlob->runCountLimit());
     }
 
     str += fProcessors.dumpProcessors();
diff --git a/src/gpu/text/GrTextBlob.cpp b/src/gpu/text/GrTextBlob.cpp
index e035124..fe52f19 100644
--- a/src/gpu/text/GrTextBlob.cpp
+++ b/src/gpu/text/GrTextBlob.cpp
@@ -54,96 +54,133 @@
     for (int i = 0; i < runCount; i++) {
         new (&cacheBlob->fRuns[i]) GrTextBlob::Run;
     }
-    cacheBlob->fRunCount = runCount;
+    cacheBlob->fRunCountLimit = runCount;
     return cacheBlob;
 }
 
-SkExclusiveStrikePtr GrTextBlob::setupCache(int runIndex,
-                                            const SkPaint& skPaint,
-                                            const SkSurfaceProps& props,
-                                            SkScalerContextFlags scalerContextFlags,
-                                            const SkMatrix& viewMatrix) {
-    GrTextBlob::Run* run = &fRuns[runIndex];
+SkExclusiveStrikePtr GrTextBlob::Run::setupCache(const SkPaint& skPaint,
+                                                 const SkSurfaceProps& props,
+                                                 SkScalerContextFlags scalerContextFlags,
+                                                 const SkMatrix& viewMatrix) {
 
     // if we have an override descriptor for the run, then we should use that
-    SkAutoDescriptor* desc = run->fOverrideDescriptor.get() ? run->fOverrideDescriptor.get() :
-                                                              &run->fDescriptor;
+    SkAutoDescriptor* desc = fOverrideDescriptor.get() ? fOverrideDescriptor.get() : &fDescriptor;
     SkScalerContextEffects effects;
     SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
         skPaint, props, scalerContextFlags, viewMatrix, desc, &effects);
-    run->fTypeface = SkPaintPriv::RefTypefaceOrDefault(skPaint);
-    run->fPathEffect = sk_ref_sp(effects.fPathEffect);
-    run->fMaskFilter = sk_ref_sp(effects.fMaskFilter);
-    return SkStrikeCache::FindOrCreateStrikeExclusive(*desc->getDesc(), effects, *run->fTypeface);
+    fTypeface = SkPaintPriv::RefTypefaceOrDefault(skPaint);
+    fPathEffect = sk_ref_sp(effects.fPathEffect);
+    fMaskFilter = sk_ref_sp(effects.fMaskFilter);
+    return SkStrikeCache::FindOrCreateStrikeExclusive(*desc->getDesc(), effects, *fTypeface);
 }
 
-void GrTextBlob::appendGlyph(int runIndex,
-                             const SkRect& positions,
-                             const SkPMColor4f& color4f,
-                             const sk_sp<GrTextStrike>& strike,
-                             GrGlyph* glyph, bool preTransformed) {
-    // TODO4F: Preserve float colors
-    GrColor color = color4f.toBytes_RGBA();
+static SkRect rect_to_draw(
+        const SkGlyph& glyph, SkPoint origin, SkScalar textScale, bool isDFT) {
 
-    Run& run = fRuns[runIndex];
-    GrMaskFormat format = glyph->fMaskFormat;
+    SkScalar dx = SkIntToScalar(glyph.fLeft);
+    SkScalar dy = SkIntToScalar(glyph.fTop);
+    SkScalar width = SkIntToScalar(glyph.fWidth);
+    SkScalar height = SkIntToScalar(glyph.fHeight);
 
-    Run::SubRunInfo* subRun = &run.fSubRunInfo.back();
-    if (run.fInitialized && subRun->maskFormat() != format) {
-        subRun = &run.push_back();
-        subRun->setStrike(strike);
-    } else if (!run.fInitialized) {
-        subRun->setStrike(strike);
+    if (isDFT) {
+        dx += SK_DistanceFieldInset;
+        dy += SK_DistanceFieldInset;
+        width -= 2 * SK_DistanceFieldInset;
+        height -= 2 * SK_DistanceFieldInset;
     }
 
-    run.fInitialized = true;
+    dx *= textScale;
+    dy *= textScale;
+    width *= textScale;
+    height *= textScale;
 
-    bool hasW = subRun->hasWCoord();
-    // glyphs drawn in perspective must always have a w coord.
-    SkASSERT(hasW || !fInitialViewMatrix.hasPerspective());
-
-    size_t vertexStride = GetVertexStride(format, hasW);
-
-    subRun->setMaskFormat(format);
-
-    subRun->joinGlyphBounds(positions);
-    subRun->setColor(color);
-
-    intptr_t vertex = reinterpret_cast<intptr_t>(this->fVertices + subRun->vertexEndIndex());
-
-    // We always write the third position component used by SDFs. If it is unused it gets
-    // overwritten. Similarly, we always write the color and the blob will later overwrite it
-    // with texture coords if it is unused.
-    size_t colorOffset = hasW ? sizeof(SkPoint3) : sizeof(SkPoint);
-    // V0
-    *reinterpret_cast<SkPoint3*>(vertex) = {positions.fLeft, positions.fTop, 1.f};
-    *reinterpret_cast<GrColor*>(vertex + colorOffset) = color;
-    vertex += vertexStride;
-
-    // V1
-    *reinterpret_cast<SkPoint3*>(vertex) = {positions.fLeft, positions.fBottom, 1.f};
-    *reinterpret_cast<GrColor*>(vertex + colorOffset) = color;
-    vertex += vertexStride;
-
-    // V2
-    *reinterpret_cast<SkPoint3*>(vertex) = {positions.fRight, positions.fTop, 1.f};
-    *reinterpret_cast<GrColor*>(vertex + colorOffset) = color;
-    vertex += vertexStride;
-
-    // V3
-    *reinterpret_cast<SkPoint3*>(vertex) = {positions.fRight, positions.fBottom, 1.f};
-    *reinterpret_cast<GrColor*>(vertex + colorOffset) = color;
-
-    subRun->appendVertices(vertexStride);
-    fGlyphs[subRun->glyphEndIndex()] = glyph;
-    subRun->glyphAppended();
-    subRun->setNeedsTransform(!preTransformed);
+    return SkRect::MakeXYWH(origin.x() + dx, origin.y() + dy, width, height);
 }
 
-void GrTextBlob::appendPathGlyph(int runIndex, const SkPath& path, SkScalar x, SkScalar y,
+void GrTextBlob::Run::appendGlyph(GrTextBlob* blob,
+                                  const sk_sp<GrTextStrike>& strike,
+                                  const SkGlyph& skGlyph, GrGlyph::MaskStyle maskStyle,
+                                  SkPoint origin,
+                                  const SkPMColor4f& color4f, SkGlyphCache* skGlyphCache,
+                                  SkScalar textRatio, bool needsTransform) {
+
+    GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
+                                         skGlyph.getSubXFixed(),
+                                         skGlyph.getSubYFixed(),
+                                         maskStyle);
+    GrGlyph* glyph = strike->getGlyph(skGlyph, id, skGlyphCache);
+    if (!glyph) {
+        return;
+    }
+
+    SkASSERT(skGlyph.fWidth == glyph->width());
+    SkASSERT(skGlyph.fHeight == glyph->height());
+
+    bool isDFT = maskStyle == GrGlyph::kDistance_MaskStyle;
+
+    SkRect glyphRect = rect_to_draw(skGlyph, origin, textRatio, isDFT);
+    if (!glyphRect.isEmpty()) {
+        // TODO4F: Preserve float colors
+        GrColor color = color4f.toBytes_RGBA();
+
+        GrMaskFormat format = glyph->fMaskFormat;
+
+        Run::SubRunInfo* subRun = &fSubRunInfo.back();
+        if (fInitialized && subRun->maskFormat() != format) {
+            subRun = &pushBackSubRun();
+            subRun->setStrike(strike);
+        } else if (!fInitialized) {
+            subRun->setStrike(strike);
+        }
+
+        fInitialized = true;
+
+        bool hasW = subRun->hasWCoord();
+        // glyphs drawn in perspective must always have a w coord.
+        SkASSERT(hasW || !blob->fInitialViewMatrix.hasPerspective());
+
+        size_t vertexStride = GetVertexStride(format, hasW);
+
+        subRun->setMaskFormat(format);
+
+        subRun->joinGlyphBounds(glyphRect);
+        subRun->setColor(color);
+
+        intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->vertexEndIndex());
+
+        // We always write the third position component used by SDFs. If it is unused it gets
+        // overwritten. Similarly, we always write the color and the blob will later overwrite it
+        // with texture coords if it is unused.
+        size_t colorOffset = hasW ? sizeof(SkPoint3) : sizeof(SkPoint);
+        // V0
+        *reinterpret_cast<SkPoint3*>(vertex) = {glyphRect.fLeft, glyphRect.fTop, 1.f};
+        *reinterpret_cast<GrColor*>(vertex + colorOffset) = color;
+        vertex += vertexStride;
+
+        // V1
+        *reinterpret_cast<SkPoint3*>(vertex) = {glyphRect.fLeft, glyphRect.fBottom, 1.f};
+        *reinterpret_cast<GrColor*>(vertex + colorOffset) = color;
+        vertex += vertexStride;
+
+        // V2
+        *reinterpret_cast<SkPoint3*>(vertex) = {glyphRect.fRight, glyphRect.fTop, 1.f};
+        *reinterpret_cast<GrColor*>(vertex + colorOffset) = color;
+        vertex += vertexStride;
+
+        // V3
+        *reinterpret_cast<SkPoint3*>(vertex) = {glyphRect.fRight, glyphRect.fBottom, 1.f};
+        *reinterpret_cast<GrColor*>(vertex + colorOffset) = color;
+
+        subRun->appendVertices(vertexStride);
+        blob->fGlyphs[subRun->glyphEndIndex()] = glyph;
+        subRun->glyphAppended();
+        subRun->setNeedsTransform(needsTransform);
+    }
+}
+
+void GrTextBlob::Run::appendPathGlyph(const SkPath& path, SkPoint position,
                                       SkScalar scale, bool preTransformed) {
-    Run& run = fRuns[runIndex];
-    run.fPathGlyphs.push_back(GrTextBlob::Run::PathGlyph(path, x, y, scale, preTransformed));
+    fPathGlyphs.push_back(PathGlyph(path, position.x(), position.y(), scale, preTransformed));
 }
 
 bool GrTextBlob::mustRegenerate(const SkPaint& paint, bool anyRunHasSubpixelPosition,
@@ -294,7 +331,7 @@
 
     // GrTextBlob::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;
+    int lastRun = SkTMin(fRunCountLimit, (1 << 16)) - 1;
     // For each run in the GrTextBlob we're going to churn through all the glyphs.
     // Each run is broken into a path part and a Mask / DFT / ARGB part.
     for (int runIndex = 0; runIndex <= lastRun; runIndex++) {
@@ -465,8 +502,8 @@
     SkASSERT_RELEASE(l.fMinMaxScale == r.fMinMaxScale);
     SkASSERT_RELEASE(l.fTextType == r.fTextType);
 
-    SkASSERT_RELEASE(l.fRunCount == r.fRunCount);
-    for (int i = 0; i < l.fRunCount; i++) {
+    SkASSERT_RELEASE(l.fRunCountLimit == r.fRunCountLimit);
+    for (int i = 0; i < l.fRunCountLimit; i++) {
         const Run& lRun = l.fRuns[i];
         const Run& rRun = r.fRuns[i];
 
diff --git a/src/gpu/text/GrTextBlob.h b/src/gpu/text/GrTextBlob.h
index f773d0b..e5908fe 100644
--- a/src/gpu/text/GrTextBlob.h
+++ b/src/gpu/text/GrTextBlob.h
@@ -132,36 +132,18 @@
     void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
     void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
 
-    int runCount() const { return fRunCount; }
+    int runCountLimit() const { return fRunCountLimit; }
 
-    void pushBackRun(int currRun) {
-        SkASSERT(currRun < fRunCount);
-        if (currRun > 0) {
-            Run::SubRunInfo& newRun = fRuns[currRun].fSubRunInfo.back();
-            Run::SubRunInfo& lastRun = fRuns[currRun - 1].fSubRunInfo.back();
+    Run* pushBackRun() {
+        SkASSERT(fRunCount < fRunCountLimit);
+        if (fRunCount > 0) {
+            Run::SubRunInfo& newRun = fRuns[fRunCount].fSubRunInfo.back();
+            Run::SubRunInfo& lastRun = fRuns[fRunCount - 1].fSubRunInfo.back();
             newRun.setAsSuccessor(lastRun);
         }
-    }
 
-    // sets the last subrun of runIndex to use distance field text
-    void setSubRunHasDistanceFields(int runIndex, bool hasLCD, bool isAntiAlias, bool hasWCoord) {
-        Run& run = fRuns[runIndex];
-        Run::SubRunInfo& subRun = run.fSubRunInfo.back();
-        subRun.setUseLCDText(hasLCD);
-        subRun.setAntiAliased(isAntiAlias);
-        subRun.setDrawAsDistanceFields();
-        subRun.setHasWCoord(hasWCoord);
-    }
-
-    // sets the last subrun of runIndex to use w values
-    void setSubRunHasW(int runIndex, bool hasWCoord) {
-        Run& run = fRuns[runIndex];
-        Run::SubRunInfo& subRun = run.fSubRunInfo.back();
-        subRun.setHasWCoord(hasWCoord);
-    }
-
-    void setRunPaintFlags(int runIndex, uint16_t paintFlags) {
-        fRuns[runIndex].fPaintFlags = paintFlags & Run::kPaintFlagsMask;
+        fRunCount++;
+        return &fRuns[fRunCount - 1];
     }
 
     void setMinAndMaxScale(SkScalar scaledMax, SkScalar scaledMin) {
@@ -170,33 +152,6 @@
         fMinMaxScale = SkMinScalar(scaledMin, fMinMaxScale);
     }
 
-    // inits the override descriptor on the current run.  All following subruns must use this
-    // descriptor
-    void initOverride(int runIndex) {
-        Run& run = fRuns[runIndex];
-        // Push back a new subrun to fill and set the override descriptor
-        run.push_back();
-        run.fOverrideDescriptor.reset(new SkAutoDescriptor);
-    }
-
-    SkExclusiveStrikePtr setupCache(int runIndex,
-                                    const SkPaint& skPaint,
-                                    const SkSurfaceProps& props,
-                                    SkScalerContextFlags scalerContextFlags,
-                                    const SkMatrix& viewMatrix);
-
-    // Appends a glyph to the blob.  If the glyph is too large, the glyph will be appended
-    // as a path.
-    void appendGlyph(int runIndex,
-                     const SkRect& positions,
-                     const SkPMColor4f& color,
-                     const sk_sp<GrTextStrike>& strike,
-                     GrGlyph* glyph, 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 hasWCoord) {
         switch (maskFormat) {
             case kA8_GrMaskFormat:
@@ -280,7 +235,7 @@
     size_t size() const { return fSize; }
 
     ~GrTextBlob() {
-        for (int i = 0; i < fRunCount; i++) {
+        for (int i = 0; i < fRunCountLimit; i++) {
             fRuns[i].~Run();
         }
     }
@@ -313,7 +268,7 @@
         fInitialY = y;
 
         // make sure all initial subruns have the correct VM and X/Y applied
-        for (int i = 0; i < fRunCount; i++) {
+        for (int i = 0; i < fRunCountLimit; i++) {
             fRuns[i].fSubRunInfo[0].init(fInitialViewMatrix, x, y);
         }
     }
@@ -474,7 +429,52 @@
             uint32_t fFlags;
         };  // SubRunInfo
 
-        SubRunInfo& push_back() {
+        // sets the last subrun of runIndex to use w values
+        void setSubRunHasW(bool hasWCoord) {
+            Run::SubRunInfo& subRun = this->fSubRunInfo.back();
+            subRun.setHasWCoord(hasWCoord);
+        }
+
+        // inits the override descriptor on the current run.  All following subruns must use this
+        // descriptor
+        void initOverride() {
+            // Push back a new subrun to fill and set the override descriptor
+            this->pushBackSubRun();
+            fOverrideDescriptor.reset(new SkAutoDescriptor);
+        }
+
+        // Appends a glyph to the blob as a path only.
+        void appendPathGlyph(
+                const SkPath& path, SkPoint position, SkScalar scale, bool preTransformed);
+
+        // Appends a glyph to the blob.  If the glyph is too large, the glyph will be appended
+        // as a path.
+        void appendGlyph(GrTextBlob* blob,
+                         const sk_sp<GrTextStrike>& strike,
+                         const SkGlyph& skGlyph, GrGlyph::MaskStyle maskStyle,
+                         SkPoint origin,
+                         const SkPMColor4f& color, SkGlyphCache* skGlyphCache,
+                         SkScalar textRatio, bool needsTransform);
+
+        SkExclusiveStrikePtr setupCache(const SkPaint& skPaint,
+                                        const SkSurfaceProps& props,
+                                        SkScalerContextFlags scalerContextFlags,
+                                        const SkMatrix& viewMatrix);
+
+        void setRunPaintFlags(uint16_t paintFlags) {
+            fPaintFlags = paintFlags & Run::kPaintFlagsMask;
+        }
+
+        // sets the last subrun of runIndex to use distance field text
+        void setSubRunHasDistanceFields(bool hasLCD, bool isAntiAlias, bool hasWCoord) {
+            Run::SubRunInfo& subRun = fSubRunInfo.back();
+            subRun.setUseLCDText(hasLCD);
+            subRun.setAntiAliased(isAntiAlias);
+            subRun.setDrawAsDistanceFields();
+            subRun.setHasWCoord(hasWCoord);
+        }
+
+        SubRunInfo& pushBackSubRun() {
             // Forward glyph / vertex information to seed the new sub run
             SubRunInfo& newSubRun = fSubRunInfo.push_back();
             const SubRunInfo& prevSubRun = fSubRunInfo.fromBack(1);
@@ -559,7 +559,8 @@
     // maximum minimum scale, and minimum maximum scale, we can support before we need to regen
     SkScalar fMaxMinScale;
     SkScalar fMinMaxScale;
-    int fRunCount;
+    int fRunCount{0};
+    int fRunCountLimit;
     uint8_t fTextType;
 };