more simple makers for textblobs

To aid in the transition away from drawText, drawPosText, etc.
... see https://skia-review.googlesource.com/c/skia/+/175240

Definitely need to have a follow-on discussion about tradeoffs for the
various positioning backends.

Bug: skia:
Change-Id: I236e151f6604d868dc18f98503c371f41593ec6e
Reviewed-on: https://skia-review.googlesource.com/c/175248
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/include/core/SkTextBlob.h b/include/core/SkTextBlob.h
index 1e07e1a..934791e 100644
--- a/include/core/SkTextBlob.h
+++ b/include/core/SkTextBlob.h
@@ -80,6 +80,39 @@
         return MakeFromText(string, strlen(string), font, encoding);
     }
 
+    /** Experimental.
+        Returns a textblob built from a single run of text with x-positions and a single y value.
+        This is equivalent to using SkTextBlobBuilder and calling allocRunPosH().
+        Returns nullptr if byteLength is zero.
+
+        @param text        character code points or glyphs drawn (based on encoding)
+        @param byteLength  byte length of text array
+        @param xpos    array of x-positions, must contain values for all of the character points.
+        @param constY  shared y-position for each character point, to be paired with each xpos.
+        @param font    SkFont used for this run
+        @param encoding specifies the encoding of the text array.
+        @return        new textblob or nullptr
+     */
+    static sk_sp<SkTextBlob> MakeFromPosTextH(const void* text, size_t byteLength,
+                                      const SkScalar xpos[], SkScalar constY, const SkFont& font,
+                                      SkTextEncoding encoding = kUTF8_SkTextEncoding);
+
+    /** Experimental.
+        Returns a textblob built from a single run of text with positions.
+        This is equivalent to using SkTextBlobBuilder and calling allocRunPos().
+        Returns nullptr if byteLength is zero.
+
+        @param text        character code points or glyphs drawn (based on encoding)
+        @param byteLength  byte length of text array
+        @param pos     array of positions, must contain values for all of the character points.
+        @param font    SkFont used for this run
+        @param encoding specifies the encoding of the text array.
+        @return        new textblob or nullptr
+     */
+    static sk_sp<SkTextBlob> MakeFromPosText(const void* text, size_t byteLength,
+                                             const SkPoint pos[], const SkFont& font,
+                                             SkTextEncoding encoding = kUTF8_SkTextEncoding);
+
     /** Writes data to allow later reconstruction of SkTextBlob. memory points to storage
         to receive the encoded data, and memory_size describes the size of storage.
         Returns bytes used if provided storage is large enough to hold all data;
diff --git a/src/core/SkFont.cpp b/src/core/SkFont.cpp
index 1b0a86b..8f3fd9c 100644
--- a/src/core/SkFont.cpp
+++ b/src/core/SkFont.cpp
@@ -150,22 +150,7 @@
 
     SkASSERT(text);
 
-    int count = 0;  // fix uninitialized warning (even though the switch is complete!)
-
-    switch (encoding) {
-        case kUTF8_SkTextEncoding:
-            count = SkUTF::CountUTF8((const char*)text, byteLength);
-            break;
-        case kUTF16_SkTextEncoding:
-            count = SkUTF::CountUTF16((const uint16_t*)text, byteLength);
-            break;
-        case kUTF32_SkTextEncoding:
-            count = SkToInt(byteLength >> 2);
-            break;
-        case kGlyphID_SkTextEncoding:
-            count = SkToInt(byteLength >> 1);
-            break;
-    }
+    int count = SkFontPriv::CountTextElements(text, byteLength, encoding);
     if (!glyphs || count > maxGlyphCount) {
         return count;
     }
@@ -542,3 +527,18 @@
     return bounds;
 }
 
+int SkFontPriv::CountTextElements(const void* text, size_t byteLength, SkTextEncoding encoding) {
+    switch (encoding) {
+        case kUTF8_SkTextEncoding:
+            return SkUTF::CountUTF8(reinterpret_cast<const char*>(text), byteLength);
+        case kUTF16_SkTextEncoding:
+            return SkUTF::CountUTF16(reinterpret_cast<const uint16_t*>(text), byteLength);
+        case kUTF32_SkTextEncoding:
+            return byteLength >> 2;
+        case kGlyphID_SkTextEncoding:
+            return byteLength >> 1;
+    }
+    SkASSERT(false);
+    return 0;
+}
+
diff --git a/src/core/SkFontPriv.h b/src/core/SkFontPriv.h
index 1d1cfc1..a0bbec3 100644
--- a/src/core/SkFontPriv.h
+++ b/src/core/SkFontPriv.h
@@ -58,6 +58,9 @@
         @return  union of bounds of all glyphs
      */
     static SkRect GetFontBounds(const SkFont&);
