Revert "Have draw(Text|PosText|PosTextH) use a single entry on the device"

This reverts commit 4225b3220ef4bf50f0d9403f812ea94d50c4ee59.

Reason for revert: made valgrind unhappy.

Original change's description:
> Have draw(Text|PosText|PosTextH) use a single entry on the device
> 
> Handle the positioning of drawText at the canvas layer. Simplify
> the code by removing similar implementations.
> 
> Change-Id: I8b711783435072f560e29fca1dd934fa2e345ed2
> Reviewed-on: https://skia-review.googlesource.com/127131
> Reviewed-by: Ben Wagner <bungeman@google.com>
> Commit-Queue: Herb Derby <herb@google.com>

TBR=jvanverth@google.com,bungeman@google.com,herb@google.com

Change-Id: I65c9d30ae6ecb1f87e8660e56d8f8ce5daab7551
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/132403
Reviewed-by: Hal Canary <halcanary@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>
diff --git a/gn/core.gni b/gn/core.gni
index 99da62f..123c6aa 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -153,8 +153,6 @@
   "$_src/core/SkGlyph.cpp",
   "$_src/core/SkGlyphCache.cpp",
   "$_src/core/SkGlyphCache.h",
-  "$_src/core/SkGlyphRun.cpp",
-  "$_src/core/SkGlyphRun.h",
   "$_src/core/SkGpuBlurUtils.h",
   "$_src/core/SkGpuBlurUtils.cpp",
   "$_src/core/SkGraphics.cpp",
diff --git a/gn/tests.gni b/gn/tests.gni
index 2655834..a67b4f4 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -85,7 +85,6 @@
   "$_tests/GeometryTest.cpp",
   "$_tests/GifTest.cpp",
   "$_tests/GLProgramsTest.cpp",
-  "$_tests/GlyphRunTest.cpp",
   "$_tests/GpuDrawPathTest.cpp",
   "$_tests/GpuLayerCacheTest.cpp",
   "$_tests/GpuRectanizerTest.cpp",
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index cbd9a7c..71b85af 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -565,6 +565,12 @@
     BDDraw(this).drawSprite(bitmap, x, y, paint);
 }
 
+void SkBitmapDevice::drawText(const void* text, size_t len,
+                              SkScalar x, SkScalar y, const SkPaint& paint) {
+    SkBitmapDeviceFilteredSurfaceProps props(fBitmap, paint, fSurfaceProps);
+    LOOP_TILER( drawText((const char*)text, len, x, y, paint, &props()), nullptr)
+}
+
 void SkBitmapDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[],
                                  int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) {
     SkBitmapDeviceFilteredSurfaceProps props(fBitmap, paint, fSurfaceProps);
diff --git a/src/core/SkBitmapDevice.h b/src/core/SkBitmapDevice.h
index ba7846c..c36bc28 100644
--- a/src/core/SkBitmapDevice.h
+++ b/src/core/SkBitmapDevice.h
@@ -111,6 +111,8 @@
      *  Does not handle text decoration.
      *  Decorations (underline and stike-thru) will be handled by SkCanvas.
      */
+    void drawText(const void* text, size_t len, SkScalar x, SkScalar y,
+                  const SkPaint&) override;
     void drawPosText(const void* text, size_t len, const SkScalar pos[],
                      int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override;
     void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index dcff1b0..8230fb3 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -15,8 +15,6 @@
 #include "SkDrawable.h"
 #include "SkDrawFilter.h"
 #include "SkDrawLooper.h"
-#include "SkGlyphCache.h"
-#include "SkGlyphRun.h"
 #include "SkImage.h"
 #include "SkImage_Base.h"
 #include "SkImageFilter.h"
@@ -36,7 +34,6 @@
 #include "SkRasterHandleAllocator.h"
 #include "SkRRect.h"
 #include "SkSpecialImage.h"
-#include "SkStrikeCache.h"
 #include "SkString.h"
 #include "SkSurface_Base.h"
 #include "SkTextBlob.h"
@@ -1078,8 +1075,7 @@
         const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
                                      (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
         const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
-        const bool trackCoverage =
-                SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
+        const bool trackCoverage = SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
         const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
                                                                              preserveLCDText,
                                                                              trackCoverage,
@@ -2443,13 +2439,10 @@
 
 void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
                           const SkPaint& paint) {
-
     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
 
     while (iter.next()) {
-        auto glyphRun = SkGlyphRun::MakeFromDrawText(
-                looper.paint(), text, byteLength, SkPoint::Make(x, y));
-        iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
+        iter.fDevice->drawText(text, byteLength, x, y, looper.paint());
     }
 
     LOOPER_END
@@ -2457,12 +2450,12 @@
 
 void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
                              const SkPaint& paint) {
+    SkPoint textOffset = SkPoint::Make(0, 0);
 
     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
 
     while (iter.next()) {
-        auto glyphRun = SkGlyphRun::MakeFromDrawPosText(looper.paint(), text, byteLength, pos);
-        iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
+        iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset, looper.paint());
     }
 
     LOOPER_END
@@ -2471,12 +2464,12 @@
 void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
                               SkScalar constY, const SkPaint& paint) {
 
+    SkPoint textOffset = SkPoint::Make(0, constY);
+
     LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
 
     while (iter.next()) {
-        auto glyphRun =
-                SkGlyphRun::MakeFromDrawPosTextH(looper.paint(), text, byteLength, xpos, constY);
-        iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
+        iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset, looper.paint());
     }
 
     LOOPER_END
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 1bad6db..35cfc9a 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -9,14 +9,12 @@
 #include "SkColorFilter.h"
 #include "SkDraw.h"
 #include "SkDrawFilter.h"
-#include "SkGlyphRun.h"
 #include "SkImageFilter.h"
 #include "SkImageFilterCache.h"
 #include "SkImagePriv.h"
 #include "SkImage_Base.h"
 #include "SkLatticeIter.h"
 #include "SkLocalMatrixShader.h"
-#include "SkMakeUnique.h"
 #include "SkMatrixPriv.h"
 #include "SkPatchUtils.h"
 #include "SkPathMeasure.h"
@@ -159,16 +157,9 @@
         }
 
         switch (it.positioning()) {
-        case SkTextBlob::kDefault_Positioning: {
-            auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
-            auto glyphRun =
-                    SkGlyphRun::MakeFromDrawText(runPaint,
-                                                 (const char*) it.glyphs(), textLen, origin);
-            this->drawPosText(
-                    it.glyphs(), textLen, glyphRun.getPositions(), 2,
-                    SkPoint::Make(0, 0), runPaint);
-        }
-        break;
+        case SkTextBlob::kDefault_Positioning:
+            this->drawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint);
+            break;
         case SkTextBlob::kHorizontal_Positioning:
             this->drawPosText(it.glyphs(), textLen, it.pos(), 1,
                               SkPoint::Make(x, y + offset.y()), runPaint);
@@ -252,17 +243,6 @@
     }
 }
 
