Use bulk metrics call in SkFont

Unify the handling of glyph metrics data in SkFont.

Change-Id: Ie1ad2a96ba205c0ee4570d70461b9db0cd874918
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/224577
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/src/core/SkFont.cpp b/src/core/SkFont.cpp
index 0f424de..eb0dbbf 100644
--- a/src/core/SkFont.cpp
+++ b/src/core/SkFont.cpp
@@ -209,53 +209,47 @@
     return count;
 }
 
-static void set_bounds(const SkGlyph& g, SkRect* bounds) {
-    *bounds = g.rect();
-}
-
-static void join_bounds_x(const SkGlyph& g, SkRect* bounds, SkScalar dx) {
-    SkRect r = g.rect();
-    r.offset(dx, 0);
-    bounds->join(r);
-}
-
 namespace {
 constexpr int kTypicalGlyphCount = 20;
-using SmallPointsArray = SkAutoSTArray<kTypicalGlyphCount, SkPoint>;
-}
+using GlyphArray = SkAutoSTArray<kTypicalGlyphCount, const SkGlyph*>;
+
+template<typename T>
+SkSpan<T> makeSpan(T* p, size_t s) { return SkSpan<T>{p, s}; }
+}  // namespace
 
 
 SkScalar SkFont::measureText(const void* text, size_t length, SkTextEncoding encoding,
                              SkRect* bounds, const SkPaint* paint) const {
-    SkStrikeSpec strikeSpec = SkStrikeSpec::MakeCanonicalized(*this, paint);
 
     SkAutoToGlyphs atg(*this, text, length, encoding);
-    const int count = atg.count();
-    if (count == 0) {
+    const int glyphCount = atg.count();
+    if (glyphCount == 0) {
         if (bounds) {
             bounds->setEmpty();
         }
         return 0;
     }
-    const SkGlyphID* glyphs = atg.glyphs();
+    const SkGlyphID* glyphIDs = atg.glyphs();
 
-    auto cache = strikeSpec.findOrCreateExclusiveStrike();
+    SkStrikeSpec strikeSpec = SkStrikeSpec::MakeCanonicalized(*this, paint);
+    auto strike = strikeSpec.findOrCreateExclusiveStrike();
+
+    GlyphArray glyphs{glyphCount};
+    strike->metrics(makeSpan(glyphIDs, glyphCount), glyphs.get());
 
     SkScalar width = 0;
     if (bounds) {
-        SkGlyph* g = cache->glyph(glyphs[0]);
-        set_bounds(*g, bounds);
-        width = g->advanceX();
-        for (int i = 1; i < count; ++i) {
-            g = cache->glyph(glyphs[i]);
-            join_bounds_x(*g, bounds, width);
-            width += g->advanceX();
+        *bounds = glyphs[0]->rect();
+        width = glyphs[0]->advanceX();
+        for (int i = 1; i < glyphCount; ++i) {
+            SkRect r = glyphs[i]->rect();
+            r.offset(width, 0);
+            bounds->join(r);
+            width += glyphs[i]->advanceX();
         }
     } else {
-        SmallPointsArray advances{count};
-        cache->getAdvances(SkSpan<const SkGlyphID>{glyphs, SkTo<size_t>(count)}, advances.get());
-        for (int i = 0; i < count; ++i) {
-            width += advances[i].x();
+        for (auto glyph : glyphs) {
+            width += glyph->advanceX();
         }
     }
 
@@ -273,72 +267,59 @@
     return width;
 }
 
-static SkRect make_bounds(const SkGlyph& g, SkScalar scale) {
-    return SkMatrix::MakeScale(scale).mapRect(g.rect());
-}
+void SkFont::getWidthsBounds(const SkGlyphID glyphIDs[],
+                             int count,
+                             SkScalar widths[],
+                             SkRect bounds[],
+                             const SkPaint* paint) const {
+    SkStrikeSpec strikeSpec = SkStrikeSpec::MakeCanonicalized(*this, paint);
+    auto strike = strikeSpec.findOrCreateExclusiveStrike();
+    GlyphArray glyphStorage{count};
+    auto glyphs = strike->metrics(makeSpan(glyphIDs, count), glyphStorage.get());
+    SkScalar scale = strikeSpec.strikeToSourceRatio();
 
-template <typename HANDLER>
-void VisitGlyphs(const SkFont& origFont, const SkPaint* paint, const SkGlyphID glyphs[], int count,
-                 HANDLER handler) {
-    if (count <= 0) {
-        return;
+    if (bounds) {
+        SkMatrix scaleMat = SkMatrix::MakeScale(scale);
+        SkRect* cursor = bounds;
+        for (auto glyph : glyphs) {
+            scaleMat.mapRectScaleTranslate(cursor++, glyph->rect());
+        }
     }
 
-    SkStrikeSpec strikeSpec = SkStrikeSpec::MakeCanonicalized(origFont, paint);
-
-    auto cache = strikeSpec.findOrCreateExclusiveStrike();
-    handler(cache.get(), glyphs, count, strikeSpec.strikeToSourceRatio());
-}
-
-void SkFont::getWidthsBounds(const SkGlyphID glyphs[], int count, SkScalar widths[], SkRect bounds[],
-                             const SkPaint* paint) const {
-    if (bounds) {
-        VisitGlyphs(*this, paint, glyphs, count, [widths, bounds]
-                (SkStrike* cache, const SkGlyphID glyphs[], int count, SkScalar scale) {
-            for (int i = 0; i < count; ++i) {
-                SkGlyph* g;
-                g = cache->glyph(glyphs[i]);
-                bounds[i] = make_bounds(*g, scale);
-                if (widths) {
-                    widths[i] = g->advanceX() * scale;
-                }
-            }
-        });
-    } else if (widths) {
-        SkStrikeSpec strikeSpec = SkStrikeSpec::MakeCanonicalized(*this, paint);
-        auto cache = strikeSpec.findOrCreateExclusiveStrike();
-        SmallPointsArray advances{count};
-        cache->getAdvances(SkSpan<const SkGlyphID>{glyphs, SkTo<size_t>(count)}, advances.get());
-        for (int i = 0; i < count; ++i) {
-            widths[i] = advances[i].x() * strikeSpec.strikeToSourceRatio();
+    if (widths) {
+        SkScalar* cursor = widths;
+        for (auto glyph : glyphs) {
+            *cursor++ = glyph->advanceX() * scale;
         }
     }
 }
 
-void SkFont::getPos(const SkGlyphID glyphs[], int count, SkPoint pos[], SkPoint origin) const {
-    auto glyphIDs = SkSpan<const SkGlyphID>{glyphs, SkTo<size_t>(count)};
+void SkFont::getPos(const SkGlyphID glyphIDs[], int count, SkPoint pos[], SkPoint origin) const {
     SkStrikeSpec strikeSpec = SkStrikeSpec::MakeCanonicalized(*this);
-    auto cache = strikeSpec.findOrCreateExclusiveStrike();
-    SmallPointsArray advancesStorage{count};
-    auto advances = cache->getAdvances(glyphIDs, advancesStorage.get());
+    auto strike = strikeSpec.findOrCreateExclusiveStrike();
+    GlyphArray glyphStorage{count};
+    auto glyphs = strike->metrics(makeSpan(glyphIDs, count), glyphStorage.get());
 
     SkPoint sum = origin;
-    for (auto advance : advances) {
+    for (auto glyph : glyphs) {
         *pos++ = sum;
-        sum += advance * strikeSpec.strikeToSourceRatio();
+        sum += glyph->advanceVector() * strikeSpec.strikeToSourceRatio();
     }
 }
 
-void SkFont::getXPos(const SkGlyphID glyphs[], int count, SkScalar xpos[], SkScalar origin) const {
+void SkFont::getXPos(
+        const SkGlyphID glyphIDs[], int count, SkScalar xpos[], SkScalar origin) const {
 
     SkStrikeSpec strikeSpec = SkStrikeSpec::MakeCanonicalized(*this);
-    auto cache = strikeSpec.findOrCreateExclusiveStrike();
-    SmallPointsArray advances{count};
-    cache->getAdvances(SkSpan<const SkGlyphID>{glyphs, SkTo<size_t>(count)}, advances.get());
+    auto strike = strikeSpec.findOrCreateExclusiveStrike();
+    GlyphArray glyphStorage{count};
+    auto glyphs = strike->metrics(makeSpan(glyphIDs, count), glyphStorage.get());
+
     SkScalar loc = origin;
-    for (int i = 0; i < count; ++i) {
-        xpos[i] = loc;
-        loc += advances[i].x() * strikeSpec.strikeToSourceRatio();
+    SkScalar* cursor = xpos;
+    for (auto glyph : glyphs) {
+        *cursor++ = loc;
+        loc += glyph->advanceX() * strikeSpec.strikeToSourceRatio();
     }
 }
 
diff --git a/src/core/SkStrike.cpp b/src/core/SkStrike.cpp
index e41e368..fbc05c3 100644
--- a/src/core/SkStrike.cpp
+++ b/src/core/SkStrike.cpp
@@ -109,21 +109,21 @@
     return fGlyphMap.count();
 }
 
-SkSpan<const SkGlyph*> SkStrike::metrics(
-        SkSpan<const SkGlyphID>glyphIDs, const SkGlyph* results[]) {
-    size_t glyphCount = 0;
+SkSpan<const SkGlyph*> SkStrike::internalMetrics(
+        SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
+    const SkGlyph** cursor = results;
     for (auto glyphID : glyphIDs) {
-        SkGlyph* glyphPtr = this->glyph(glyphID);
-        results[glyphCount++] = glyphPtr;
+        const SkGlyph* glyphPtr = this->glyph(glyphID);
+        *cursor++ = glyphPtr;
     }
 
-    return {results, glyphCount};
+    return {results, glyphIDs.size()};
 }
 
 SkSpan<SkPoint> SkStrike::getAdvances(SkSpan<const SkGlyphID> glyphIDs, SkPoint advances[]) {
     auto cursor = advances;
     SkAutoSTArray<50, const SkGlyph*> glyphStorage{SkTo<int>(glyphIDs.size())};
-    auto glyphs = this->metrics(glyphIDs, glyphStorage.get());
+    auto glyphs = this->internalMetrics(glyphIDs, glyphStorage.get());
     for (const SkGlyph* glyph : glyphs) {
         *cursor++ = glyph->advanceVector();
     }
@@ -172,6 +172,11 @@
     return SkStrikeCommon::PixelRounding(fIsSubpixel, fAxisAlignment);
 }
 
+SkSpan<const SkGlyph*> SkStrike::metrics(SkSpan<const SkGlyphID> glyphIDs,
+                                         const SkGlyph* results[]) {
+    return this->internalMetrics(glyphIDs, results);
+}
+
 // N.B. This glyphMetrics call culls all the glyphs which will not display based on a non-finite
 // position or that there are no mask pixels.
 SkSpan<const SkGlyphPos> SkStrike::prepareForDrawing(const SkGlyphID glyphIDs[],
diff --git a/src/core/SkStrike.h b/src/core/SkStrike.h
index b872757..6aa30a3 100644
--- a/src/core/SkStrike.h
+++ b/src/core/SkStrike.h
@@ -107,6 +107,9 @@
 
     const SkDescriptor& getDescriptor() const override;
 
+    SkSpan<const SkGlyph*> metrics(SkSpan<const SkGlyphID> glyphIDs,
+                                   const SkGlyph* results[]);
+
     SkSpan<const SkGlyphPos> prepareForDrawing(const SkGlyphID glyphIDs[],
                                                const SkPoint positions[],
                                                size_t n,
@@ -162,9 +165,9 @@
 
     SkGlyph* makeGlyph(SkPackedGlyphID);
 
-    // Metrics will hold a mutex while doing its work. This is one of the few places that will
-    // need a mutex.
-    SkSpan<const SkGlyph*> metrics(SkSpan<const SkGlyphID>glyphIDs, const SkGlyph* result[]);
+    // internalMetrics will only be called with a mutex already held.
+    SkSpan<const SkGlyph*> internalMetrics(
+            SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* result[]);
 
     const SkAutoDescriptor                 fDesc;
     const std::unique_ptr<SkScalerContext> fScalerContext;