Use SkTextBlob for nvpr color bitmap fallbacks

BUG=skia:

Review URL: https://codereview.chromium.org/1381873003
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index 9f394f9..61f7f86 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -92,6 +92,32 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
+class GrStencilAndCoverTextContext::FallbackBlobBuilder {
+public:
+    FallbackBlobBuilder() : fBuffIdx(0) {}
+
+    bool isInitialized() const { return SkToBool(fBuilder); }
+
+    void init(const SkPaint& font, SkScalar textRatio);
+
+    void appendGlyph(uint16_t glyphId, const SkPoint& pos);
+
+    const SkTextBlob* buildIfInitialized();
+
+private:
+    enum { kWriteBufferSize = 1024 };
+
+    void flush();
+
+    SkAutoTDelete<SkTextBlobBuilder>   fBuilder;
+    SkPaint                            fFont;
+    int                                fBuffIdx;
+    uint16_t                           fGlyphIds[kWriteBufferSize];
+    SkPoint                            fPositions[kWriteBufferSize];
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
 GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
     : fStroke(fontAndStroke),
       fFont(fontAndStroke) {
@@ -198,16 +224,20 @@
 
     SkFixed fx = SkScalarToFixed(x);
     SkFixed fy = SkScalarToFixed(y);
+    FallbackBlobBuilder fallback;
     while (text < stop) {
         const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0);
         fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio);
         if (glyph.fWidth) {
-            this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy)));
+            this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy)),
+                              &fallback);
         }
 
         fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio);
         fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio);
     }
+
+    fFallbackTextBlob.reset(fallback.buildIfInitialized());
 }
 
 void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t byteLength,
@@ -230,6 +260,7 @@
 
     SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
     SkTextAlignProc alignProc(fFont.getTextAlign());
+    FallbackBlobBuilder fallback;
     while (text < stop) {
         const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0);
         if (glyph.fWidth) {
@@ -238,10 +269,12 @@
             SkPoint loc;
             alignProc(tmsLoc, glyph, &loc);
 
-            this->appendGlyph(glyph, loc);
+            this->appendGlyph(glyph, loc, &fallback);
         }
         pos += scalarsPerPosition;
     }
+
+    fFallbackTextBlob.reset(fallback.buildIfInitialized());
 }
 
 GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx,
@@ -275,11 +308,14 @@
 }
 
 inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& glyph,
-                                                               const SkPoint& pos) {
-    // Stick the glyphs we can't draw into the fallback arrays.
+                                                               const SkPoint& pos,
+                                                               FallbackBlobBuilder* fallback) {
+    // Stick the glyphs we can't draw into the fallback text blob.
     if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
-        fFallbackIndices.push_back(glyph.getGlyphID());
-        fFallbackPositions.push_back(pos);
+        if (!fallback->isInitialized()) {
+            fallback->init(fFont, fTextRatio);
+        }
+        fallback->appendGlyph(glyph.getGlyphID(), pos);
     } else {
         float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * pos.y() };
         fDraw->append(glyph.getGlyphID(), translate);
@@ -318,31 +354,62 @@
                                GrPathRendering::kWinding_FillType);
     }
 
