Revert "Remove drawTextBlob from device use drawGlyphRunList"

This reverts commit e2e52e46ca63540d429656baeee48fd3a402be26.

Reason for revert: See if this is blocking the Chrome roll

Original change's description:
> 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>

TBR=jvanverth@google.com,halcanary@google.com,bungeman@google.com,herb@google.com,reed@google.com,khushalsagar@chromium.org,khushalsagar@google.com

Change-Id: I4d93a534990c89deee7d3aaa00ec40d47e0d2ece
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/138120
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/include/core/SkTextBlob.h b/include/core/SkTextBlob.h
index 9f4f10f..59151d3 100644
--- a/include/core/SkTextBlob.h
+++ b/include/core/SkTextBlob.h
@@ -14,7 +14,6 @@
 #include "SkString.h"
 #include "SkRefCnt.h"
 
-class SkGlyphRunList;
 class SkReadBuffer;
 class SkWriteBuffer;
 
@@ -111,7 +110,6 @@
         fCacheID.store(cacheID);
     }
 
-    friend class SkGlyphRunList;
     friend class GrTextBlobCache;
     friend class SkTextBlobBuilder;
     friend class SkTextBlobRunIterator;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index c590d77..b297f98 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -2453,7 +2453,8 @@
     while (iter.next()) {
         fScratchGlyphRunBuilder->prepareDrawText(
                 looper.paint(), text, byteLength, SkPoint::Make(x, y));
-        fScratchGlyphRunBuilder->draw(iter.fDevice);
+        auto glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
+        iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
     }
 
     LOOPER_END
@@ -2466,7 +2467,8 @@
 
     while (iter.next()) {
         fScratchGlyphRunBuilder->prepareDrawPosText(looper.paint(), text, byteLength, pos);
-        fScratchGlyphRunBuilder->draw(iter.fDevice);
+        auto glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
+        iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
     }
 
     LOOPER_END
@@ -2480,7 +2482,8 @@
     while (iter.next()) {
         fScratchGlyphRunBuilder->prepareDrawPosTextH(
                 looper.paint(), text, byteLength, xpos, constY);
-        fScratchGlyphRunBuilder->draw(iter.fDevice);
+        const auto& glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
+        iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
     }
 
     LOOPER_END
@@ -2533,9 +2536,7 @@
     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
 
     while (iter.next()) {
-        fScratchGlyphRunBuilder->prepareTextBlob(
-                looper.paint(), *blob, SkPoint::Make(x, y), drawFilter);
-        fScratchGlyphRunBuilder->draw(iter.fDevice);
+        iter.fDevice->drawTextBlob(blob, x, y, looper.paint(), drawFilter);
     }
 
     LOOPER_END
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 9fd61c9..46404b2 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -141,6 +141,53 @@
     }
 }
 
+void SkBaseDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+                                const SkPaint &paint, SkDrawFilter* drawFilter) {
+
+    SkPaint runPaint = paint;
+
+    SkTextBlobRunIterator it(blob);
+    for (;!it.done(); it.next()) {
+        size_t textLen = it.glyphCount() * sizeof(uint16_t);
+        const SkPoint& offset = it.offset();
+        // applyFontToPaint() always overwrites the exact same attributes,
+        // so it is safe to not re-seed the paint for this reason.
+        it.applyFontToPaint(&runPaint);
+
+        if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) {
+            // A false return from filter() means we should abort the current draw.
+            runPaint = paint;
+            continue;
+        }
+
+        switch (it.positioning()) {
+        case SkTextBlob::kDefault_Positioning: {
+            auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
+            SkGlyphRunBuilder builder;
+            builder.prepareDrawText(runPaint, (const char*) it.glyphs(), textLen, origin);
+            auto glyphRun = builder.useGlyphRun();
+            glyphRun->temporaryShuntToDrawPosText(runPaint, this);
+        }
+        break;
+        case SkTextBlob::kHorizontal_Positioning:
+            this->drawPosText(it.glyphs(), textLen, it.pos(), 1,
+                              SkPoint::Make(x, y + offset.y()), runPaint);
+            break;
+        case SkTextBlob::kFull_Positioning:
+            this->drawPosText(it.glyphs(), textLen, it.pos(), 2,
+                              SkPoint::Make(x, y), runPaint);
+            break;
+        default:
+            SK_ABORT("unhandled positioning mode");
+        }
+
+        if (drawFilter) {
+            // A draw filter may change the paint arbitrarily, so we must re-seed in this case.
+            runPaint = paint;
+        }
+    }
+}
+
 void SkBaseDevice::drawImage(const SkImage* image, SkScalar x, SkScalar y,
                              const SkPaint& paint) {
     SkBitmap bm;
@@ -205,10 +252,11 @@
     }
 }
 
-void SkBaseDevice::drawGlyphRunList(SkGlyphRunList* glyphRunList) {
-    for (auto& glyphRun : *glyphRunList) {
-        glyphRun.temporaryShuntToDrawPosText(this, glyphRunList->origin());
-    }
+void SkBaseDevice::drawGlyphRun(const SkPaint& paint, SkGlyphRun* glyphRun) {
+    SkPaint glyphPaint(paint);
+    glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+    glyphRun->temporaryShuntToDrawPosText(glyphPaint, this);
 }
 
 void SkBaseDevice::drawBitmapLattice(const SkBitmap& bitmap,
diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h
index 9a4086e..f840cf6 100644
--- a/src/core/SkDevice.h
+++ b/src/core/SkDevice.h
@@ -18,7 +18,6 @@
 class SkDrawFilter;
 struct SkDrawShadowRec;
 class SkGlyphRun;
-class SkGlyphRunList;
 class SkGlyphRunBuilder;
 class SkImageFilterCache;
 struct SkIRect;
@@ -225,10 +224,13 @@
      *  Does not handle text decoration.
      *  Decorations (underline and stike-thru) will be handled by SkCanvas.
      */
-    virtual void drawGlyphRunList(SkGlyphRunList* glyphRunList);
+    virtual void drawGlyphRun(const SkPaint& paint, SkGlyphRun* glyphRun);
     virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) = 0;
     virtual void drawShadow(const SkPath&, const SkDrawShadowRec&);
 
+    // default implementation unrolls the blob runs.
+    virtual void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
+                              const SkPaint& paint, SkDrawFilter* drawFilter);
     // default implementation calls drawVertices
     virtual void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
                            const SkPoint texCoords[4], SkBlendMode, bool interpColorsLinearly,