-void SkBaseDevice::drawGlyphRun(const SkPaint& paint, SkGlyphRun* info) {
-    SkPaint glyphPaint(paint);
-    glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-
-    auto glyphs = info->copyGlyphIDs();
-
-    this->drawPosText(
-            glyphs.get(), info->runSize() * 2,
-            info->getPositions(), 2, SkPoint::Make(0, 0), glyphPaint);
-}
-
 void SkBaseDevice::drawBitmapLattice(const SkBitmap& bitmap,
                                      const SkCanvas::Lattice& lattice, const SkRect& dst,
                                      const SkPaint& paint) {
@@ -516,8 +496,6 @@
 
     SkPaint localPaint(paint);
     SkShader* shader = paint.getShader();
-    SkScalar pos[2] = {0.0f, 0.0f};
-    SkPoint origin = SkPoint::Make(0, 0);
 
     SkMatrix localM, currM;
     const void* stopText = (const char*)text + len;
@@ -539,7 +517,7 @@
         }
 
         int subLen = proc((const char*)text);
-        this->drawPosText(text, subLen, pos, 2, origin, localPaint);
+        this->drawText(text, subLen, 0, 0, localPaint);
         text = (const char*)text + subLen;
     }
 }
diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h
index d36dc4d..40b9589 100644
--- a/src/core/SkDevice.h
+++ b/src/core/SkDevice.h
@@ -17,7 +17,6 @@
 class SkBitmap;
 class SkDrawFilter;
 struct SkDrawShadowRec;
-class SkGlyphRun;
 class SkImageFilterCache;
 struct SkIRect;
 class SkMatrix;
@@ -223,7 +222,11 @@
      *  Does not handle text decoration.
      *  Decorations (underline and stike-thru) will be handled by SkCanvas.
      */
-    virtual void drawGlyphRun(const SkPaint& paint, SkGlyphRun* info);
+    virtual void drawText(const void* text, size_t len,
+                          SkScalar x, SkScalar y, const SkPaint& paint) = 0;
+    virtual void drawPosText(const void* text, size_t len,
+                             const SkScalar pos[], int scalarsPerPos,
+                             const SkPoint& offset, const SkPaint& paint) = 0;
     virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) = 0;
     virtual void drawShadow(const SkPath&, const SkDrawShadowRec&);
 
@@ -346,10 +349,6 @@
     friend class SkSurface_Raster;
     friend class DeviceTestingAccess;
 
-    virtual void drawPosText(const void* text, size_t len,
-                             const SkScalar pos[], int scalarsPerPos,
-                             const SkPoint& offset, const SkPaint& paint) = 0;
-
     // used to change the backend's pixels (and possibly config/rowbytes)
     // but cannot change the width/height, so there should be no change to
     // any clip information.
@@ -428,6 +427,7 @@
     void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
     void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
                         SkCanvas::SrcRectConstraint) override {}
+    void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
     void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
                      const SkPaint&) override {}
     void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index e975ea2..b7150f8 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -1537,6 +1537,37 @@
     return flags;
 }
 
+void SkDraw::drawText(const char text[], size_t byteLength, SkScalar x, SkScalar y,
+                      const SkPaint& paint, const SkSurfaceProps* props) const {
+    SkASSERT(byteLength == 0 || text != nullptr);
+
+    SkDEBUGCODE(this->validate();)
+
+    // nothing to draw
+    if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
+        return;
+    }
+
+    // SkScalarRec doesn't currently have a way of representing hairline stroke and
+    // will fill if its frame-width is 0.
+    if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
+        this->drawText_asPaths(text, byteLength, x, y, paint);
+        return;
+    }
+
+    auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(
+            paint, props, this->scalerContextFlags(), fMatrix);
+
+    // The Blitter Choose needs to be live while using the blitter below.
+    SkAutoBlitterChoose    blitterChooser(*this, nullptr, paint);
+    SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
+    DrawOneGlyph           drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter());
+
+    SkFindAndPlaceGlyph::ProcessText(
+        paint.getTextEncoding(), text, byteLength,
+        {x, y}, *fMatrix, paint.getTextAlign(), cache.get(), drawOneGlyph);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, const SkScalar pos[],
diff --git a/src/core/SkDraw.h b/src/core/SkDraw.h
index 266960e..eabccf0 100644
--- a/src/core/SkDraw.h
+++ b/src/core/SkDraw.h
@@ -62,6 +62,8 @@
     void    drawBitmap(const SkBitmap&, const SkMatrix&, const SkRect* dstOrNull,
                        const SkPaint&) const;
     void    drawSprite(const SkBitmap&, int x, int y, const SkPaint&) const;
+    void    drawText(const char text[], size_t byteLength, SkScalar x,
+                     SkScalar y, const SkPaint& paint, const SkSurfaceProps*) const;
     void    drawPosText(const char text[], size_t byteLength,
                         const SkScalar pos[], int scalarsPerPosition,
                         const SkPoint& offset, const SkPaint&, const SkSurfaceProps*) const;
diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp
index 3734b96..bf5f77c 100644
--- a/src/core/SkGlyphCache.cpp
+++ b/src/core/SkGlyphCache.cpp
@@ -130,13 +130,6 @@
     return *this->lookupByPackedGlyphID(packedGlyphID, kFull_MetricsType);
 }
 
-void SkGlyphCache::getAdvances(SkSpan<SkGlyphID> glyphIDs, SkPoint advances[]) {
-    for (ptrdiff_t i = 0; i < glyphIDs.size(); i++) {
-        auto glyph = this->getGlyphIDAdvance(glyphIDs[i]);
-        advances[i] = SkPoint::Make(glyph.fAdvanceX, glyph.fAdvanceY);
-    }
-}
-
 SkGlyph* SkGlyphCache::lookupByChar(SkUnichar charCode, MetricsType type, SkFixed x, SkFixed y) {
     SkPackedUnicharID id(charCode, x, y);
     CharGlyphRec* rec = this->getCharGlyphRec(id);
diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h
index e904c6e..2e73557 100644
--- a/src/core/SkGlyphCache.h
+++ b/src/core/SkGlyphCache.h
@@ -10,7 +10,6 @@
 #include "SkArenaAlloc.h"
 #include "SkDescriptor.h"
 #include "SkGlyph.h"
-#include "SkGlyphRun.h"
 #include "SkPaint.h"
 #include "SkTHash.h"
 #include "SkScalerContext.h"
@@ -68,8 +67,6 @@
     const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y);
     const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
 
-    void getAdvances(SkSpan<SkGlyphID>, SkPoint[]);
-
     /** Return the glyphID for the specified Unichar. If the char has already been seen, use the
         existing cache entry. If not, ask the scalercontext to compute it for us.
     */
diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp
deleted file mode 100644
index a25b9af..0000000
--- a/src/core/SkGlyphRun.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkGlyphRun.h"
-
-#include <algorithm>
-#include <tuple>
-
-#include "SkDraw.h"
-#include "SkGlyphCache.h"
-#include "SkMakeUnique.h"
-#include "SkMSAN.h"
-#include "SkPaint.h"
-#include "SkPaintPriv.h"
-#include "SkStrikeCache.h"
-#include "SkUtils.h"
-
-namespace {
-
-// 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
-// for Sparse Sets"
-class GlyphSet {
-public:
-    GlyphSet(uint32_t glyphUniverseSize)
-    : fUniverseSize{glyphUniverseSize}
-    , fIndexes{skstd::make_unique_default<uint16_t[]>(2 * glyphUniverseSize)}
-    , fUniqueGlyphIDs{&fIndexes[glyphUniverseSize]} {
-        SkASSERT(glyphUniverseSize <= (1 << 16));
-        sk_msan_mark_initialized(fIndexes.get(), &fIndexes[glyphUniverseSize], "works with uninited");
-    }
-
-    uint16_t add(SkGlyphID glyphID) {
-        if (glyphID >= fUniverseSize) {
-            glyphID = kUndefGlyph;
-        }
-        auto index = fIndexes[glyphID];
-        if (index < fUniqueCount && fUniqueGlyphIDs[index] == glyphID) {
-            return index;
-        }
-
-        fUniqueGlyphIDs[fUniqueCount] = glyphID;
-        fIndexes[glyphID] = fUniqueCount;
-        fUniqueCount += 1;
-        return fUniqueCount - 1;
-    }
-
-    std::tuple<uint16_t, std::unique_ptr<SkGlyphID[]>> uniqueGlyphIDs() const {
-        auto uniqueGlyphs = skstd::make_unique_default<SkGlyphID[]>(fUniqueCount);
-        memcpy(uniqueGlyphs.get(), fUniqueGlyphIDs, fUniqueCount * sizeof(SkGlyphID));
-        return std::make_tuple(fUniqueCount, std::move(uniqueGlyphs));
-    }
-
-private:
-    static constexpr SkGlyphID  kUndefGlyph{0};
-    const uint32_t              fUniverseSize;
-    uint16_t                    fUniqueCount{0};
-    std::unique_ptr<uint16_t[]> fIndexes;
-    SkGlyphID*                  fUniqueGlyphIDs;
- };
-
-template<typename T>
-bool is_aligned(const void* ptr) {
-    uintptr_t bits = reinterpret_cast<uintptr_t>(ptr);
-    return (bits & (alignof(T) - 1)) == 0;
-}
-
-template<typename T>
-bool is_aligned_size(size_t size) {
-    return size % sizeof(T) == 0;
-}
-
-SkTypeface::Encoding convert_encoding(SkPaint::TextEncoding encoding) {
-    switch (encoding) {
-        case  SkPaint::kUTF8_TextEncoding: return SkTypeface::kUTF8_Encoding;
-        case SkPaint::kUTF16_TextEncoding: return SkTypeface::kUTF16_Encoding;
-        case SkPaint::kUTF32_TextEncoding: return SkTypeface::kUTF32_Encoding;
-        default: return SkTypeface::kUTF32_Encoding;
-    }
-}
-
-using Core = std::tuple<size_t,   std::unique_ptr<uint16_t[]>,
-                        uint16_t, std::unique_ptr<SkGlyphID[]>>;
-
-Core make_from_glyphids(size_t glyphCount, const SkGlyphID* glyphs, SkGlyphID maxGlyphID) {
-    if (glyphCount == 0) { return Core(0, nullptr, 0, nullptr); }
-
-    GlyphSet glyphSet{maxGlyphID};
-
-    auto denseIndex = skstd::make_unique_default<uint16_t[]>(glyphCount);
-    for (size_t i = 0; i < glyphCount; i++) {
-        denseIndex[i] = glyphSet.add(glyphs[i]);
-    }
-
-    std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
-    uint16_t uniqueCount;
-    std::tie(uniqueCount, uniqueGlyphIDs) = glyphSet.uniqueGlyphIDs();
-
-    return Core(glyphCount, std::move(denseIndex), uniqueCount, std::move(uniqueGlyphIDs));
-}
-
-Core make_from_utfn(size_t byteLength, const void* utfN, const SkTypeface& typeface,
-                    SkTypeface::Encoding encoding) {
-    auto count = SkUTFN_CountUnichars(encoding, utfN, byteLength);
-
-    if (count <= 0) {
-        return Core(0, nullptr, 0, nullptr);
-    }
-
-    auto glyphs = skstd::make_unique_default<SkGlyphID[]>(count);
-
-    // TODO: move to using cached version.
-    typeface.charsToGlyphs(utfN, encoding, glyphs.get(), count);
-
-    return make_from_glyphids(count, glyphs.get(), typeface.countGlyphs());
-}
-
-Core make_core(const SkPaint& paint, const void* bytes, size_t byteLength) {
-    auto encoding = paint.getTextEncoding();
-    auto typeface = SkPaintPriv::GetTypefaceOrDefault(paint);
-    if (encoding == SkPaint::kGlyphID_TextEncoding) {
-        return make_from_glyphids(
-                byteLength / 2, reinterpret_cast<const SkGlyphID*>(bytes), typeface->countGlyphs());
-    } else {
-        return make_from_utfn(byteLength, bytes, *typeface, convert_encoding(encoding));
-    }
-}
-
-}  // namespace
-
-SkGlyphRun SkGlyphRun::MakeFromDrawText(
-        const SkPaint& paint, const void* bytes, size_t byteLength,
-        const SkPoint origin) {
-    size_t runSize;
-    std::unique_ptr<uint16_t[]> denseIndex;
-    uint16_t uniqueSize;
-    std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
-    std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength);
-
-    if (runSize == 0) { return SkGlyphRun{}; }
-
-    auto advances = skstd::make_unique_default<SkPoint[]>(uniqueSize);
-
-    {
-        auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(paint);
-        cache->getAdvances(SkSpan<SkGlyphID>{uniqueGlyphIDs.get(), uniqueSize}, advances.get());
-    }
-
-    auto positions = skstd::make_unique_default<SkPoint[]>(runSize);
-
-    SkPoint endOfLastGlyph = origin;
-
-    for (size_t i = 0; i < runSize; i++) {
-        positions[i] = endOfLastGlyph;
-        endOfLastGlyph += advances[denseIndex[i]];
-    }
-
-    if (paint.getTextAlign() != SkPaint::kLeft_Align) {
-        SkVector len = endOfLastGlyph - origin;
-        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
-            len.scale(SK_ScalarHalf);
-        }
-        for (size_t i = 0; i < runSize; i++) {
-            positions[i] -= len;
-        }
-    }
-
-    return SkGlyphRun{
-        runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)};
-}
-
-SkGlyphRun SkGlyphRun::MakeFromDrawPosTextH(
-        const SkPaint& paint, const void* bytes, size_t byteLength,
-        const SkScalar xpos[], SkScalar constY) {
-    size_t runSize;
-    std::unique_ptr<uint16_t[]> denseIndex;
-    uint16_t uniqueSize;
-    std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
-    std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength);
-
-    if (runSize == 0) { return SkGlyphRun{}; }
-
-    auto positions = skstd::make_unique_default<SkPoint[]>(runSize);
-
-    for (size_t i = 0; i < runSize; i++) {
-        positions[i] = SkPoint::Make(xpos[i], constY);
-    }
-
-    return SkGlyphRun{
-        runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)};
-}
-
-SkGlyphRun SkGlyphRun::MakeFromDrawPosText(
-        const SkPaint& paint, const void* bytes, size_t byteLength,
-        const SkPoint pos[]) {
-    size_t runSize;
-    std::unique_ptr<uint16_t[]> denseIndex;
-    uint16_t uniqueSize;
-    std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
-    std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength);
-
-    if (runSize == 0) { return SkGlyphRun{}; }
-
-    auto positions = skstd::make_unique_default<SkPoint[]>(runSize);
-
-    memcpy(positions.get(), pos, sizeof(SkPoint) * runSize);
-
-    return SkGlyphRun{
-        runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)};
-}
-
-std::unique_ptr<SkGlyphID[]> SkGlyphRun::copyGlyphIDs() const {
-    auto glyphs = skstd::make_unique_default<SkGlyphID[]>(fRunSize);
-
-    for (size_t i = 0; i < fRunSize; i++) {
-        glyphs[i] = fUniqueGlyphs[fDenseIndex[i]];
-    }
-
-    return glyphs;
-}
-
-SkGlyphRun::SkGlyphRun(size_t runSize,
-                       std::unique_ptr<uint16_t[]>&& denseIndex,
-                       std::unique_ptr<SkPoint[]>&& positions,
-                       uint16_t uniqueSize,
-                       std::unique_ptr<SkGlyphID[]>&& uniqueGlyphIDs)
-    : fDenseIndex{std::move(denseIndex)}
-    , fPositions{std::move(positions)}
-    , fUniqueGlyphs{std::move(uniqueGlyphIDs)}
-    , fRunSize{runSize}
-    , fUniqueSize{uniqueSize} { }
diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h
deleted file mode 100644
index 17b4297..0000000
--- a/src/core/SkGlyphRun.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkGlyphRunInfo_DEFINED
-#define SkGlyphRunInfo_DEFINED
-
-#include <memory>
-#include <vector>
-
-#include "SkDescriptor.h"
-#include "SkMask.h"
-#include "SkPath.h"
-#include "SkPoint.h"
-#include "SkTypes.h"
-
-class SkGlyphRun {
-public:
-    SkGlyphRun() = default;
-    SkGlyphRun(SkGlyphRun&&) = default;
-    static SkGlyphRun MakeFromDrawText(
-            const SkPaint& paint, const void* bytes, size_t byteLength,
-            SkPoint origin);
-    static SkGlyphRun MakeFromDrawPosTextH(
-            const SkPaint& paint, const void* bytes, size_t byteLength,
-            const SkScalar xpos[], SkScalar constY);
-    static SkGlyphRun MakeFromDrawPosText(
-            const SkPaint& paint, const void* bytes, size_t byteLength,
-            const SkPoint pos[]);
-
-    size_t runSize() const { return fRunSize; }
-    uint16_t uniqueSize() const { return fUniqueSize; }
-
-    // copyGlyphIDs is temporary glue to work with the existing system. Don't use with new code.
-    std::unique_ptr<SkGlyphID[]> copyGlyphIDs() const;
-    const SkScalar* getPositions() const {
-        return reinterpret_cast<const SkScalar*>(fPositions.get());
-    }
-
-private:
-    SkGlyphRun(size_t runSize,
-               std::unique_ptr<uint16_t[]>&& denseIndex,
-               std::unique_ptr<SkPoint[]>&& positions,
-               uint16_t uniqueSize,
-               std::unique_ptr<SkGlyphID[]>&& uniqueGlyphIDs);
-
-    std::unique_ptr<uint16_t[]>  fDenseIndex;
-    std::unique_ptr<SkPoint[]>   fPositions;
-    std::unique_ptr<SkGlyphID[]> fUniqueGlyphs;
-    const size_t                 fRunSize{0};
-    const uint16_t               fUniqueSize{0};
-};
-
-template <typename T>
-class SkSpan {
-public:
-    SkSpan(const T* ptr, size_t size) : fPtr{ptr}, fSize{size} {}
-    SkSpan(const std::vector<T>& v) : fPtr{v.data()}, fSize{v.size()} {}
-    const T& operator [] (ptrdiff_t i) const { return fPtr[i]; }
-    const T* begin() const { return fPtr; }
-    const T* end() const { return fPtr + fSize; }
-    ptrdiff_t size() const { return fSize; }
-
-private:
-    const T* fPtr;
-    size_t fSize;
-};
-
-#endif  // SkGlyphRunInfo_DEFINED
diff --git a/src/core/SkThreadedBMPDevice.cpp b/src/core/SkThreadedBMPDevice.cpp
index 10cd824..b75e90d 100644
--- a/src/core/SkThreadedBMPDevice.cpp
+++ b/src/core/SkThreadedBMPDevice.cpp
@@ -210,6 +210,16 @@
     });
 }
 
