Remove drawTextBlob from device use drawGlyphRunList

Convert all backends to use GlyphRunList instead of
text blobs. If the device did not originally implement
drawTextBlob it will be simulated by drawPosText on the
device.

Other changes:
Change to using an origin from absolulte positioning. The GPU
code uses origin change to update blobs under translation.

Change cluster to use const uint32_t instead of just
uint32_t.

Add SkPaint to runs.

The draw filter is hosted up to the canavas level and applied there.

Change-Id: Ib105b6bd26b67db55f1c954e37c79fbdcaa9d4a2
Reviewed-on: https://skia-review.googlesource.com/137224
Reviewed-by: Herb Derby <herb@google.com>
Reviewed-by: Khusal Sagar <khushalsagar@chromium.org>
Reviewed-by: Hal Canary <halcanary@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/src/gpu/text/GrTextContext.cpp b/src/gpu/text/GrTextContext.cpp
index a20ba44..3309d22 100644
--- a/src/gpu/text/GrTextContext.cpp
+++ b/src/gpu/text/GrTextContext.cpp
@@ -84,58 +84,48 @@
     }
 }
 
-// TODO if this function ever shows up in profiling, then we can compute this value when the
-// textblob is being built and cache it.  However, for the time being textblobs mostly only have 1
-// run so this is not a big deal to compute here.
-bool GrTextContext::HasLCD(const SkTextBlob* blob) {
-    SkTextBlobRunIterator it(blob);
-    for (; !it.done(); it.next()) {
-        if (it.isLCD()) {
-            return true;
-        }
-    }
-    return false;
-}
+void GrTextContext::drawGlyphRunList(
+        GrContext* context, GrTextUtils::Target* target, const GrClip& clip,
+        const SkMatrix& viewMatrix, const SkSurfaceProps& props, SkGlyphRunList* glyphRunList,
+        const SkIRect& clipBounds) {
+    SkPoint origin = glyphRunList->origin();
 
-void GrTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* target,
-                                 const GrClip& clip, const SkPaint& skPaint,
-                                 const SkMatrix& viewMatrix, const SkSurfaceProps& props,
-                                 const SkTextBlob* blob, SkScalar x, SkScalar y,
-                                 SkDrawFilter* drawFilter, const SkIRect& clipBounds) {
+    // Get the first paint to use as the key paint.
+    const SkPaint& skPaint = (*glyphRunList)[0].paint();
+
     // If we have been abandoned, then don't draw
     if (context->abandoned()) {
         return;
     }
 
-    sk_sp<GrTextBlob> cacheBlob;
     SkMaskFilterBase::BlurRec blurRec;
-    GrTextBlob::Key key;
     // It might be worth caching these things, but its not clear at this time
     // TODO for animated mask filters, this will fill up our cache.  We need a safeguard here
     const SkMaskFilter* mf = skPaint.getMaskFilter();
-    bool canCache = !(skPaint.getPathEffect() ||
-                      (mf && !as_MFB(mf)->asABlur(&blurRec)) ||
-                      drawFilter);
+    bool canCache = glyphRunList->canCache() && !(skPaint.getPathEffect() ||
+                      (mf && !as_MFB(mf)->asABlur(&blurRec)));
     SkScalerContextFlags scalerContextFlags = ComputeScalerContextFlags(target->colorSpaceInfo());
 
     auto glyphCache = context->contextPriv().getGlyphCache();
     GrTextBlobCache* textBlobCache = context->contextPriv().getTextBlobCache();
 
+    sk_sp<GrTextBlob> cacheBlob;
+    GrTextBlob::Key key;
     if (canCache) {
-        bool hasLCD = HasLCD(blob);
+        bool hasLCD = glyphRunList->anyRunsLCD();
 
         // We canonicalize all non-lcd draws to use kUnknown_SkPixelGeometry
         SkPixelGeometry pixelGeometry = hasLCD ? props.pixelGeometry() :
-                                                 kUnknown_SkPixelGeometry;
+                                        kUnknown_SkPixelGeometry;
 
         // TODO we want to figure out a way to be able to use the canonical color on LCD text,
         // see the note on ComputeCanonicalColor above.  We pick a dummy value for LCD text to
         // ensure we always match the same key
         GrColor canonicalColor = hasLCD ? SK_ColorTRANSPARENT :
-                                          ComputeCanonicalColor(skPaint, hasLCD);
+                                 ComputeCanonicalColor(skPaint, hasLCD);
 
         key.fPixelGeometry = pixelGeometry;
-        key.fUniqueID = blob->uniqueID();
+        key.fUniqueID = glyphRunList->uniqueID();
         key.fStyle = skPaint.getStyle();
         key.fHasBlur = SkToBool(mf);
         key.fCanonicalColor = canonicalColor;
@@ -145,135 +135,77 @@
 
     GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo());
     if (cacheBlob) {
-        if (cacheBlob->mustRegenerate(paint, blurRec, viewMatrix, x, y)) {
+        if (cacheBlob->mustRegenerate(paint, blurRec, viewMatrix, origin.x(), origin.y())) {
             // We have to remake the blob because changes may invalidate our masks.
             // TODO we could probably get away reuse most of the time if the pointer is unique,
             // but we'd have to clear the subrun information
             textBlobCache->remove(cacheBlob.get());
-            cacheBlob = textBlobCache->makeCachedBlob(blob, key, blurRec, skPaint);
-            this->regenerateTextBlob(cacheBlob.get(), glyphCache,
+            cacheBlob = textBlobCache->makeCachedBlob(glyphRunList, key, blurRec, skPaint);
+            this->regenerateGlyphRunList(cacheBlob.get(), glyphCache,
                                      *context->contextPriv().caps()->shaderCaps(), paint,
-                                     scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter);
+                                     scalerContextFlags, viewMatrix, props, glyphRunList);
         } else {
             textBlobCache->makeMRU(cacheBlob.get());
 
             if (CACHE_SANITY_CHECK) {
-                int glyphCount = 0;
-                int runCount = 0;
-                GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob);
+                int glyphCount = glyphRunList->totalGlyphCount();
+                int runCount = glyphRunList->runCount();
                 sk_sp<GrTextBlob> sanityBlob(textBlobCache->makeBlob(glyphCount, runCount));
                 sanityBlob->setupKey(key, blurRec, skPaint);
-                this->regenerateTextBlob(
+                this->regenerateGlyphRunList(
                         sanityBlob.get(), glyphCache, *context->contextPriv().caps()->shaderCaps(),
-                        paint, scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter);
+                        paint, scalerContextFlags, viewMatrix, props, glyphRunList);
                 GrTextBlob::AssertEqual(*sanityBlob, *cacheBlob);
             }
         }
     } else {
         if (canCache) {
-            cacheBlob = textBlobCache->makeCachedBlob(blob, key, blurRec, skPaint);
+            cacheBlob = textBlobCache->makeCachedBlob(glyphRunList, key, blurRec, skPaint);
         } else {
-            cacheBlob = textBlobCache->makeBlob(blob);
+            cacheBlob = textBlobCache->makeBlob(glyphRunList);
         }
-        this->regenerateTextBlob(cacheBlob.get(), glyphCache,
+        this->regenerateGlyphRunList(cacheBlob.get(), glyphCache,
                                  *context->contextPriv().caps()->shaderCaps(), paint,
-                                 scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter);
+                                 scalerContextFlags, viewMatrix, props, glyphRunList);
     }
 
     cacheBlob->flush(target, props, fDistanceAdjustTable.get(), paint,
-                     clip, viewMatrix, clipBounds, x, y);
+                     clip, viewMatrix, clipBounds, origin.x(), origin.y());
 }
 