@@ -347,7 +349,6 @@
 
     // Temporarily friend the SkGlyphRunBuilder until drawPosText is gone.
     friend class SkGlyphRun;
-    friend class SkGlyphRunBuilder;
     virtual void drawPosText(const void* text, size_t len,
                              const SkScalar pos[], int scalarsPerPos,
                              const SkPoint& offset, const SkPaint& paint) = 0;
diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp
index 583d676..ce1c336 100644
--- a/src/core/SkGlyphRun.cpp
+++ b/src/core/SkGlyphRun.cpp
@@ -12,7 +12,7 @@
 #include <tuple>
 
 #include "SkDevice.h"
-#include "SkDrawFilter.h"
+#include "SkDraw.h"
 #include "SkGlyphCache.h"
 #include "SkMSAN.h"
 #include "SkMakeUnique.h"
@@ -90,23 +90,22 @@
                        size_t uniqueOffset, uint16_t uniqueSize,
                        SkSpan<SkGlyphID>  scratchGlyphs,
                        SkSpan<const char> text,
-                       SkSpan<const uint32_t> clusters,
-                       SkPaint&&          runPaint)
+                       SkSpan<uint32_t>   clusters)
         : fRunInfo{runInfo}
         , fDenseOffset{denseOffset}, fDenseSize{denseSize}
         , fUniqueOffset{uniqueOffset}, fUniqueSize{uniqueSize}
         , fTemporaryShuntGlyphIDs{scratchGlyphs}
         , fText{text}
-        , fClusters{clusters}
-        , fRunPaint{std::move(runPaint)} {}
+        , fClusters{clusters} { }
 
-void SkGlyphRun::temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin) {
+
+void SkGlyphRun::temporaryShuntToDrawPosText(const SkPaint& paint, SkBaseDevice* device) {
 
     auto pos = (const SkScalar*) this->positions().data();
 
     device->drawPosText(
             fTemporaryShuntGlyphIDs.data(), fDenseSize * sizeof(SkGlyphID),
-            pos, 2, origin, fRunPaint);
+            pos, 2, SkPoint::Make(0, 0), paint);
 }
 
 void SkGlyphRun::temporaryShuntToCallback(TemporaryShuntCallback callback) {
@@ -116,40 +115,19 @@
 }
 
 // -- SkGlyphRunList -------------------------------------------------------------------------------
-SkGlyphRunList::SkGlyphRunList(
-        SkSpan<SkGlyphRun> glyphRuns, SkPoint origin, const SkTextBlob* textBlob)
-        : fGlyphRuns{glyphRuns}
-        , fOrigin{origin}
-        , fTemporaryTextBlobShunt{textBlob} { }
-
-uint64_t SkGlyphRunList::uniqueID() const {
-    return fTemporaryTextBlobShunt != nullptr ? fTemporaryTextBlobShunt->uniqueID()
-                                              : SK_InvalidUniqueID;
-}
-
-bool SkGlyphRunList::anyRunsLCD() const {
-    for (const auto& r : fGlyphRuns) {
-        if (r.paint().isLCDRenderText()) {
-            return true;
-        }
-    }
-    return false;
-}
-
-void SkGlyphRunList::temporaryShuntBlobnotifyAddedToCache(uint32_t cacheID) const {
-    SkASSERT(fTemporaryTextBlobShunt != nullptr);
-    fTemporaryTextBlobShunt->notifyAddedToCache(cacheID);
-}
-
-// -- SkGlyphRunListIterator -----------------------------------------------------------------------
-constexpr SkPoint SkGlyphRunListIterator::fZero;
+SkGlyphRunList::SkGlyphRunList(SkSpan<SkGlyphRun> glyphRuns, uint64_t uniqueID)
+        : fUniqueID{uniqueID}
+        , fGlyphRuns{glyphRuns} { }
 
 // -- SkGlyphRunBuilder ----------------------------------------------------------------------------
 void SkGlyphRunBuilder::prepareDrawText(
         const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin) {
     this->initialize();
-    this->drawText(
-            paint, bytes, byteLength, origin, SkSpan<const char>(), SkSpan<const uint32_t>());
+    SkSpan<const char> originalText((const char*)bytes, byteLength);
+    if (paint.getTextEncoding() != SkPaint::kUTF8_TextEncoding) {
+        originalText = SkSpan<const char>();
+    }
+    this->drawText(paint, bytes, byteLength, origin, originalText, SkSpan<uint32_t>());
 }
 
 void SkGlyphRunBuilder::prepareDrawPosTextH(const SkPaint& paint, const void* bytes,
@@ -157,22 +135,19 @@
                                             SkScalar constY) {
     this->initialize();
     this->drawPosTextH(
-            paint, bytes, byteLength, xpos, constY,
-            SkSpan<const char>(), SkSpan<const uint32_t>());
+            paint, bytes, byteLength, xpos, constY, SkSpan<const char>(), SkSpan<uint32_t>());
 }
 
 void SkGlyphRunBuilder::prepareDrawPosText(const SkPaint& paint, const void* bytes,
                                            size_t byteLength, const SkPoint* pos) {
     this->initialize();
-    this->drawPosText(paint, bytes, byteLength, pos,
-            SkSpan<const char>(), SkSpan<const uint32_t>());
+    this->drawPosText(paint, bytes, byteLength, pos, SkSpan<const char>(), SkSpan<uint32_t>());
 }
 
 void SkGlyphRunBuilder::prepareTextBlob(
-        const SkPaint& paint, const SkTextBlob& blob, SkPoint origin, SkDrawFilter* drawFilter) {
+        const SkPaint& paint, const SkTextBlob& blob, SkPoint origin) {
     this->initialize();
-    fTemporaryTextBlobShunt = &blob;
-    fOrigin = origin;
+    fUniqueID = blob.uniqueID();
 
     SkPaint runPaint = paint;
 
@@ -181,44 +156,33 @@
         // so it is safe to not re-seed the paint for this reason.
         it.applyFontToPaint(&runPaint);
 
-        if (drawFilter != nullptr && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) {
-            // A false return from filter() means we should abort the current draw.
-            runPaint = paint;
-            continue;
-        }
-
         // These better be glyphs
         SkASSERT(runPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
 
         auto text = SkSpan<const char>(it.text(), it.textSize());
-        auto clusters = SkSpan<const uint32_t>(it.clusters(), it.glyphCount());
+        auto clusters = SkSpan<uint32_t>(it.clusters(), it.glyphCount());
         size_t glyphLen = it.glyphCount() * sizeof(SkGlyphID);
         const SkPoint& offset = it.offset();
 
         switch (it.positioning()) {
             case SkTextBlob::kDefault_Positioning: {
-                this->drawText(runPaint, it.glyphs(), glyphLen, offset, text, clusters);
+                auto dtOrigin = origin + offset;
+                this->drawText(runPaint, it.glyphs(), glyphLen, dtOrigin, text, clusters);
             }
             break;
             case SkTextBlob::kHorizontal_Positioning: {
-                auto constY = offset.y();
+                auto constY = origin.y() + offset.y();
                 this->drawPosTextH(
                         runPaint, it.glyphs(), glyphLen, it.pos(), constY, text, clusters);
             }
             break;
             case SkTextBlob::kFull_Positioning:
                 this->drawPosText(
-                        runPaint, it.glyphs(), glyphLen, (const SkPoint*)it.pos(), text,
-                        clusters);
+                        runPaint, it.glyphs(), glyphLen, (const SkPoint*)it.pos(), text, clusters);
             break;
             default:
                 SK_ABORT("unhandled positioning mode");
         }
-
-        if (drawFilter != nullptr) {
-            // A draw filter may change the paint arbitrarily, so we must re-seed in this case.
-            runPaint = paint;
-        }
     }
 }
 
