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;