Use SkGlyphRun instead of builder

Move from passing builder down the stack to passing the
object we really want to be the interface down the stack.

Move code that shunts from glyph run style to drawTextPos
to the SkGlyphRun from the builder.

Change-Id: Iefaca69104737ce46c06fbb26dc99996784b2bdb
Reviewed-on: https://skia-review.googlesource.com/135620
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Ben Wagner <bungeman@google.com>
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 494bd3b..be55947 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -2452,7 +2452,8 @@
 
     while (iter.next()) {
         fScratchGlyphRunBuilder->prepareDrawText(paint, text, byteLength, SkPoint::Make(x, y));
-        iter.fDevice->drawGlyphRun(looper.paint(), fScratchGlyphRunBuilder.get());
+        auto glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
+        iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
     }
 
     LOOPER_END
@@ -2465,7 +2466,8 @@
 
     while (iter.next()) {
         fScratchGlyphRunBuilder->prepareDrawPosText(paint, text, byteLength, pos);
-        iter.fDevice->drawGlyphRun(looper.paint(), fScratchGlyphRunBuilder.get());
+        auto glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
+        iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
     }
 
     LOOPER_END
@@ -2478,7 +2480,8 @@
 
     while (iter.next()) {
         fScratchGlyphRunBuilder->prepareDrawPosTextH(paint, text, byteLength, xpos, constY);
-        iter.fDevice->drawGlyphRun(looper.paint(), fScratchGlyphRunBuilder.get());
+        const auto& glyphRun = fScratchGlyphRunBuilder->useGlyphRun();
+        iter.fDevice->drawGlyphRun(looper.paint(), glyphRun);
     }
 
     LOOPER_END
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index aea08c5..2356098 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -165,7 +165,8 @@
             auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
             SkGlyphRunBuilder builder;
             builder.prepareDrawText(runPaint, (const char*) it.glyphs(), textLen, origin);
-            builder.temporaryShuntToDrawPosText(runPaint, this);
+            auto glyphRun = builder.useGlyphRun();
+            glyphRun->temporaryShuntToDrawPosText(runPaint, this);
         }
         break;
         case SkTextBlob::kHorizontal_Positioning:
@@ -251,11 +252,11 @@
     }
 }
 
-void SkBaseDevice::drawGlyphRun(const SkPaint& paint, SkGlyphRunBuilder* runBuilder) {
+void SkBaseDevice::drawGlyphRun(const SkPaint& paint, SkGlyphRun* glyphRun) {
     SkPaint glyphPaint(paint);
     glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
 
-    runBuilder->temporaryShuntToDrawPosText(glyphPaint, this);
+    glyphRun->temporaryShuntToDrawPosText(glyphPaint, this);
 }
 
 void SkBaseDevice::drawBitmapLattice(const SkBitmap& bitmap,
diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h
index 2500833..f840cf6 100644
--- a/src/core/SkDevice.h
+++ b/src/core/SkDevice.h
@@ -224,7 +224,7 @@
      *  Does not handle text decoration.
      *  Decorations (underline and stike-thru) will be handled by SkCanvas.
      */
-    virtual void drawGlyphRun(const SkPaint& paint, SkGlyphRunBuilder* info);
+    virtual void drawGlyphRun(const SkPaint& paint, SkGlyphRun* glyphRun);
     virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) = 0;
     virtual void drawShadow(const SkPath&, const SkDrawShadowRec&);
 
@@ -348,7 +348,7 @@
     friend class DeviceTestingAccess;
 
     // Temporarily friend the SkGlyphRunBuilder until drawPosText is gone.
-    friend class SkGlyphRunBuilder;
+    friend class SkGlyphRun;
     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 caea07a..29c1dfd 100644
--- a/src/core/SkGlyphRun.cpp
+++ b/src/core/SkGlyphRun.cpp
@@ -76,6 +76,24 @@
     // correctly even when the fIndexes buffer is uninitialized!
 }
 