@@ -229,29 +193,22 @@
 }
 
 SkGlyphRunList* SkGlyphRunBuilder::useGlyphRunList() {
-    new ((void*)&fScratchGlyphRunList)
-        SkGlyphRunList{SkSpan<SkGlyphRun>(fGlyphRuns), fOrigin, fTemporaryTextBlobShunt};
+    new ((void*)&fScratchGlyphRunList) SkGlyphRunList{SkSpan<SkGlyphRun>(fGlyphRuns), fUniqueID};
     return &fScratchGlyphRunList;
 }
 
-void SkGlyphRunBuilder::draw(SkBaseDevice* device) {
-    auto glyphRunList = this->useGlyphRunList();
-    device->drawGlyphRunList(glyphRunList);
-}
-
 size_t SkGlyphRunBuilder::runSize() const { return fDenseIndex.size() - fLastDenseIndex; }
 
 size_t SkGlyphRunBuilder::uniqueSize() const { return fUniqueGlyphIDs.size() - fLastUniqueIndex; }
 
 void SkGlyphRunBuilder::initialize() {
-    fTemporaryTextBlobShunt = nullptr;
+    fUniqueID = 0;
     fDenseIndex.clear();
     fPositions.clear();
     fUniqueGlyphIDs.clear();
     fGlyphRuns.clear();
     fLastDenseIndex = 0;
     fLastUniqueIndex = 0;
-    fOrigin = {0, 0};
 }
 
 SkGlyphID* SkGlyphRunBuilder::addDenseAndUnique(
@@ -288,19 +245,10 @@
 }
 
 void SkGlyphRunBuilder::addGlyphRunToList(
-        const SkPaint& runPaint,
-        SkGlyphID* temporaryShuntGlyphIDs,
-        SkSpan<const char> text,
-        SkSpan<const uint32_t> clusters) {
+        SkGlyphID* temporaryShuntGlyphIDs, SkSpan<const char> text, SkSpan<uint32_t> clusters) {
 
     // Ignore empty runs.
     if (fDenseIndex.size() != fLastDenseIndex) {
-        SkPaint modifiedRunPaint{runPaint};
-
-        // TODO: remove these once the text stack has all the encoding and align code removed.
-        modifiedRunPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-        modifiedRunPaint.setTextAlign(SkPaint::kLeft_Align);
-
         auto runSize = this->runSize();
         auto uniqueSize = this->uniqueSize();
 
@@ -310,8 +258,7 @@
                 fLastUniqueIndex, SkTo<uint16_t>(uniqueSize),
                 SkSpan<SkGlyphID>(temporaryShuntGlyphIDs, runSize),
                 text,
-                clusters,
-                std::move(modifiedRunPaint));
+                clusters);
 
         fLastDenseIndex = fDenseIndex.size();
         fLastUniqueIndex = fUniqueGlyphIDs.size();
@@ -320,7 +267,7 @@
 
 void SkGlyphRunBuilder::drawText(
         const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin,
-        SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
+        SkSpan<const char> text, SkSpan<uint32_t> clusters) {
 
     SkGlyphID* temporaryShuntGlyphIDs = this->addDenseAndUnique(paint, bytes, byteLength);
 
@@ -339,22 +286,22 @@
     }
 
     if (paint.getTextAlign() != SkPaint::kLeft_Align) {
-        SkVector runWidth = endOfLastGlyph - origin;
+        SkVector len = endOfLastGlyph - origin;
         if (paint.getTextAlign() == SkPaint::kCenter_Align) {
-            runWidth.scale(SK_ScalarHalf);
+            len.scale(SK_ScalarHalf);
         }
         for (size_t i = fLastDenseIndex; i < this->runSize(); i++) {
-            fPositions[i] -= runWidth;
+            fPositions[i] -= len;
         }
     }
 
-    this->addGlyphRunToList(paint, temporaryShuntGlyphIDs, text, clusters);
+    this->addGlyphRunToList(temporaryShuntGlyphIDs, text, clusters);
 }
 