+void SkThreadedBMPDevice::drawText(const void* text, size_t len, SkScalar x, SkScalar y,
+        const SkPaint& paint) {
+    char* clonedText = this->cloneArray((const char*)text, len);
+    SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
+    SkSurfaceProps prop(SkBitmapDeviceFilteredSurfaceProps(fBitmap, paint, this->surfaceProps())());
+    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
+        TileDraw(ds, tileBounds).drawText(clonedText, len, x, y, paint, &prop);
+    });
+}
+
 void SkThreadedBMPDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[],
         int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) {
     char* clonedText = this->cloneArray((const char*)text, len);
diff --git a/src/core/SkThreadedBMPDevice.h b/src/core/SkThreadedBMPDevice.h
index 6defce5..d9e27b4 100644
--- a/src/core/SkThreadedBMPDevice.h
+++ b/src/core/SkThreadedBMPDevice.h
@@ -32,6 +32,9 @@
     void drawPath(const SkPath&, const SkPaint&, const SkMatrix* prePathMatrix,
                   bool pathIsMutable) override;
     void drawSprite(const SkBitmap&, int x, int y, const SkPaint&) override;
+
+    void drawText(const void* text, size_t len, SkScalar x, SkScalar y,
+                  const SkPaint&) override;
     void drawPosText(const void* text, size_t len, const SkScalar pos[],
                      int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override;
     void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index a79f9d1..e5bda32 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -217,6 +217,20 @@
     return this->getRTOpList();
 }
 
+void GrRenderTargetContext::drawText(const GrClip& clip, const SkPaint& skPaint,
+                                     const SkMatrix& viewMatrix, const char text[],
+                                     size_t byteLength, SkScalar x, SkScalar y,
+                                     const SkIRect& clipBounds) {
+    ASSERT_SINGLE_OWNER
+    RETURN_IF_ABANDONED
+    SkDEBUGCODE(this->validate();)
+    GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawText", fContext);
+
+    GrTextContext* atlasTextContext = this->drawingManager()->getTextContext();
+    atlasTextContext->drawText(fContext, fTextTarget.get(), clip, skPaint, viewMatrix,
+                               fSurfaceProps, text, byteLength, x, y, clipBounds);
+}
+
 void GrRenderTargetContext::drawPosText(const GrClip& clip, const SkPaint& paint,
                                         const SkMatrix& viewMatrix, const char text[],
                                         size_t byteLength, const SkScalar pos[],
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index d605314..acbf963 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -63,6 +63,9 @@
     //      we could use GrPaint except that
     //    * SkPaint->GrPaint conversion depends upon whether the glyphs are color or grayscale and
     //      this can vary within a text run.
+    virtual void drawText(const GrClip&, const SkPaint&, const SkMatrix& viewMatrix,
+                          const char text[], size_t byteLength, SkScalar x, SkScalar y,
+                          const SkIRect& clipBounds);
     virtual void drawPosText(const GrClip&, const SkPaint&, const SkMatrix& viewMatrix,
                              const char text[], size_t byteLength, const SkScalar pos[],
                              int scalarsPerPosition, const SkPoint& offset,
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 210cefc..06307a1 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1611,6 +1611,17 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+void SkGpuDevice::drawText(const void* text,
+                           size_t byteLength, SkScalar x, SkScalar y,
+                           const SkPaint& paint) {
+    ASSERT_SINGLE_OWNER
+    GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext.get());
+    SkDEBUGCODE(this->validate();)
+
+    fRenderTargetContext->drawText(this->clip(), paint, this->ctm(), (const char*)text, byteLength,
+                                   x, y, this->devClipBounds());
+}
+
 void SkGpuDevice::drawPosText(const void* text, size_t byteLength,
                               const SkScalar pos[], int scalarsPerPos,
                               const SkPoint& offset, const SkPaint& paint) {
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index 7c7030e..d98dbff 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -87,6 +87,8 @@
                         const SkPaint& paint, SkCanvas::SrcRectConstraint) override;
     void drawSprite(const SkBitmap& bitmap, int x, int y,
                     const SkPaint& paint) override;
+    void drawText(const void* text, size_t len, SkScalar x, SkScalar y,
+                  const SkPaint&) override;
     void drawPosText(const void* text, size_t len, const SkScalar pos[],
                      int scalarsPerPos, const SkPoint& offset, const SkPaint&) override;
     void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
diff --git a/src/gpu/text/GrTextContext.cpp b/src/gpu/text/GrTextContext.cpp
index 72926fe..f662fa9 100644
--- a/src/gpu/text/GrTextContext.cpp
+++ b/src/gpu/text/GrTextContext.cpp
@@ -17,7 +17,6 @@
 #include "SkFindAndPlaceGlyph.h"
 #include "SkGr.h"
 #include "SkGraphics.h"
-#include "SkGlyphRun.h"
 #include "SkMakeUnique.h"
 #include "SkMaskFilterBase.h"
 #include "SkPaintPriv.h"
@@ -210,17 +209,11 @@
                                     shaderCaps.supportsDistanceFieldText(), fOptions)) {
             switch (it.positioning()) {
                 case SkTextBlob::kDefault_Positioning: {
-                    auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
-                    auto glyphRun =
-                            SkGlyphRun::MakeFromDrawText(runPaint.skPaint(),
-                                    (const char*)it.glyphs(), textLen, origin);
-
-                    this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint,
-                                        scalerContextFlags, viewMatrix, (const char*)it.glyphs(),
-                                        textLen, glyphRun.getPositions(), 2, SkPoint::Make(0,0));
+                    this->drawDFText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
+                                     viewMatrix, (const char*)it.glyphs(), textLen, x + offset.x(),
+                                     y + offset.y());
                     break;
                 }