-void GrTextContext::regenerateTextBlob(GrTextBlob* cacheBlob,
+void GrTextContext::regenerateGlyphRunList(GrTextBlob* cacheBlob,
                                        GrGlyphCache* glyphCache,
                                        const GrShaderCaps& shaderCaps,
                                        const GrTextUtils::Paint& paint,
                                        SkScalerContextFlags scalerContextFlags,
                                        const SkMatrix& viewMatrix,
-                                       const SkSurfaceProps& props, const SkTextBlob* blob,
-                                       SkScalar x, SkScalar y,
-                                       SkDrawFilter* drawFilter) const {
-    cacheBlob->initReusableBlob(paint.luminanceColor(), viewMatrix, x, y);
+                                       const SkSurfaceProps& props,
+                                       SkGlyphRunList* glyphRunList) const {
+    SkPoint origin = glyphRunList->origin();
+    cacheBlob->initReusableBlob(paint.luminanceColor(), viewMatrix, origin.x(), origin.y());
 
     // Regenerate textblob
-    SkTextBlobRunIterator it(blob);
-    GrTextUtils::RunPaint runPaint(&paint, drawFilter);
+    SkGlyphRunListIterator it(glyphRunList);
+    GrTextUtils::RunPaint runPaint(&paint, nullptr);
     for (int run = 0; !it.done(); it.next(), run++) {
         int glyphCount = it.glyphCount();
         size_t textLen = glyphCount * sizeof(uint16_t);
-        const SkPoint& offset = it.offset();
         cacheBlob->push_back_run(run);
         if (!runPaint.modifyForRun([it](SkPaint* p) { it.applyFontToPaint(p); })) {
             continue;
         }
         cacheBlob->setRunPaintFlags(run, runPaint.skPaint().getFlags());
 
+        SkASSERT(it.positioning() == SkTextBlob::kFull_Positioning);
         if (CanDrawAsDistanceFields(runPaint, viewMatrix, props,
                                     shaderCaps.supportsDistanceFieldText(), fOptions)) {
-            switch (it.positioning()) {
-                case SkTextBlob::kDefault_Positioning: {
-                    auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
-                    SkGlyphRunBuilder builder;
-                    builder.prepareDrawText(runPaint.skPaint(),
-                                            (const char*)it.glyphs(), textLen, origin);
-
-                    auto glyphRun = builder.useGlyphRun();
-
-                    glyphRun->temporaryShuntToCallback(
-                            [&](size_t runSize, const char* glyphIDs, const SkScalar* pos) {
-                                this->drawDFPosText(
-                                    cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
-                                    viewMatrix, glyphIDs, 2 * runSize, pos, 2,
-                                    SkPoint::Make(0,0));
-                            });
-                    break;
-                }
-
-                case SkTextBlob::kHorizontal_Positioning: {
-                    SkPoint dfOffset = SkPoint::Make(x, y + offset.y());
-                    this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint,
-                                        scalerContextFlags, viewMatrix, (const char*)it.glyphs(),
-                                        textLen, it.pos(), 1, dfOffset);
-                    break;
-                }
-                case SkTextBlob::kFull_Positioning: {
-                    SkPoint dfOffset = SkPoint::Make(x, y);
-                    this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint,
-                                        scalerContextFlags, viewMatrix, (const char*)it.glyphs(),
-                                        textLen, it.pos(), 2, dfOffset);
-                    break;
-                }
-            }
+            this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint,
+                                scalerContextFlags, viewMatrix, (const char*)it.glyphs(),
+                                textLen, it.pos(), 2, origin);
         } else {
-            switch (it.positioning()) {
-                case SkTextBlob::kDefault_Positioning: {
-                    auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
-                    SkGlyphRunBuilder builder;
-                    builder.prepareDrawText(runPaint.skPaint(),
-                                            (const char*)it.glyphs(), textLen, origin);
-
-                    auto glyphRun = builder.useGlyphRun();
-
-                    glyphRun->temporaryShuntToCallback(
-                            [&](size_t runSize, const char* glyphIDs, const SkScalar* pos) {
-                                this->DrawBmpPosText(
-                                    cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
-                                    viewMatrix, glyphIDs, 2 * runSize,
-                                    pos, 2, SkPoint::Make(0, 0));
-                            });
-                    break;
-                }
-                case SkTextBlob::kHorizontal_Positioning:
-                    DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
-                                   viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 1,
-                                   SkPoint::Make(x, y + offset.y()));
-                    break;
-                case SkTextBlob::kFull_Positioning:
-                    DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
-                                   viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2,
-                                   SkPoint::Make(x, y));
-                    break;
-            }
+            DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
+                           viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2,
+                           origin);
         }
     }
 }
@@ -333,7 +265,6 @@
     }
 }
 
-
 void GrTextContext::DrawBmpPosText(GrTextBlob* blob, int runIndex,
                                    GrGlyphCache* glyphCache, const SkSurfaceProps& props,
                                    const GrTextUtils::Paint& paint,
@@ -786,6 +717,7 @@
     builder.prepareDrawText(skPaint, text, textLen, origin);
     sk_sp<GrTextBlob> blob;
 
+    // TODO - remove shunt call when removing drawPosText from device.
     auto glyphRun = builder.useGlyphRun();
     // Use the text and textLen below, because we don't want to mess with the paint.
     glyphRun->temporaryShuntToCallback(