+// -- SkGlyphRun -----------------------------------------------------------------------------------
+
+void SkGlyphRun::temporaryShuntToDrawPosText(const SkPaint& paint, SkBaseDevice* device) {
+
+    auto pos = (const SkScalar*) fPositions.data();
+
+    device->drawPosText(
+            fTemporaryShuntGlyphIDs.data(), fDenseIndex.size() * sizeof(SkGlyphID),
+            pos, 2, SkPoint::Make(0, 0), paint);
+}
+
+void SkGlyphRun::temporaryShuntToCallback(TemporaryShuntCallback callback) {
+    auto bytes = (const char *)fTemporaryShuntGlyphIDs.data();
+    auto pos = (const SkScalar*)fPositions.data();
+    callback(this->runSize(), bytes, pos);
+}
+
+
 // -- SkGlyphRunBuilder ----------------------------------------------------------------------------
 void SkGlyphRunBuilder::prepareDrawText(
         const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin) {
@@ -127,26 +145,14 @@
     }
 }
 
-const SkGlyphRun& SkGlyphRunBuilder::useGlyphRun() const {
+SkGlyphRun* SkGlyphRunBuilder::useGlyphRun() {
+    fScratchGlyphRun.~SkGlyphRun();
     new ((void*)&fScratchGlyphRun) SkGlyphRun{SkSpan<uint16_t>(fDenseIndex),
-                                       SkSpan<SkPoint>(fPositions),
-                                       SkSpan<SkGlyphID>(fUniqueGlyphs)};
-    return fScratchGlyphRun;
-}
-
-void SkGlyphRunBuilder::temporaryShuntToDrawPosText(const SkPaint& paint, SkBaseDevice* device) {
-
-    auto pos = (const SkScalar*) fPositions.data();
-
-    device->drawPosText(
-            fTemporaryShuntGlyphIDs, fDenseIndex.size() * 2,
-            pos, 2, SkPoint::Make(0, 0), paint);
-}
-
-void SkGlyphRunBuilder::temporaryShuntToCallback(TemporaryShuntCallback callback) {
-    auto bytes = (const char *)fTemporaryShuntGlyphIDs;
-    auto pos = (const SkScalar*)fPositions.data();
-    callback(this->runSize(), bytes, pos);
+                                              SkSpan<SkPoint>(fPositions),
+                                              SkSpan<SkGlyphID>(
+                                                      fTemporaryShuntGlyphIDs, fDenseIndex.size()),
+                                              SkSpan<SkGlyphID>(fUniqueGlyphs)};
+    return &fScratchGlyphRun;
 }
 
 void SkGlyphRunBuilder::initializeDenseAndUnique(
@@ -175,6 +181,8 @@
         glyphIDs = (const SkGlyphID*)bytes;
     }
 
+    SkASSERT(glyphIDs != nullptr);
+
     if (runSize == 0) { return; }
     fTemporaryShuntGlyphIDs = glyphIDs;
 
diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h
index eeb9c29..243d5d1 100644
--- a/src/core/SkGlyphRun.h
+++ b/src/core/SkGlyphRun.h
@@ -23,13 +23,17 @@
 template <typename T>
 class SkSpan {
 public:
-    SkSpan() = default;
+    SkSpan() : fPtr{nullptr}, fSize{0} {}
     SkSpan(const T* ptr, size_t size) : fPtr{ptr}, fSize{size} {}
     explicit 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; }
+    T* begin() const { return fPtr; }
+    T* end() const { return fPtr + fSize; }
+    const T* cbegin() const { return fPtr; }
+    const T* cend() const { return fPtr + fSize; }
+    const T* data() const { return fPtr; }
     ptrdiff_t size() const { return fSize; }
+    bool empty() const { return fSize == 0; }
 
 private:
     const T* fPtr;