+
+    // Returns the number of elements (characters or glyphs) in the array.
+    static int CountTextElements(const void* text, size_t byteLength, SkTextEncoding);
 };
 
 class SkAutoToGlyphs {
diff --git a/src/core/SkTextBlob.cpp b/src/core/SkTextBlob.cpp
index 2e6b427..6d1adbf 100644
--- a/src/core/SkTextBlob.cpp
+++ b/src/core/SkTextBlob.cpp
@@ -718,24 +718,36 @@
 
 sk_sp<SkTextBlob> SkTextBlob::MakeFromText(const void* text, size_t byteLength, const SkFont& font,
                                            SkTextEncoding encoding) {
-    SkPaint legacyPaint;
-    font.LEGACY_applyToPaint(&legacyPaint);
-    legacyPaint.setTextEncoding(encoding);
+    // Note: we deliberately promote this to fully positioned blobs, since we'd have to pay the
+    // same cost down stream (i.e. computing bounds), so its cheaper to pay the cost once now.
+    const int count = font.countText(text, byteLength, encoding);
+    SkTextBlobBuilder builder;
+    auto buffer = builder.allocRunPos(font, count);
+    font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
+    font.getPos(buffer.glyphs, count, reinterpret_cast<SkPoint*>(buffer.pos), {0, 0});
+    return builder.make();
+}
 
-    SkGlyphRunBuilder runBuilder;
+sk_sp<SkTextBlob> SkTextBlob::MakeFromPosText(const void* text, size_t byteLength,
+                                              const SkPoint pos[], const SkFont& font,
+                                              SkTextEncoding encoding) {
+    const int count = font.countText(text, byteLength, encoding);
+    SkTextBlobBuilder builder;
+    auto buffer = builder.allocRunPos(font, count);
+    font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
+    memcpy(buffer.pos, pos, count * sizeof(SkPoint));
+    return builder.make();
+}
 
-    runBuilder.drawText(legacyPaint, text, byteLength, SkPoint::Make(0, 0));
-
-    auto glyphRunList = runBuilder.useGlyphRunList();
-    SkTextBlobBuilder blobBuilder;
-    if (!glyphRunList.empty()) {
-        auto run = glyphRunList[0];
-
-        auto runData = blobBuilder.allocRunPos(font, run.runSize());
-        run.filloutGlyphsAndPositions(runData.glyphs, (SkPoint *)runData.pos);
-    }
-
-    return blobBuilder.make();
+sk_sp<SkTextBlob> SkTextBlob::MakeFromPosTextH(const void* text, size_t byteLength,
+                                               const SkScalar xpos[], SkScalar constY,
+                                               const SkFont& font, SkTextEncoding encoding) {
+    const int count = font.countText(text, byteLength, encoding);
+    SkTextBlobBuilder builder;
+    auto buffer = builder.allocRunPosH(font, count, constY);
+    font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
+    memcpy(buffer.pos, xpos, count * sizeof(SkScalar));
+    return builder.make();
 }
 
 sk_sp<SkData> SkTextBlob::serialize(const SkSerialProcs& procs) const {