-
                 case SkTextBlob::kHorizontal_Positioning: {
                     SkPoint dfOffset = SkPoint::Make(x, y + offset.y());
                     this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint,
@@ -238,17 +231,11 @@
             }
         } else {
             switch (it.positioning()) {
-                case SkTextBlob::kDefault_Positioning: {
-                    auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
-                    auto glyphRun =
-                            SkGlyphRun::MakeFromDrawText(
-                                    runPaint.skPaint(), (const char*) it.glyphs(), textLen, origin);
-
-                    this->DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint,
-                                         scalerContextFlags, viewMatrix, (const char*) it.glyphs(),
-                                         textLen, glyphRun.getPositions(), 2, SkPoint::Make(0, 0));
+                case SkTextBlob::kDefault_Positioning:
+                    DrawBmpText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
+                                viewMatrix, (const char*)it.glyphs(), textLen, x + offset.x(),
+                                y + offset.y());
                     break;
-                }
                 case SkTextBlob::kHorizontal_Positioning:
                     DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
                                    viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 1,
@@ -265,6 +252,35 @@
 }
 
 inline sk_sp<GrTextBlob>
+GrTextContext::makeDrawTextBlob(GrTextBlobCache* blobCache,
+                                GrGlyphCache* glyphCache,
+                                const GrShaderCaps& shaderCaps,
+                                const GrTextUtils::Paint& paint,
+                                SkScalerContextFlags scalerContextFlags,
+                                const SkMatrix& viewMatrix,
+                                const SkSurfaceProps& props,
+                                const char text[], size_t byteLength,
+                                SkScalar x, SkScalar y) const {
+    int glyphCount = paint.skPaint().countText(text, byteLength);
+    if (!glyphCount) {
+        return nullptr;
+    }
+    sk_sp<GrTextBlob> blob = blobCache->makeBlob(glyphCount, 1);
+    blob->initThrowawayBlob(viewMatrix, x, y);
+    blob->setRunPaintFlags(0, paint.skPaint().getFlags());
+
+    if (CanDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps.supportsDistanceFieldText(),
+                                fOptions)) {
+        this->drawDFText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix,
+                         text, byteLength, x, y);
+    } else {
+        DrawBmpText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, text,
+                    byteLength, x, y);
+    }
+    return blob;
+}
+
+inline sk_sp<GrTextBlob>
 GrTextContext::makeDrawPosTextBlob(GrTextBlobCache* blobCache,
                                    GrGlyphCache* glyphCache,
                                    const GrShaderCaps& shaderCaps,
@@ -295,6 +311,29 @@
     return blob;
 }
 
+void GrTextContext::drawText(GrContext* context, GrTextUtils::Target* target,
+                             const GrClip& clip, const SkPaint& skPaint,
+                             const SkMatrix& viewMatrix, const SkSurfaceProps& props,
+                             const char text[], size_t byteLength, SkScalar x, SkScalar y,
+                             const SkIRect& regionClipBounds) {
+    if (context->contextPriv().abandoned()) {
+        return;
+    }
+
+    auto glyphCache = context->contextPriv().getGlyphCache();
+    auto textBlobCache = context->contextPriv().getTextBlobCache();
+
+    GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo());
+    sk_sp<GrTextBlob> blob(this->makeDrawTextBlob(
+            textBlobCache, glyphCache, *context->contextPriv().caps()->shaderCaps(), paint,
+            ComputeScalerContextFlags(target->colorSpaceInfo()), viewMatrix, props, text,
+            byteLength, x, y));
+    if (blob) {
+        blob->flush(target, props, fDistanceAdjustTable.get(), paint,
+                    clip, viewMatrix, regionClipBounds, x, y);
+    }
+}
+
 void GrTextContext::drawPosText(GrContext* context, GrTextUtils::Target* target,
                                 const GrClip& clip, const SkPaint& skPaint,
                                 const SkMatrix& viewMatrix, const SkSurfaceProps& props,
@@ -319,6 +358,41 @@
     }
 }
 