@@ -39,20 +43,37 @@
 class SkGlyphRun {
 public:
     SkGlyphRun() = default;
-    SkGlyphRun(SkSpan<uint16_t> denseIndex, SkSpan<SkPoint> positions,
+    SkGlyphRun(SkSpan<uint16_t>  denseIndex,
+               SkSpan<SkPoint>   positions,
+               SkSpan<SkGlyphID> scratchGlyphs,
                SkSpan<SkGlyphID> uniqueGlyphIDs)
             : fDenseIndex{denseIndex}
             , fPositions{positions}
-            , fUniqueGlyphIDs{uniqueGlyphIDs} {}
+            , fTemporaryShuntGlyphIDs{scratchGlyphs}
+            , fUniqueGlyphIDs{uniqueGlyphIDs} {
+        SkASSERT(denseIndex.size() == positions.size());
+        SkASSERT(denseIndex.size() == scratchGlyphs.size());
+    }
+
+    // The temporaryShunt calls are to allow inter-operating with existing code while glyph runs
+    // are developed.
+    void temporaryShuntToDrawPosText(const SkPaint& paint, SkBaseDevice* device);
+    using TemporaryShuntCallback = std::function<void(size_t, const char*, const SkScalar*)>;
+    void temporaryShuntToCallback(TemporaryShuntCallback callback);
 
     size_t runSize() const { return fDenseIndex.size(); }
     uint16_t uniqueSize() const { return fUniqueGlyphIDs.size(); }
     SkSpan<SkPoint> positions() const { return SkSpan<SkPoint>(fPositions); }
 
 private:
-    SkSpan<uint16_t>  fDenseIndex;
-    SkSpan<SkPoint>   fPositions;
-    SkSpan<SkGlyphID> fUniqueGlyphIDs;
+    // Indices into the unique glyph IDs. On for each original glyph.
+    const SkSpan<uint16_t>  fDenseIndex;
+    // The base line position of all the glyphs in source space.
+    const SkSpan<SkPoint>   fPositions;
+    // This is temporary while converting from the old per glyph code to the bulk code.
+    const SkSpan<SkGlyphID> fTemporaryShuntGlyphIDs;
+    // The set of unique glyphs in the run.
+    const SkSpan<SkGlyphID> fUniqueGlyphIDs;
 };
 
 // A faster set implementation that does not need any initialization, and reading the set items
@@ -89,13 +110,7 @@
     size_t runSize() const {return fDenseIndex.size();}
     size_t uniqueSize() const {return fUniqueGlyphs.size();}
 
-    const SkGlyphRun& useGlyphRun() const;
-
-    // The temporaryShunt calls are to allow inter-operating with existing code while glyph runs
-    // are developed.
-    void temporaryShuntToDrawPosText(const SkPaint& paint, SkBaseDevice* device);
-    using TemporaryShuntCallback = std::function<void(size_t, const char*, const SkScalar*)>;
-    void temporaryShuntToCallback(TemporaryShuntCallback callback);
+    SkGlyphRun* useGlyphRun();
 
 private:
     void initializeDenseAndUnique(const SkPaint& paint, const void* bytes, size_t byteLength);
@@ -119,7 +134,7 @@
     const SkGlyphID*       fTemporaryShuntGlyphIDs{nullptr};
 
     // Used for collecting the set of unique glyphs.
-    SkGlyphSet            fGlyphSet;
+    SkGlyphSet             fGlyphSet;
 };
 
 #endif  // SkGlyphRunInfo_DEFINED
diff --git a/src/gpu/text/GrTextContext.cpp b/src/gpu/text/GrTextContext.cpp
index b63b726..6da4c0d 100644
--- a/src/gpu/text/GrTextContext.cpp
+++ b/src/gpu/text/GrTextContext.cpp
@@ -217,7 +217,9 @@
                     builder.prepareDrawText(runPaint.skPaint(),
                                             (const char*)it.glyphs(), textLen, origin);
 
-                    builder.temporaryShuntToCallback(
+                    auto glyphRun = builder.useGlyphRun();
+
+                    glyphRun->temporaryShuntToCallback(
                             [&](size_t runSize, const char* glyphIDs, const SkScalar* pos) {
                                 this->drawDFPosText(
                                     cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
@@ -250,7 +252,9 @@
                     builder.prepareDrawText(runPaint.skPaint(),
                                             (const char*)it.glyphs(), textLen, origin);
 
-                    builder.temporaryShuntToCallback(
+                    auto glyphRun = builder.useGlyphRun();
+
+                    glyphRun->temporaryShuntToCallback(
                             [&](size_t runSize, const char* glyphIDs, const SkScalar* pos) {
                                 this->DrawBmpPosText(
                                     cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
@@ -782,8 +786,9 @@
     builder.prepareDrawText(skPaint, text, textLen, origin);
     sk_sp<GrTextBlob> blob;
 
+    auto glyphRun = builder.useGlyphRun();
     // Use the text and textLen below, because we don't want to mess with the paint.
-    builder.temporaryShuntToCallback(
+    glyphRun->temporaryShuntToCallback(
             [&](size_t runSize, const char* glyphIDs, const SkScalar* pos) {
                 blob = textContext->makeDrawPosTextBlob(
                     context->contextPriv().getTextBlobCache(), glyphCache,