-    if (fFallbackIndices.count()) {
-        SkASSERT(fFallbackPositions.count() == fFallbackIndices.count());
-
-        enum { kPreservedFlags = SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag |
-                                 SkPaint::kLCDRenderText_Flag | SkPaint::kAutoHinting_Flag };
-
+    if (fFallbackTextBlob) {
         SkPaint fallbackSkPaint(originalSkPaint);
         fStroke.applyToPaint(&fallbackSkPaint);
         if (!fStroke.isFillStyle()) {
             fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio);
         }
-        fallbackSkPaint.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for.
-        fallbackSkPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-        fallbackSkPaint.setHinting(fFont.getHinting());
-        fallbackSkPaint.setFlags((fFont.getFlags() & kPreservedFlags) |
-                                 (originalSkPaint.getFlags() & ~kPreservedFlags));
-        // No need for subpixel positioning with bitmap glyphs. TODO: revisit if non-bitmap color
-        // glyphs show up and https://code.google.com/p/skia/issues/detail?id=4408 gets resolved.
-        fallbackSkPaint.setSubpixelText(false);
-        fallbackSkPaint.setTextSize(fFont.getTextSize() * fTextRatio);
 
-        fallbackTextContext->drawPosText(dc, rt, clip, paint, fallbackSkPaint, viewMatrix,
-                                         (char*)fFallbackIndices.begin(),
-                                         sizeof(uint16_t) * fFallbackIndices.count(),
-                                         fFallbackPositions[0].asScalars(), 2, SkPoint::Make(0, 0),
-                                         regionClipBounds);
+        fallbackTextContext->drawTextBlob(dc, rt, clip, fallbackSkPaint, viewMatrix,
+                                          fFallbackTextBlob, 0, 0, nullptr, regionClipBounds);
     }
 }
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void GrStencilAndCoverTextContext::FallbackBlobBuilder::init(const SkPaint& font,
+                                                             SkScalar textRatio) {
+    SkASSERT(!this->isInitialized());
+    fBuilder.reset(new SkTextBlobBuilder);
+    fFont = font;
+    fFont.setTextAlign(SkPaint::kLeft_Align); // The glyph positions will already account for align.
+    fFont.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    // No need for subpixel positioning with bitmap glyphs. TODO: revisit if non-bitmap color glyphs
+    // show up and https://code.google.com/p/skia/issues/detail?id=4408 gets resolved.
+    fFont.setSubpixelText(false);
+    fFont.setTextSize(fFont.getTextSize() * textRatio);
+    fBuffIdx = 0;
+}
+
+void GrStencilAndCoverTextContext::FallbackBlobBuilder::appendGlyph(uint16_t glyphId,
+                                                                    const SkPoint& pos) {
+    SkASSERT(this->isInitialized());
+    if (fBuffIdx >= kWriteBufferSize) {
+        this->flush();
+    }
+    fGlyphIds[fBuffIdx] = glyphId;
+    fPositions[fBuffIdx] = pos;
+    fBuffIdx++;
+}
+
+void GrStencilAndCoverTextContext::FallbackBlobBuilder::flush() {
+    SkASSERT(this->isInitialized());
+    SkASSERT(fBuffIdx <= kWriteBufferSize);
+    if (!fBuffIdx) {
+        return;
+    }
+    // This will automatically merge with previous runs since we use the same font.
+    const SkTextBlobBuilder::RunBuffer& buff = fBuilder->allocRunPos(fFont, fBuffIdx);
+    memcpy(buff.glyphs, fGlyphIds, fBuffIdx * sizeof(uint16_t));
+    memcpy(buff.pos, fPositions[0].asScalars(), fBuffIdx * 2 * sizeof(SkScalar));
+    fBuffIdx = 0;
+}
+
+const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfInitialized() {
+    if (!this->isInitialized()) {
+        return nullptr;
+    }
+    this->flush();
+    return fBuilder->build();
+}
diff --git a/src/gpu/GrStencilAndCoverTextContext.h b/src/gpu/GrStencilAndCoverTextContext.h
index c5c29ad..9e85e89 100644
--- a/src/gpu/GrStencilAndCoverTextContext.h
+++ b/src/gpu/GrStencilAndCoverTextContext.h
@@ -45,6 +45,8 @@
                        const SkScalar pos[], int scalarsPerPosition,
                        const SkPoint& offset, const SkIRect& regionClipBounds) override;
 
+    class FallbackBlobBuilder;
+
     class TextRun {
     public:
         TextRun(const SkPaint& fontAndStroke);
@@ -64,7 +66,7 @@
     private:
         GrPathRange* createGlyphs(GrContext*, SkGlyphCache*);
 
-        void appendGlyph(const SkGlyph&, const SkPoint&);
+        void appendGlyph(const SkGlyph&, const SkPoint&, FallbackBlobBuilder*);
 
         GrStrokeInfo                     fStroke;
         SkPaint                          fFont;
@@ -73,8 +75,7 @@
         SkMatrix                         fLocalMatrix;
         bool                             fUsingRawGlyphPaths;
         SkAutoTUnref<GrPathRangeDraw>    fDraw;
-        SkSTArray<32, uint16_t, true>    fFallbackIndices;
-        SkSTArray<32, SkPoint, true>     fFallbackPositions;
+        SkAutoTUnref<const SkTextBlob>   fFallbackTextBlob;
     };
 
     typedef GrTextContext INHERITED;