+void GrTextContext::DrawBmpText(GrTextBlob* blob, int runIndex,
+                                GrGlyphCache* glyphCache, const SkSurfaceProps& props,
+                                const GrTextUtils::Paint& paint,
+                                SkScalerContextFlags scalerContextFlags,
+                                const SkMatrix& viewMatrix, const char text[],
+                                size_t byteLength, SkScalar x, SkScalar y) {
+    SkASSERT(byteLength == 0 || text != nullptr);
+
+    // nothing to draw
+    if (text == nullptr || byteLength == 0) {
+        return;
+    }
+
+    // Ensure the blob is set for bitmaptext
+    blob->setHasBitmap();
+
+    if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) {
+        DrawBmpTextAsPaths(blob, runIndex, glyphCache, props, paint, scalerContextFlags, viewMatrix,
+                           text, byteLength, x, y);
+        return;
+    }
+
+    sk_sp<GrTextStrike> currStrike;
+    auto cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix);
+    SkFindAndPlaceGlyph::ProcessText(paint.skPaint().getTextEncoding(), text, byteLength, {x, y},
+                                     viewMatrix, paint.skPaint().getTextAlign(), cache.get(),
+                                     [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
+                                         position += rounding;
+                                         BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike,
+                                                        glyph, SkScalarFloorToScalar(position.fX),
+                                                        SkScalarFloorToScalar(position.fY),
+                                                        paint.filteredPremulColor(), cache.get(),
+                                                        SK_Scalar1, false);
+                                     });
+}
 
 void GrTextContext::DrawBmpPosText(GrTextBlob* blob, int runIndex,
                                    GrGlyphCache* glyphCache, const SkSurfaceProps& props,
@@ -358,6 +432,43 @@
             });
 }
 
+void GrTextContext::DrawBmpTextAsPaths(GrTextBlob* blob, int runIndex,
+                                       GrGlyphCache* glyphCache,
+                                       const SkSurfaceProps& props,
+                                       const GrTextUtils::Paint& origPaint,
+                                       SkScalerContextFlags scalerContextFlags,
+                                       const SkMatrix& viewMatrix, const char text[],
+                                       size_t byteLength, SkScalar x, SkScalar y) {
+    // nothing to draw
+    if (text == nullptr || byteLength == 0) {
+        return;
+    }
+
+    // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
+    SkPaint pathPaint(origPaint);
+    pathPaint.setStyle(SkPaint::kFill_Style);
+    pathPaint.setPathEffect(nullptr);
+
+    GrTextUtils::PathTextIter iter(text, byteLength, pathPaint, true);
+    FallbackTextHelper fallbackTextHelper(viewMatrix, pathPaint, glyphCache, iter.getPathScale());
+
+    const SkGlyph* iterGlyph;
+    const SkPath* iterPath;
+    SkScalar xpos = 0;
+    const char* lastText = text;
+    while (iter.next(&iterGlyph, &iterPath, &xpos)) {
+        if (iterGlyph) {
+            SkPoint pos = SkPoint::Make(xpos + x, y);
+            fallbackTextHelper.appendText(*iterGlyph, iter.getText() - lastText, lastText, pos);
+        } else if (iterPath) {
+            blob->appendPathGlyph(runIndex, *iterPath, xpos + x, y, iter.getPathScale(), false);
+        }
+        lastText = iter.getText();
+    }
+
+    fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, origPaint, scalerContextFlags);
+}
+
 void GrTextContext::DrawBmpPosTextAsPaths(GrTextBlob* blob, int runIndex,
                                           GrGlyphCache* glyphCache,
                                           const SkSurfaceProps& props,
@@ -567,6 +678,74 @@
     *flags = SkScalerContextFlags::kNone;
 }
 