-void SkGlyphRunBuilder::drawPosTextH(
-        const SkPaint& paint, const void* bytes, size_t byteLength,
-        const SkScalar* xpos, SkScalar constY,
-        SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
+void SkGlyphRunBuilder::drawPosTextH(const SkPaint& paint, const void* bytes,
+                                     size_t byteLength, const SkScalar* xpos,
+                                     SkScalar constY,
+                                     SkSpan<const char> text, SkSpan<uint32_t> clusters) {
 
     SkGlyphID* temporaryShuntGlyphIDs = this->addDenseAndUnique(paint, bytes, byteLength);
 
@@ -362,20 +309,19 @@
         fPositions.push_back(SkPoint::Make(xpos[i], constY));
     }
 
-    this->addGlyphRunToList(paint, temporaryShuntGlyphIDs, text, clusters);
+    this->addGlyphRunToList(temporaryShuntGlyphIDs, text, clusters);
 }
 
-void SkGlyphRunBuilder::drawPosText(
-        const SkPaint& paint, const void* bytes,
-        size_t byteLength, const SkPoint* pos,
-        SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
+void SkGlyphRunBuilder::drawPosText(const SkPaint& paint, const void* bytes,
+                                    size_t byteLength, const SkPoint* pos,
+                                    SkSpan<const char> text, SkSpan<uint32_t> clusters) {
     SkGlyphID* temporaryShuntGlyphIDs = this->addDenseAndUnique(paint, bytes, byteLength);
 
     for (size_t i = 0; i < runSize(); i++) {
         fPositions.push_back(pos[i]);
     }
 
-    this->addGlyphRunToList(paint, temporaryShuntGlyphIDs, text, clusters);
+    this->addGlyphRunToList(temporaryShuntGlyphIDs, text, clusters);
 }
 
 
diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h
index 6f9041c..739ad0b 100644
--- a/src/core/SkGlyphRun.h
+++ b/src/core/SkGlyphRun.h
@@ -16,11 +16,9 @@
 #include "SkMask.h"
 #include "SkPath.h"
 #include "SkPoint.h"
-#include "SkTextBlob.h"
 #include "SkTypes.h"
 
 class SkBaseDevice;
-class SkDrawFilter;
 
 template <typename T>
 class SkSpan {
@@ -76,12 +74,11 @@
                size_t fUniqueOffset, uint16_t fUniqueSize,
                SkSpan<SkGlyphID>  scratchGlyphs,
                SkSpan<const char> text,
-               SkSpan<const uint32_t>   clusters,
-               SkPaint&&          runPaint);
+               SkSpan<uint32_t>   clusters);
 
     // The temporaryShunt calls are to allow inter-operating with existing code while glyph runs
     // are developed.
-    void temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin);
+    void temporaryShuntToDrawPosText(const SkPaint& paint, SkBaseDevice* device);
     using TemporaryShuntCallback = std::function<void(size_t, const char*, const SkScalar*)>;
     void temporaryShuntToCallback(TemporaryShuntCallback callback);
 
@@ -93,21 +90,6 @@
     SkSpan<const SkGlyphID> uniqueGlyphIDs() const {
         return fRunInfo.uniqueGlyphIDs(fUniqueOffset, fUniqueSize);
     }
-    SkSpan<SkGlyphID> shuntGlyphsIDs() const {
-        return fTemporaryShuntGlyphIDs;
-    }
-
-    const SkPaint& paint() const {
-        return fRunPaint;
-    }
-
-    SkSpan<const uint32_t> clusters() const {
-        return fClusters;
-    }
-
-    SkSpan<const char> text() const {
-        return fText;
-    }
 
 private:
     const SkIndexedRunInfo& fRunInfo;
@@ -121,39 +103,18 @@
     // Original text from SkTextBlob if present. Will be empty of not present.
     const SkSpan<const char> fText;
     // Original clusters from SkTextBlob if present. Will be empty if not present.
-    const SkSpan<const uint32_t>   fClusters;
-    // Paint for this run modified to have glyph encoding and left alignment.
-    const SkPaint fRunPaint;
+    const SkSpan<uint32_t>   fClusters;
 };
 
 class SkGlyphRunList {
+    const uint64_t     fUniqueID{0};
     SkSpan<SkGlyphRun> fGlyphRuns;
-    SkPoint            fOrigin = {0, 0};
-
-    // The text blob is needed to hookup the call back that the SkTextBlob destructor calls. It
-    // should be used for nothing else
-    const SkTextBlob*  fTemporaryTextBlobShunt{nullptr};
 
 public:
     SkGlyphRunList() = default;
-    // Blob maybe null.
-    SkGlyphRunList(SkSpan<SkGlyphRun> glyphRuns, SkPoint origin, const SkTextBlob* blob);
+    SkGlyphRunList(SkSpan<SkGlyphRun> glyphRuns, uint64_t uniqueID);
 
-    uint64_t uniqueID() const;
-    bool anyRunsLCD() const;
-    void temporaryShuntBlobnotifyAddedToCache(uint32_t cacheID) const;
-
-    bool canCache() const { return fTemporaryTextBlobShunt != nullptr; }
-    ptrdiff_t runCount() const { return fGlyphRuns.size(); }
-    size_t totalGlyphCount() const {
-        size_t glyphCount = 0;
-        for(const auto& run : fGlyphRuns) {
-            glyphCount += run.runSize();
-        }
-        return glyphCount;
-    }
-
-    SkPoint origin() const { return fOrigin; }
+    uint64_t uniqueID() const { return fUniqueID; }
 
     auto begin() -> decltype(fGlyphRuns.begin())               { return fGlyphRuns.begin(); }
     auto end()   -> decltype(fGlyphRuns.end())                 { return fGlyphRuns.end();   }
@@ -161,30 +122,6 @@
     auto operator [] (ptrdiff_t i) -> decltype(fGlyphRuns[i])  { return fGlyphRuns[i];      }
 };
 
