Find the best font size for too big glyphs
If the font produces glyphs that won't fit in the atlas then:
Given the original font as a starting point, find a smaller font
where the maximum glyphs size will fit in the atlas with room for
padding.
From that new font size, calculate a scale factor that will
make the smaller glyphs the same size as the original font.
This is the second attempt at this code.
Change-Id: I2add9a8e9bae59546b7e8c3bbd5c17eb48d90f65
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/554401
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
diff --git a/src/text/gpu/SubRunContainer.cpp b/src/text/gpu/SubRunContainer.cpp
index 6901e7e..2f8cc94 100644
--- a/src/text/gpu/SubRunContainer.cpp
+++ b/src/text/gpu/SubRunContainer.cpp
@@ -2527,44 +2527,58 @@
// dimension.
const SkSpan<const SkGlyphID> glyphs = rejected->source().get<0>();
- // For glyphs that won't fit in the atlas, calculating the amount to reduce the size
- // can't be done using simple ratios. This is because the SkScaler forces glyph width
- // and height to integer amounts causing the ratio to be too high if it rounds up.
- // If it does round up, you need to try again to find the maximum glyph dimensions
- // and scale factor.
+ // It could be that this font produces glyphs that won't fit in the atlas. Find the
+ // largest glyph dimension for the glyph run.
+ SkStrikeSpec gaugingStrikeSpec = SkStrikeSpec::MakeTransformMask(
+ runFont, runPaint, deviceProps, scalerContextFlags, *gaugingMatrix);
+ SkScopedStrikeForGPU gaugingStrike =
+ gaugingStrikeSpec.findOrCreateScopedStrike(strikeCache);
+
+ // Remember, this will be an integer.
+ const SkScalar originalMaxGlyphDimension =
+ gaugingStrike->findMaximumGlyphDimension(glyphs);
+
SkScalar strikeToSourceScale = 1;
SkFont reducedFont = runFont;
- SkScalar maxGlyphDimension;
- do {
- reducedFont.setSize(reducedFont.getSize() / strikeToSourceScale);
+ if (originalMaxGlyphDimension > kMaxBilerpAtlasDimension) {
+ // For glyphs that won't fit in the atlas, calculating the amount to reduce the
+ // size can't be done using simple ratios. This is because the SkScaler forces
+ // glyph width and height to integer amounts causing the ratio to be too high if
+ // it rounds up. If it does round up, you need to try again to find the maximum
+ // glyph dimensions and scale factor.
+ SkScalar maxGlyphDimension = originalMaxGlyphDimension;
+ SkScalar reductionFactor = kMaxBilerpAtlasDimension / maxGlyphDimension;
- // Gauge the scale factor needed to reduce the font size by.
- SkStrikeSpec gaugingStrikeSpec = SkStrikeSpec::MakeTransformMask(
- reducedFont, runPaint, deviceProps, scalerContextFlags, *gaugingMatrix);
+ // Find a new reducedFont that produces a maximum glyph dimension that is
+ // <= kMaxBilerpAtlasDimension.
+ do {
+ // Make a smaller font that will hopefully fit in the atlas.
+ reducedFont.setSize(runFont.getSize() * reductionFactor);
- // A strike that is too big, but will give an accurate maximum glyph dimension.
- SkScopedStrikeForGPU gaugingStrike =
- gaugingStrikeSpec.findOrCreateScopedStrike(strikeCache);
+ // Create a strike to calculate the new reduced maximum glyph dimension.
+ SkStrikeSpec reducingStrikeSpec = SkStrikeSpec::MakeTransformMask(
+ reducedFont, runPaint, deviceProps, scalerContextFlags, *gaugingMatrix);
+ SkScopedStrikeForGPU reducingStrike =
+ reducingStrikeSpec.findOrCreateScopedStrike(strikeCache);
- // Remember, this will be an integer.
- maxGlyphDimension = gaugingStrike->findMaximumGlyphDimension(glyphs);
+ // Remember, this will be an integer.
+ maxGlyphDimension = reducingStrike->findMaximumGlyphDimension(glyphs);
- // If the glyphs are too big we need to calculate a scaling factor to allow the
- // image of the glyph to fit in the atlas.
- if (kMaxBilerpAtlasDimension < maxGlyphDimension) {
- SkScalar candidateStrikeToSourceScale =
- maxGlyphDimension / kMaxBilerpAtlasDimension;
- // Be sure that strikeToSourceCache is always getting bigger to avoid an
- // infinite loop.
- if (candidateStrikeToSourceScale > strikeToSourceScale) {
- // Yep. Getting bigger.
- strikeToSourceScale = candidateStrikeToSourceScale;
- } else {
- // Force it bigger.
- strikeToSourceScale *= 1.01f;
- }
- }
- } while (kMaxBilerpAtlasDimension < maxGlyphDimension);
+ // The largest reduction factor allowed for each iteration. Smaller reduction
+ // factors reduce the font size faster.
+ static constexpr SkScalar kMaximumReduction =
+ 1.0f - 1.0f / kMaxBilerpAtlasDimension;
+
+ // Make the reduction smaller by at least kMaximumReduction in case the
+ // maximum glyph dimension is too big.
+ reductionFactor *=
+ std::min(kMaximumReduction, kMaxBilerpAtlasDimension/maxGlyphDimension);
+ } while (maxGlyphDimension > kMaxBilerpAtlasDimension);
+
+ // Calculate the factor to make the maximum dimension of the reduced font be the
+ // same size as the maximum dimension from the original runFont.
+ strikeToSourceScale = originalMaxGlyphDimension / maxGlyphDimension;
+ }
if (!SkScalarNearlyZero(strikeToSourceScale)) {
SkStrikeSpec strikeSpec = SkStrikeSpec::MakeTransformMask(