+void GrTextContext::drawDFText(GrTextBlob* blob, int runIndex,
+                               GrGlyphCache* glyphCache, const SkSurfaceProps& props,
+                               const GrTextUtils::Paint& paint,
+                               SkScalerContextFlags scalerContextFlags,
+                               const SkMatrix& viewMatrix, const char text[],
+                               size_t byteLength, SkScalar x, SkScalar y) const {
+    SkASSERT(byteLength == 0 || text != nullptr);
+
+    // nothing to draw
+    if (text == nullptr || byteLength == 0) {
+        return;
+    }
+
+    const SkPaint& skPaint = paint.skPaint();
+    SkPaint::GlyphCacheProc glyphCacheProc =
+            SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(), true);
+
+    SkTArray<SkScalar> positions;
+
+    const char* textPtr = text;
+    SkScalar stopX = 0;
+    SkScalar stopY = 0;
+
+    SkAutoDescriptor desc;
+    SkScalerContextEffects effects;
+    // We apply the fake-gamma by altering the distance in the shader, so we ignore the
+    // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
+    SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
+        skPaint, &props, SkScalerContextFlags::kNone, nullptr, &desc, &effects);
+    auto typeface = SkPaintPriv::GetTypefaceOrDefault(skPaint);
+
+    {
+        auto origPaintCache =
+            SkStrikeCache::FindOrCreateStrikeExclusive(*desc.getDesc(), effects, *typeface);
+
+        const char* stop = text + byteLength;
+        while (textPtr < stop) {
+            // don't need x, y here, since all subpixel variants will have the
+            // same advance
+            const SkGlyph& glyph = glyphCacheProc(origPaintCache.get(), &textPtr);
+
+            positions.push_back(stopX);
+            positions.push_back(stopY);
+
+            stopX += SkFloatToScalar(glyph.fAdvanceX);
+            stopY += SkFloatToScalar(glyph.fAdvanceY);
+        }
+        SkASSERT(textPtr == stop);
+    }
+
+    // now adjust starting point depending on alignment
+    SkScalar alignX = stopX;
+    SkScalar alignY = stopY;
+    if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
+        alignX = SkScalarHalf(alignX);
+        alignY = SkScalarHalf(alignY);
+    } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) {
+        alignX = 0;
+        alignY = 0;
+    }
+    x -= alignX;
+    y -= alignY;
+    SkPoint offset = SkPoint::Make(x, y);
+
+    this->drawDFPosText(blob, runIndex, glyphCache, props, paint, scalerContextFlags,
+                        viewMatrix, text, byteLength, positions.begin(), 2, offset);
+}
+
 void GrTextContext::drawDFPosText(GrTextBlob* blob, int runIndex,
                                   GrGlyphCache* glyphCache, const SkSurfaceProps& props,
                                   const GrTextUtils::Paint& paint,
@@ -757,15 +936,11 @@
 
     // right now we don't handle textblobs, nor do we handle drawPosText. Since we only intend to
     // test the text op with this unit test, that is okay.
-
-    auto origin = SkPoint::Make(x, y);
-    auto glyphRun = SkGlyphRun::MakeFromDrawText(skPaint, text, textLen, origin);
-
-    sk_sp<GrTextBlob> blob(textContext->makeDrawPosTextBlob(
+    sk_sp<GrTextBlob> blob(textContext->makeDrawTextBlob(
             context->contextPriv().getTextBlobCache(), glyphCache,
             *context->contextPriv().caps()->shaderCaps(), utilsPaint,
             GrTextContext::kTextBlobOpScalerContextFlags, viewMatrix, surfaceProps, text,
-            static_cast<size_t>(textLen), glyphRun.getPositions(), 2, origin));
+            static_cast<size_t>(textLen), SkIntToScalar(x), SkIntToScalar(y)));
 
     return blob->test_makeOp(textLen, 0, 0, viewMatrix, x, y, utilsPaint, surfaceProps,
                              textContext->dfAdjustTable(), rtc->textTarget());
diff --git a/src/gpu/text/GrTextContext.h b/src/gpu/text/GrTextContext.h
index 7d31d84..3dab70b 100644
--- a/src/gpu/text/GrTextContext.h
+++ b/src/gpu/text/GrTextContext.h
@@ -44,6 +44,9 @@
 
     static std::unique_ptr<GrTextContext> Make(const Options& options);
 
+    void drawText(GrContext*, GrTextUtils::Target*, const GrClip&, const SkPaint&,
+                  const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[],
+                  size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds);
     void drawPosText(GrContext*, GrTextUtils::Target*, const GrClip&, const SkPaint&,
                      const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[],
                      size_t byteLength, const SkScalar pos[], int scalarsPerPosition,
@@ -120,6 +123,15 @@
 
     static bool HasLCD(const SkTextBlob*);
 
+    sk_sp<GrTextBlob> makeDrawTextBlob(GrTextBlobCache*, GrGlyphCache*,
+                                            const GrShaderCaps&,
+                                            const GrTextUtils::Paint&,
+                                            SkScalerContextFlags scalerContextFlags,
+                                            const SkMatrix& viewMatrix,
+                                            const SkSurfaceProps&,
+                                            const char text[], size_t byteLength,
+                                            SkScalar x, SkScalar y) const;
+
     sk_sp<GrTextBlob> makeDrawPosTextBlob(GrTextBlobCache*, GrGlyphCache*,
                                                const GrShaderCaps&,
                                                const GrTextUtils::Paint&,
@@ -132,12 +144,23 @@
                                                const SkPoint& offset) const;
 
     // Functions for appending BMP text to GrTextBlob
+    static void DrawBmpText(GrTextBlob*, int runIndex, GrGlyphCache*,
+                            const SkSurfaceProps&, const GrTextUtils::Paint& paint,
+                            SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix,
+                            const char text[], size_t byteLength, SkScalar x, SkScalar y);
+
     static void DrawBmpPosText(GrTextBlob*, int runIndex, GrGlyphCache*,
                                const SkSurfaceProps&, const GrTextUtils::Paint& paint,
                                SkScalerContextFlags scalerContextFlags, const SkMatrix& viewMatrix,
                                const char text[], size_t byteLength, const SkScalar pos[],
                                int scalarsPerPosition, const SkPoint& offset);
 
+    static void DrawBmpTextAsPaths(GrTextBlob*, int runIndex, GrGlyphCache*,
+                                   const SkSurfaceProps&, const GrTextUtils::Paint& paint,
+                                   SkScalerContextFlags scalerContextFlags,
+                                   const SkMatrix& viewMatrix, const char text[],
+                                   size_t byteLength, SkScalar x, SkScalar y);
+
     static void DrawBmpPosTextAsPaths(GrTextBlob*, int runIndex, GrGlyphCache*,
                                       const SkSurfaceProps&, const GrTextUtils::Paint& paint,
                                       SkScalerContextFlags scalerContextFlags,
@@ -147,6 +170,11 @@
                                       const SkPoint& offset);
 
     // functions for appending distance field text
+    void drawDFText(GrTextBlob* blob, int runIndex, GrGlyphCache*, const SkSurfaceProps&,
+                    const GrTextUtils::Paint& paint, SkScalerContextFlags scalerContextFlags,
+                    const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x,
+                    SkScalar y) const;
+
     void drawDFPosText(GrTextBlob* blob, int runIndex, GrGlyphCache*,
                        const SkSurfaceProps&, const GrTextUtils::Paint& paint,
                        SkScalerContextFlags scalerContextFlags,
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index f4c034e..1cf649c 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1450,6 +1450,12 @@
     }
 }
 
+void SkPDFDevice::drawText(const void* text, size_t len,
+                           SkScalar x, SkScalar y, const SkPaint& paint) {
+    this->internalDrawText(text, len, nullptr, SkTextBlob::kDefault_Positioning,
+                           SkPoint{x, y}, paint, nullptr, 0, nullptr);
+}
+
 void SkPDFDevice::drawPosText(const void* text, size_t len,
                               const SkScalar pos[], int scalarsPerPos,
                               const SkPoint& offset, const SkPaint& paint) {
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index 33d0e70..a9c0590 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -95,6 +95,8 @@
                        const SkRect& dst,
                        const SkPaint&,
                        SkCanvas::SrcRectConstraint) override;
+    void drawText(const void* text, size_t len,
+                  SkScalar x, SkScalar y, const SkPaint&) override;
     void drawPosText(const void* text, size_t len,
                      const SkScalar pos[], int scalarsPerPos,
                      const SkPoint& offset, const SkPaint&) override;
diff --git a/src/svg/SkSVGDevice.cpp b/src/svg/SkSVGDevice.cpp
index 3462f7c..e777f60 100644
--- a/src/svg/SkSVGDevice.cpp
+++ b/src/svg/SkSVGDevice.cpp
@@ -936,6 +936,17 @@
     drawBitmapCommon(MxCp(&adjustedMatrix, cs), bm, paint);
 }
 
+void SkSVGDevice::drawText(const void* text, size_t len,
+                           SkScalar x, SkScalar y, const SkPaint& paint) {
+    AutoElement elem("text", fWriter, fResourceBucket.get(), MxCp(this), paint);
+    elem.addTextAttributes(paint);
+
+    SVGTextBuilder builder(text, len, paint, SkPoint::Make(x, y), 0);
+    elem.addAttribute("x", builder.posX());
+    elem.addAttribute("y", builder.posY());
+    elem.addText(builder.text());
+}
+
 void SkSVGDevice::drawPosText(const void* text, size_t len,
                               const SkScalar pos[], int scalarsPerPos, const SkPoint& offset,
                               const SkPaint& paint) {
diff --git a/src/svg/SkSVGDevice.h b/src/svg/SkSVGDevice.h
index 4784c7e..222e55d 100644
--- a/src/svg/SkSVGDevice.h
+++ b/src/svg/SkSVGDevice.h
@@ -37,6 +37,8 @@
                         const SkRect* srcOrNull, const SkRect& dst,
                         const SkPaint& paint, SkCanvas::SrcRectConstraint) override;
 
+    void drawText(const void* text, size_t len,
+                  SkScalar x, SkScalar y, const SkPaint& paint) override;
     void drawPosText(const void* text, size_t len,
                      const SkScalar pos[], int scalarsPerPos,
                      const SkPoint& offset, const SkPaint& paint) override;
diff --git a/src/xps/SkXPSDevice.cpp b/src/xps/SkXPSDevice.cpp
index ef5f488..29ee8f3 100644
--- a/src/xps/SkXPSDevice.cpp
+++ b/src/xps/SkXPSDevice.cpp
@@ -2047,6 +2047,63 @@
     GlyphRun* const fXpsGlyphs;
 };
 