-class SkGlyphRunListIterator {
-public:
-    explicit SkGlyphRunListIterator(SkGlyphRunList* list) : fList{*list} {}
-
-    bool done() const { return fIndex == fList.size(); }
-    void next() { fIndex += 1;}
-    uint32_t glyphCount() const { return fList[fIndex].runSize(); }
-    const uint16_t* glyphs() const { return fList[fIndex].shuntGlyphsIDs().data(); }
-    const SkScalar* pos() const { return (const SkScalar*)fList[fIndex].positions().data(); }
-    const SkPoint& offset() const { return fZero; }
-    void applyFontToPaint(SkPaint* paint) const { *paint = fList[fIndex].paint(); }
-    SkTextBlob::GlyphPositioning positioning() const { return SkTextBlob::kFull_Positioning; }
-    const uint32_t* clusters() const { return fList[fIndex].clusters().data(); }
-    uint32_t textSize() const { return fList[fIndex].text().size(); }
-    const char* text() const { return fList[fIndex].text().data(); }
-
-    bool isLCD() const { return fList[fIndex].paint().isLCDRenderText(); }
-
-private:
-    static constexpr SkPoint fZero{0,0};
-    ptrdiff_t fIndex{0};
-    SkGlyphRunList& fList;
-};
-
 // A faster set implementation that does not need any initialization, and reading the set items
 // is order the number of items, and not the size of the universe.
 // This implementation is based on the paper by Briggs and Torczon, "An Efficient Representation
@@ -217,14 +154,10 @@
             const SkScalar xpos[], SkScalar constY);
     void prepareDrawPosText(
             const SkPaint& paint, const void* bytes, size_t byteLength, const SkPoint pos[]);
-    void prepareTextBlob(
-            const SkPaint& paint, const SkTextBlob& blob, SkPoint origin, SkDrawFilter* filter);
+    void prepareTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin);
 
-    void draw(SkBaseDevice* device);
-
-    // Public for testing only.
-    SkGlyphRun* useGlyphRun();
     SkGlyphRunList* useGlyphRunList();
+    SkGlyphRun* useGlyphRun();
 
 private:
     size_t runSize() const;
@@ -232,27 +165,20 @@
     void initialize();
     SkGlyphID* addDenseAndUnique(const SkPaint& paint, const void* bytes, size_t byteLength);
     void addGlyphRunToList(
-            const SkPaint& runPaint,
-            SkGlyphID* temporaryShuntGlyphIDs,
-            SkSpan<const char> text,
-            SkSpan<const uint32_t> clusters);
+            SkGlyphID* temporaryShuntGlyphIDs, SkSpan<const char> text, SkSpan<uint32_t> clusters);
 
     void drawText(
             const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin,
-            SkSpan<const char> text, SkSpan<const uint32_t> clusters);
+            SkSpan<const char> text, SkSpan<uint32_t> clusters);
     void drawPosTextH(
             const SkPaint& paint, const void* bytes, size_t byteLength,
             const SkScalar* xpos, SkScalar constY,
-            SkSpan<const char> text, SkSpan<const uint32_t> clusters);
+            SkSpan<const char> text, SkSpan<uint32_t> clusters);
     void drawPosText(
             const SkPaint& paint, const void* bytes, size_t byteLength, const SkPoint* pos,
-            SkSpan<const char> text, SkSpan<const uint32_t> clusters);
+            SkSpan<const char> text, SkSpan<uint32_t> clusters);
 
-    const SkTextBlob*      fTemporaryTextBlobShunt{nullptr};
-
-    // The point passed into drawTextBlob. This allows the GPU back end to detect and adjust for
-    // translations.
-    SkPoint                fOrigin;
+    uint64_t               fUniqueID{0};
 
     std::vector<uint16_t>  fDenseIndex;
     std::vector<SkPoint>   fPositions;
diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp
index 18e47f3..774a1eb 100644
--- a/src/core/SkRemoteGlyphCache.cpp
+++ b/src/core/SkRemoteGlyphCache.cpp
@@ -16,9 +16,9 @@
 #include "SkDevice.h"
 #include "SkDraw.h"
 #include "SkFindAndPlaceGlyph.h"
-#include "SkGlyphRun.h"
 #include "SkPathEffect.h"
 #include "SkStrikeCache.h"
+#include "SkTextBlobRunIterator.h"
 #include "SkTraceEvent.h"
 #include "SkTypeface_remote.h"
 
@@ -240,20 +240,27 @@
     }
 
 protected:
-    void drawGlyphRunList(SkGlyphRunList* glyphRunList) override {
-        SkPaint runPaint;
-        SkGlyphRunListIterator it(glyphRunList);
+    void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint,
+                      SkDrawFilter* drawFilter) override {
+        // The looper should be applied by the SkCanvas.
+        SkASSERT(paint.getDrawLooper() == nullptr);
+        // We don't support SkDrawFilter.
+        SkASSERT(drawFilter == nullptr);
+
+        SkPoint position{x, y};
+        SkPaint runPaint{paint};
+        SkTextBlobRunIterator it(blob);
         for (; !it.done(); it.next()) {
             // applyFontToPaint() always overwrites the exact same attributes,
             // so it is safe to not re-seed the paint for this reason.
             it.applyFontToPaint(&runPaint);
-            this->processGlyphRun(glyphRunList->origin(), it, runPaint);
+            this->processGlyphRun(position, it, runPaint);
         }
     }
 
 private:
     void processGlyphRun(const SkPoint& position,
-                         const SkGlyphRunListIterator& it,
+                         const SkTextBlobRunIterator& it,
                          const SkPaint& runPaint) {
         TRACE_EVENT0("skia", "SkTextBlobCacheDiffCanvas::processGlyphRun");
 
@@ -337,7 +344,7 @@
         }
     }
 