+void SkXPSDevice::drawText(const void* text, size_t byteLen,
+                           SkScalar x, SkScalar y,
+                           const SkPaint& paint) {
+    if (byteLen < 1) return;
+
+    if (text_must_be_pathed(paint, this->ctm())) {
+        SkPath path;
+        paint.getTextPath(text, byteLen, x, y, &path);
+        this->drawPath(path, paint, nullptr, true);
+        //TODO: add automation "text"
+        return;
+    }
+
+    TypefaceUse* typeface;
+    HRV(CreateTypefaceUse(paint, &typeface));
+
+    auto cache =
+        SkStrikeCache::FindOrCreateStrikeExclusive(
+            paint, &this->surfaceProps(),
+            SkScalerContextFlags::kNone, nullptr);
+
+    // Advance width and offsets for glyphs measured in hundredths of the font em size
+    // (XPS Spec 5.1.3).
+    FLOAT centemPerUnit = 100.0f / SkScalarToFLOAT(paint.getTextSize());
+    GlyphRun xpsGlyphs;
+    xpsGlyphs.setReserve(num_glyph_guess(paint.getTextEncoding(),
+        static_cast<const char*>(text), byteLen));
+
+    ProcessOneGlyph processOneGlyph(centemPerUnit, typeface->glyphsUsed, &xpsGlyphs);
+
+    SkFindAndPlaceGlyph::ProcessText(
+        paint.getTextEncoding(), static_cast<const char*>(text), byteLen,
+        SkPoint{ x, y }, SkMatrix::I(), paint.getTextAlign(), cache.get(), processOneGlyph);
+
+    if (xpsGlyphs.count() == 0) {
+        return;
+    }
+
+    XPS_POINT origin = {
+        xpsGlyphs[0].horizontalOffset / centemPerUnit,
+        xpsGlyphs[0].verticalOffset / -centemPerUnit,
+    };
+    xpsGlyphs[0].horizontalOffset = 0.0f;
+    xpsGlyphs[0].verticalOffset = 0.0f;
+
+    HRV(AddGlyphs(this->fXpsFactory.get(),
+                  this->fCurrentXpsCanvas.get(),
+                  typeface,
+                  nullptr,
+                  xpsGlyphs.begin(), xpsGlyphs.count(),
+                  &origin,
+                  SkScalarToFLOAT(paint.getTextSize()),
+                  XPS_STYLE_SIMULATION_NONE,
+                  this->ctm(),
+                  paint));
+}
+
 void SkXPSDevice::drawPosText(const void* text, size_t byteLen,
                               const SkScalar pos[], int scalarsPerPos,
                               const SkPoint& offset, const SkPaint& paint) {
diff --git a/src/xps/SkXPSDevice.h b/src/xps/SkXPSDevice.h
index 81e881e..a5ee076 100644
--- a/src/xps/SkXPSDevice.h
+++ b/src/xps/SkXPSDevice.h
@@ -97,6 +97,8 @@
                         const SkRect* srcOrNull, const SkRect& dst,
                         const SkPaint& paint,
                         SkCanvas::SrcRectConstraint) override;
+    void drawText(const void* text, size_t len,
+                  SkScalar x, SkScalar y, const SkPaint& paint) override;
     void drawPosText(const void* text, size_t len,
                      const SkScalar pos[], int scalarsPerPos,
                      const SkPoint& offset, const SkPaint& paint) override;
diff --git a/tests/GlyphRunTest.cpp b/tests/GlyphRunTest.cpp
deleted file mode 100644
index cad01ac..0000000
--- a/tests/GlyphRunTest.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkGlyphRun.h"
-
-#include "Test.h"
-
-DEF_TEST(GlyphRunInfo, reporter) {
-    SkGlyphID glyphs[] = {100, 3, 240, 3, 234, 111, 3, 4, 10, 11};
-    uint16_t count = SK_ARRAY_COUNT(glyphs);
-
-    SkPaint paint;
-    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-
-    SkGlyphRun::MakeFromDrawText(paint, glyphs, count, SkPoint::Make(0, 0));
-}
\ No newline at end of file
diff --git a/tests/SVGDeviceTest.cpp b/tests/SVGDeviceTest.cpp
index 6cf533f..b55a35f 100644
--- a/tests/SVGDeviceTest.cpp
+++ b/tests/SVGDeviceTest.cpp
@@ -24,9 +24,6 @@
 #include "SkSVGCanvas.h"
 #include "SkXMLWriter.h"
 
-#if 0
-Using the new system where devices only gets glyphs causes this to fail because the font has no
-glyph to unichar data.
 namespace {
 
 
@@ -52,9 +49,6 @@
     REPORTER_ASSERT(reporter, textNode != nullptr);
     if (textNode != nullptr) {
         REPORTER_ASSERT(reporter, dom.getType(textNode) == SkDOM::kText_Type);
-        if (strcmp(expected, dom.getName(textNode)) != 0) {
-            SkDebugf("string fail %s == %s\n", expected, dom.getName(textNode));
-        }
         REPORTER_ASSERT(reporter, strcmp(expected, dom.getName(textNode)) == 0);
     }
 
@@ -72,9 +66,6 @@
             REPORTER_ASSERT(reporter, xpos[0] == offset.x());
         } else {
             for (int i = 0; i < xposCount; ++i) {
-                if (xpos[i] != SkIntToScalar(expected[i])) {
-                    SkDebugf("Bad xs %g == %g\n", xpos[i], SkIntToScalar(expected[i]));
-                }
                 REPORTER_ASSERT(reporter, xpos[i] == SkIntToScalar(expected[i]));
             }
         }
@@ -112,7 +103,7 @@
         std::unique_ptr<SkCanvas> svgCanvas = SkSVGCanvas::Make(SkRect::MakeWH(100, 100), &writer);
         svgCanvas->drawText(txt, len, offset.x(), offset.y(), paint);
     }
-    check_text_node(reporter, dom, dom.finishParsing(), offset, 2, expected);
+    check_text_node(reporter, dom, dom.finishParsing(), offset, 0, expected);
 
     {
         SkAutoTMalloc<SkScalar> xpos(len);
@@ -124,7 +115,7 @@
         std::unique_ptr<SkCanvas> svgCanvas = SkSVGCanvas::Make(SkRect::MakeWH(100, 100), &writer);
         svgCanvas->drawPosTextH(txt, len, xpos, offset.y(), paint);
     }
-    check_text_node(reporter, dom, dom.finishParsing(), offset, 2, expected);
+    check_text_node(reporter, dom, dom.finishParsing(), offset, 1, expected);
 
     {
         SkAutoTMalloc<SkPoint> pos(len);
@@ -141,7 +132,6 @@
 
 }
 
-
 DEF_TEST(SVGDevice_whitespace_pos, reporter) {
     static const struct {
         const char* tst_in;
@@ -163,7 +153,6 @@
         test_whitespace_pos(reporter, tests[i].tst_in, tests[i].tst_out);
     }
 }
-#endif
 
 
 void SetImageShader(SkPaint* paint, int imageWidth, int imageHeight, SkShader::TileMode xTile,