-    void processGlyphRunForPaths(const SkGlyphRunListIterator& it,
+    void processGlyphRunForPaths(const SkTextBlobRunIterator& it,
                                  const SkPaint& runPaint,
                                  const SkMatrix& runMatrix) {
         TRACE_EVENT0("skia", "SkTextBlobCacheDiffCanvas::processGlyphRunForPaths");
@@ -387,7 +394,7 @@
     }
 
 #if SK_SUPPORT_GPU
-    bool processGlyphRunForDFT(const SkGlyphRunListIterator& it,
+    bool processGlyphRunForDFT(const SkTextBlobRunIterator& it,
                                const SkPaint& runPaint,
                                const SkMatrix& runMatrix) {
         TRACE_EVENT0("skia", "SkTextBlobCacheDiffCanvas::processGlyphRunForDFT");
diff --git a/src/core/SkTypeface_remote.h b/src/core/SkTypeface_remote.h
index f7326cc..47a68fd 100644
--- a/src/core/SkTypeface_remote.h
+++ b/src/core/SkTypeface_remote.h
@@ -123,7 +123,8 @@
         return 0;
     }
     int onCountGlyphs() const override {
-        return this->glyphCount();
+        SK_ABORT("Should never be called.");
+        return 0;
     }
 
     void* onGetCTFontRef() const override {
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 9d31a0d..1dbde17 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -237,17 +237,18 @@
                                   clipBounds);
 }
 
-void GrRenderTargetContext::drawGlyphRunList(
-        const GrClip& clip, const SkMatrix& viewMatrix,
-        SkGlyphRunList* blob, const SkIRect& clipBounds) {
+void GrRenderTargetContext::drawTextBlob(const GrClip& clip, const SkPaint& paint,
+                                         const SkMatrix& viewMatrix, const SkTextBlob* blob,
+                                         SkScalar x, SkScalar y, SkDrawFilter* filter,
+                                         const SkIRect& clipBounds) {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
-    GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawGlyphRunList", fContext);
+    GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextBlob", fContext);
 
     GrTextContext* atlasTextContext = this->drawingManager()->getTextContext();
-    atlasTextContext->drawGlyphRunList(fContext, fTextTarget.get(), clip, viewMatrix,
-                                       fSurfaceProps, blob, clipBounds);
+    atlasTextContext->drawTextBlob(fContext, fTextTarget.get(), clip, paint, viewMatrix,
+                                   fSurfaceProps, blob, x, y, filter, clipBounds);
 }
 
 void GrRenderTargetContext::discard() {
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index b529398..783b351 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -37,7 +37,6 @@
 struct GrUserStencilSettings;
 class SkDrawFilter;
 struct SkDrawShadowRec;
-class SkGlyphRunList;
 struct SkIPoint;
 struct SkIRect;
 class SkLatticeIter;
@@ -68,9 +67,10 @@
                              const char text[], size_t byteLength, const SkScalar pos[],
                              int scalarsPerPosition, const SkPoint& offset,
                              const SkIRect& clipBounds);
-    virtual void drawGlyphRunList(const GrClip&,
-                                  const SkMatrix& viewMatrix, SkGlyphRunList*,
-                                  const SkIRect& clipBounds);
+    virtual void drawTextBlob(const GrClip&, const SkPaint&,
+                              const SkMatrix& viewMatrix, const SkTextBlob*,
+                              SkScalar x, SkScalar y,
+                              SkDrawFilter*, const SkIRect& clipBounds);
 
     /**
      * Provides a perfomance hint that the render target's contents are allowed
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index d4f329d..819acd2 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1624,13 +1624,14 @@
                                       this->devClipBounds());
 }
 
-void SkGpuDevice::drawGlyphRunList(SkGlyphRunList* list) {
+void SkGpuDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+                               const SkPaint& paint, SkDrawFilter* drawFilter) {
     ASSERT_SINGLE_OWNER
-    GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawGlyphRunList", fContext.get());
+    GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawTextBlob", fContext.get());
     SkDEBUGCODE(this->validate();)
 
-    fRenderTargetContext->drawGlyphRunList(
-            this->clip(), this->ctm(), list, this->devClipBounds());
+    fRenderTargetContext->drawTextBlob(this->clip(), paint, this->ctm(), blob, x, y, drawFilter,
+                                       this->devClipBounds());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index 0bd1c80..7c7030e 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -89,7 +89,8 @@
                     const SkPaint& paint) override;
     void drawPosText(const void* text, size_t len, const SkScalar pos[],
                      int scalarsPerPos, const SkPoint& offset, const SkPaint&) override;
-    void drawGlyphRunList(SkGlyphRunList* list) override;
+    void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
+                      const SkPaint& paint, SkDrawFilter* drawFilter) override;
     void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
     void drawShadow(const SkPath&, const SkDrawShadowRec&) override;
     void drawAtlas(const SkImage* atlas, const SkRSXform[], const SkRect[],
diff --git a/src/gpu/text/GrTextBlobCache.h b/src/gpu/text/GrTextBlobCache.h
index 7a8ea0b..b41d401 100644
--- a/src/gpu/text/GrTextBlobCache.h
+++ b/src/gpu/text/GrTextBlobCache.h
@@ -55,20 +55,6 @@
         blob->notifyAddedToCache(fUniqueID);
         return cacheBlob;
     }
-    sk_sp<GrTextBlob> makeBlob(SkGlyphRunList* glyphRunList) {
-        return GrTextBlob::Make(glyphRunList->totalGlyphCount(), glyphRunList->size());
-    }
-
-    sk_sp<GrTextBlob> makeCachedBlob(SkGlyphRunList* glyphRunList,
-                                     const GrTextBlob::Key& key,
-                                     const SkMaskFilterBase::BlurRec& blurRec,
-                                     const SkPaint& paint) {
-        sk_sp<GrTextBlob> cacheBlob(makeBlob(glyphRunList));
-        cacheBlob->setupKey(key, blurRec, paint);
-        this->add(cacheBlob);
-        glyphRunList->temporaryShuntBlobnotifyAddedToCache(fUniqueID);
-        return cacheBlob;
-    }
 
     sk_sp<GrTextBlob> find(const GrTextBlob::Key& key) const {
         const auto* idEntry = fBlobIDCache.find(key.fUniqueID);
diff --git a/src/gpu/text/GrTextContext.cpp b/src/gpu/text/GrTextContext.cpp
index 3309d22..a20ba44 100644
--- a/src/gpu/text/GrTextContext.cpp
+++ b/src/gpu/text/GrTextContext.cpp
@@ -84,48 +84,58 @@
     }
 }
 
-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();
+// 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;
+}
 
-    // Get the first paint to use as the key paint.
-    const SkPaint& skPaint = (*glyphRunList)[0].paint();
-
+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) {
     // 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 = glyphRunList->canCache() && !(skPaint.getPathEffect() ||
-                      (mf && !as_MFB(mf)->asABlur(&blurRec)));
+    bool canCache = !(skPaint.getPathEffect() ||
+                      (mf && !as_MFB(mf)->asABlur(&blurRec)) ||
+                      drawFilter);
     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 = glyphRunList->anyRunsLCD();
+        bool hasLCD = HasLCD(blob);
 
         // 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 = glyphRunList->uniqueID();
+        key.fUniqueID = blob->uniqueID();
         key.fStyle = skPaint.getStyle();
         key.fHasBlur = SkToBool(mf);
         key.fCanonicalColor = canonicalColor;
@@ -135,77 +145,135 @@
 
     GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo());
     if (cacheBlob) {
-        if (cacheBlob->mustRegenerate(paint, blurRec, viewMatrix, origin.x(), origin.y())) {
+        if (cacheBlob->mustRegenerate(paint, blurRec, viewMatrix, x, 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(glyphRunList, key, blurRec, skPaint);
-            this->regenerateGlyphRunList(cacheBlob.get(), glyphCache,
+            cacheBlob = textBlobCache->makeCachedBlob(blob, key, blurRec, skPaint);
+            this->regenerateTextBlob(cacheBlob.get(), glyphCache,
                                      *context->contextPriv().caps()->shaderCaps(), paint,
-                                     scalerContextFlags, viewMatrix, props, glyphRunList);
+                                     scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter);
         } else {
             textBlobCache->makeMRU(cacheBlob.get());
 
             if (CACHE_SANITY_CHECK) {
-                int glyphCount = glyphRunList->totalGlyphCount();
-                int runCount = glyphRunList->runCount();
+                int glyphCount = 0;
+                int runCount = 0;
+                GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob);
                 sk_sp<GrTextBlob> sanityBlob(textBlobCache->makeBlob(glyphCount, runCount));
                 sanityBlob->setupKey(key, blurRec, skPaint);
-                this->regenerateGlyphRunList(
+                this->regenerateTextBlob(
                         sanityBlob.get(), glyphCache, *context->contextPriv().caps()->shaderCaps(),
-                        paint, scalerContextFlags, viewMatrix, props, glyphRunList);
+                        paint, scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter);
                 GrTextBlob::AssertEqual(*sanityBlob, *cacheBlob);
             }
         }
     } else {
         if (canCache) {
-            cacheBlob = textBlobCache->makeCachedBlob(glyphRunList, key, blurRec, skPaint);
+            cacheBlob = textBlobCache->makeCachedBlob(blob, key, blurRec, skPaint);
         } else {
-            cacheBlob = textBlobCache->makeBlob(glyphRunList);
+            cacheBlob = textBlobCache->makeBlob(blob);
         }
-        this->regenerateGlyphRunList(cacheBlob.get(), glyphCache,
+        this->regenerateTextBlob(cacheBlob.get(), glyphCache,
                                  *context->contextPriv().caps()->shaderCaps(), paint,
-                                 scalerContextFlags, viewMatrix, props, glyphRunList);
+                                 scalerContextFlags, viewMatrix, props, blob, x, y, drawFilter);
     }
 
     cacheBlob->flush(target, props, fDistanceAdjustTable.get(), paint,
-                     clip, viewMatrix, clipBounds, origin.x(), origin.y());
+                     clip, viewMatrix, clipBounds, x, y);
 }
 
-void GrTextContext::regenerateGlyphRunList(GrTextBlob* cacheBlob,
+void GrTextContext::regenerateTextBlob(GrTextBlob* cacheBlob,
                                        GrGlyphCache* glyphCache,
                                        const GrShaderCaps& shaderCaps,
                                        const GrTextUtils::Paint& paint,
                                        SkScalerContextFlags scalerContextFlags,
                                        const SkMatrix& viewMatrix,
-                                       const SkSurfaceProps& props,
-                                       SkGlyphRunList* glyphRunList) const {
-    SkPoint origin = glyphRunList->origin();
-    cacheBlob->initReusableBlob(paint.luminanceColor(), viewMatrix, origin.x(), origin.y());
+                                       const SkSurfaceProps& props, const SkTextBlob* blob,
+                                       SkScalar x, SkScalar y,
+                                       SkDrawFilter* drawFilter) const {
+    cacheBlob->initReusableBlob(paint.luminanceColor(), viewMatrix, x, y);
 
     // Regenerate textblob
-    SkGlyphRunListIterator it(glyphRunList);
-    GrTextUtils::RunPaint runPaint(&paint, nullptr);
+    SkTextBlobRunIterator it(blob);
+    GrTextUtils::RunPaint runPaint(&paint, drawFilter);
     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)) {
-            this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint,
-                                scalerContextFlags, viewMatrix, (const char*)it.glyphs(),
-                                textLen, it.pos(), 2, origin);
+            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;
+                }
+            }
         } else {
-            DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
-                           viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2,
-                           origin);
+            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;
+            }
         }
     }
 }
@@ -265,6 +333,7 @@
     }
 }
 
+
 void GrTextContext::DrawBmpPosText(GrTextBlob* blob, int runIndex,
                                    GrGlyphCache* glyphCache, const SkSurfaceProps& props,
                                    const GrTextUtils::Paint& paint,
@@ -717,7 +786,6 @@
     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(
diff --git a/src/gpu/text/GrTextContext.h b/src/gpu/text/GrTextContext.h
index 25aeea0..dd82b3c 100644
--- a/src/gpu/text/GrTextContext.h
+++ b/src/gpu/text/GrTextContext.h
@@ -48,9 +48,9 @@
                      const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[],
                      size_t byteLength, const SkScalar pos[], int scalarsPerPosition,
                      const SkPoint& offset, const SkIRect& regionClipBounds);
-    void drawGlyphRunList(GrContext*, GrTextUtils::Target*, const GrClip&,
-                          const SkMatrix& viewMatrix, const SkSurfaceProps&, SkGlyphRunList*,
-                          const SkIRect& clipBounds);
+    void drawTextBlob(GrContext*, GrTextUtils::Target*, const GrClip&, const SkPaint&,
+                      const SkMatrix& viewMatrix, const SkSurfaceProps&, const SkTextBlob*,
+                      SkScalar x, SkScalar y, SkDrawFilter*, const SkIRect& clipBounds);
 
     std::unique_ptr<GrDrawOp> createOp_TestingOnly(GrContext*,
                                                    GrTextContext*,
@@ -115,15 +115,17 @@
     static SkColor ComputeCanonicalColor(const SkPaint&, bool lcd);
     // Determines if we need to use fake gamma (and contrast boost):
     static SkScalerContextFlags ComputeScalerContextFlags(const GrColorSpaceInfo&);
-
-    void regenerateGlyphRunList(GrTextBlob* bmp,
+    void regenerateTextBlob(GrTextBlob* bmp,
                             GrGlyphCache*,
                             const GrShaderCaps&,
                             const GrTextUtils::Paint&,
                             SkScalerContextFlags scalerContextFlags,
                             const SkMatrix& viewMatrix,
                             const SkSurfaceProps&,
-                            SkGlyphRunList* glyphRunList) const;
+                            const SkTextBlob* blob, SkScalar x, SkScalar y,
+                            SkDrawFilter* drawFilter) const;
+
+    static bool HasLCD(const SkTextBlob*);
 
     sk_sp<GrTextBlob> makeDrawPosTextBlob(GrTextBlobCache*, GrGlyphCache*,
                                                const GrShaderCaps&,
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 72d543c..45a9b95 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -19,7 +19,6 @@
 #include "SkDraw.h"
 #include "SkDrawFilter.h"
 #include "SkGlyphCache.h"
-#include "SkGlyphRun.h"
 #include "SkImageFilterCache.h"
 #include "SkJpegEncoder.h"
 #include "SkMakeUnique.h"
@@ -1459,12 +1458,17 @@
                            offset, paint, nullptr, 0, nullptr);
 }
 
-void SkPDFDevice::drawGlyphRunList(SkGlyphRunList* glyphRunList) {
-    for (SkGlyphRunListIterator it(glyphRunList); !it.done(); it.next()) {
-        SkPaint runPaint;
+void SkPDFDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+                               const SkPaint &paint, SkDrawFilter* drawFilter) {
+    for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) {
+        SkPaint runPaint(paint);
         it.applyFontToPaint(&runPaint);
+        if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) {
+            continue;
+        }
+        SkPoint offset = it.offset() + SkPoint{x, y};
         this->internalDrawText(it.glyphs(), sizeof(SkGlyphID) * it.glyphCount(),
-                               it.pos(), it.positioning(), glyphRunList->origin(), runPaint,
+                               it.pos(), it.positioning(), offset, runPaint,
                                it.clusters(), it.textSize(), it.text());
     }
 }
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index 90f4b8e..33d0e70 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -22,7 +22,6 @@
 #include "SkTextBlob.h"
 #include "SkKeyedImage.h"
 
-class SkGlyphRunList;
 class SkKeyedImage;
 class SkPath;
 class SkPDFArray;
@@ -99,7 +98,8 @@
     void drawPosText(const void* text, size_t len,
                      const SkScalar pos[], int scalarsPerPos,
                      const SkPoint& offset, const SkPaint&) override;
-    void drawGlyphRunList(SkGlyphRunList* glyphRunList) override;
+    void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
+                      const SkPaint &, SkDrawFilter*) override;
     void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
     void drawDevice(SkBaseDevice*, int x, int y,
                     const SkPaint&) override;
diff --git a/tests/GlyphRunTest.cpp b/tests/GlyphRunTest.cpp
index 8107f20..cd2a221 100644
--- a/tests/GlyphRunTest.cpp
+++ b/tests/GlyphRunTest.cpp
@@ -75,7 +75,7 @@
     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
 
     SkGlyphRunBuilder runBuilder;
-    runBuilder.prepareTextBlob(font, *blob, SkPoint::Make(0, 0), nullptr);
+    runBuilder.prepareTextBlob(font, *blob, SkPoint::Make(0, 0));
 
     auto runList = runBuilder.useGlyphRunList();
 
@@ -96,4 +96,4 @@
 
         runIndex += 1;
     }
-}
+}
\ No newline at end of file
diff --git a/tests/SkRemoteGlyphCacheTest.cpp b/tests/SkRemoteGlyphCacheTest.cpp
index 6986a7b..4a7bd86 100644
--- a/tests/SkRemoteGlyphCacheTest.cpp
+++ b/tests/SkRemoteGlyphCacheTest.cpp
@@ -69,8 +69,6 @@
     font.setStyle(SkPaint::kFill_Style);
     font.setHinting(SkPaint::kNormal_Hinting);
     font.setTextSize(1u);
-    font.setAntiAlias(true);
-    font.setSubpixelText(true);
 
     SkTextBlobBuilder builder;
     SkRect bounds = SkRect::MakeWH(10, 10);
@@ -101,13 +99,12 @@
 }
 
 SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
-                    GrContext* context, const SkMatrix* matrix = nullptr,
-                    SkScalar x = 0) {
+                    GrContext* context, const SkMatrix* matrix = nullptr) {
     const SkImageInfo info =
             SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
     auto surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
     if (matrix) surface->getCanvas()->concat(*matrix);
-    surface->getCanvas()->drawTextBlob(blob.get(), x, 0, paint);
+    surface->getCanvas()->drawTextBlob(blob.get(), 0u, 0u, paint);
     SkBitmap bitmap;
     bitmap.allocN32Pixels(width, height);
     surface->readPixels(bitmap, 0, 0);
@@ -335,45 +332,6 @@
     discardableManager->unlockAndDeleteAll();
 }
 
-DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
-    sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
-    SkStrikeServer server(discardableManager.get());
-    SkStrikeClient client(discardableManager, false);
-    SkPaint paint;
-    paint.setAntiAlias(true);
-    paint.setSubpixelText(true);
-    paint.setLCDRenderText(true);
-
-    // Server.
-    auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
-    auto serverTfData = server.serializeTypeface(serverTf.get());
-
-    int glyphCount = 10;
-    auto serverBlob = buildTextBlob(serverTf, glyphCount);
-    const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
-    SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
-                                                MakeSettings(ctxInfo.grContext()));
-    cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
-
-    std::vector<uint8_t> serverStrikeData;
-    server.writeStrikeData(&serverStrikeData);
-
-    // Client.
-    auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
-    REPORTER_ASSERT(reporter,
-                    client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
-    auto clientBlob = buildTextBlob(clientTf, glyphCount);
-
-    SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
-    SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
-    COMPARE_BLOBS(expected, actual, reporter);
-    REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
-    SkStrikeCache::ValidateGlyphCacheDataSize();
-
-    // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
-    discardableManager->unlockAndDeleteAll();
-}
-
 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
     SkStrikeServer server(discardableManager.get());