diff options
author | Ben Wagner <bungeman@google.com> | 2019-03-20 15:52:21 -0400 |
---|---|---|
committer | Ben Wagner <bungeman@google.com> | 2019-03-22 14:19:03 +0000 |
commit | 47d268ce1867b2090a2cd78724768ea52621b9b1 (patch) | |
tree | b276858ec82e559336645464bfd2a44e7f429929 | |
parent | 80061590f0e2354c4b1e00afe9973f45680a897e (diff) | |
download | skia-47d268ce1867b2090a2cd78724768ea52621b9b1.tar.gz |
Always draw emoji with GPU.
Remove some illogical code which prevents large font size requests for
color fonts from working, and add a large mask fallback when drawing
with masks and there are no paths available.
Change-Id: I3e8c1dfc124cd315278b42cfcfebb39fc32212b8
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/202420
Commit-Queue: Ben Wagner <bungeman@google.com>
Reviewed-by: Herb Derby <herb@google.com>
(cherry picked from commit 3e685ea1648d3c0f687b2f329658266295f2c2ea)
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/202946
Reviewed-by: Ben Wagner <bungeman@google.com>
-rw-r--r-- | src/core/SkGlyphRunPainter.cpp | 80 | ||||
-rw-r--r-- | src/core/SkGlyphRunPainter.h | 10 |
2 files changed, 48 insertions, 42 deletions
diff --git a/src/core/SkGlyphRunPainter.cpp b/src/core/SkGlyphRunPainter.cpp index d938e0edd5..8a6a5e0499 100644 --- a/src/core/SkGlyphRunPainter.cpp +++ b/src/core/SkGlyphRunPainter.cpp @@ -267,19 +267,17 @@ void SkGlyphRunListPainter::drawForBitmapDevice( // transformations from the view matrix. Calculate a text scale based on that reduction. This // scale factor is used to increase the size of the destination rectangles. The destination // rectangles are then scaled, rotated, etc. by the GPU using the view matrix. -void SkGlyphRunListPainter::processARGBFallback(SkScalar maxGlyphDimension, +void SkGlyphRunListPainter::processARGBFallback(SkScalar maxSourceGlyphDimension, const SkPaint& runPaint, const SkFont& runFont, const SkMatrix& viewMatrix, - SkScalar cacheToSourceScale, SkGlyphRunPainterInterface* process) { SkASSERT(!fARGBGlyphsIDs.empty()); SkScalar maxScale = viewMatrix.getMaxScale(); - // This is a conservative estimate of the longest dimension among all the glyph widths and - // heights. - SkScalar conservativeMaxGlyphDimension = maxGlyphDimension * cacheToSourceScale * maxScale; + // This is a linear estimate of the longest dimension among all the glyph widths and heights. + SkScalar conservativeMaxGlyphDimension = maxSourceGlyphDimension * maxScale; // If the situation that the matrix is simple, and all the glyphs are small enough. Go fast! // N.B. If the matrix has scale, that will be reflected in the strike through the viewMatrix @@ -328,19 +326,8 @@ void SkGlyphRunListPainter::processARGBFallback(SkScalar maxGlyphDimension, SkScalar runFontTextSize = runFont.getSize(); // Scale the text size down so the long side of all the glyphs will fit in the atlas. - SkScalar reducedTextSize = - (maxAtlasDimension / conservativeMaxGlyphDimension) * runFontTextSize; - - // If there's a glyph in the font that's particularly large, it's possible - // that fScaledFallbackTextSize may end up minimizing too much. We'd rather skip - // that glyph than make the others blurry, so we set a minimum size of half the - // maximum text size to avoid this case. - SkScalar fallbackTextSize = - SkScalarFloorToScalar(std::max(reducedTextSize, 0.5f * runFontTextSize)); - - // Don't allow the text size to get too big. This will also improve glyph cache hit rate - // for larger text sizes. - fallbackTextSize = std::min(fallbackTextSize, 256.0f); + SkScalar fallbackTextSize = SkScalarFloorToScalar( + (maxAtlasDimension / maxSourceGlyphDimension) * runFontTextSize); SkFont fallbackFont{runFont}; fallbackFont.setSize(fallbackTextSize); @@ -472,10 +459,8 @@ void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunLi { // fGlyphPos will be reused here. if (!fARGBGlyphsIDs.empty()) { - this->processARGBFallback( - maxFallbackDimension, runPaint, glyphRun.font(), viewMatrix, - cacheToSourceScale, - process); + this->processARGBFallback(maxFallbackDimension * cacheToSourceScale, + runPaint, runFont, viewMatrix, process); } } } @@ -536,10 +521,8 @@ void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunLi // fGlyphPos will be reused here. if (!fARGBGlyphsIDs.empty()) { - this->processARGBFallback( - maxFallbackDimension, runPaint, glyphRun.font(), viewMatrix, - strikeToSourceRatio, - process); + this->processARGBFallback(maxFallbackDimension * strikeToSourceRatio, + runPaint, runFont, viewMatrix, process); } } } else { @@ -556,29 +539,40 @@ void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunLi fStrikeCache->findOrCreateScopedStrike(*ad.getDesc(), effects, *typeface); ScopedBuffers _ = this->ensureBuffers(glyphRun); + SkScalar maxFallbackDimension{-SK_ScalarInfinity}; SkMatrix mapping = viewMatrix; mapping.preTranslate(origin.x(), origin.y()); SkVector rounding = strike->rounding(); mapping.postTranslate(rounding.x(), rounding.y()); - mapping.mapPoints(fPositions, glyphRun.positions().data(), glyphRun.runSize()); - - int drawableGlyphCount = strike->glyphMetrics( - glyphRun.glyphsIDs().data(), - fPositions, - glyphRun.glyphsIDs().size(), - fGlyphPos); + mapping.mapPoints(fPositions, glyphRun.positions().data(), glyphRun.runSize()); int glyphsWithMaskCount = 0; - // N.B. this is using the same underlying fGlyphPos array for input and output. - for (int i = 0; i < drawableGlyphCount; i++) { - SkGlyphPos glyphPos = fGlyphPos[i]; - if (SkStrikeCommon::GlyphTooBigForAtlas(*glyphPos.glyph)) { - if (strike->decideCouldDrawFromPath(*glyphPos.glyph)) { - fPaths.push_back(glyphPos); + const SkPoint* positionCursor = glyphRun.positions().data(); + const SkPoint* devicePositionCursor = fPositions; + for (auto glyphID : glyphRun.glyphsIDs()) { + SkPoint glyphPos = *positionCursor++; + SkPoint deviceGlyphPos = *devicePositionCursor++; + if (!SkScalarsAreFinite(deviceGlyphPos.x(), deviceGlyphPos.y())) { + continue; + } + + const SkGlyph& glyph = strike->getGlyphMetrics(glyphID, deviceGlyphPos); + if (glyph.isEmpty()) { + continue; + } + + if (SkStrikeCommon::GlyphTooBigForAtlas(glyph)) { + if (strike->decideCouldDrawFromPath(glyph)) { + fPaths.push_back({&glyph, deviceGlyphPos}); + } else { + SkScalar largestDimension = std::max(glyph.fWidth, glyph.fHeight); + maxFallbackDimension = std::max(maxFallbackDimension, largestDimension); + fARGBGlyphsIDs.push_back(glyph.getGlyphID()); + fARGBPositions.push_back(origin + glyphPos); } } else { - fGlyphPos[glyphsWithMaskCount++] = glyphPos; + fGlyphPos[glyphsWithMaskCount++] = {&glyph, deviceGlyphPos}; } } @@ -591,6 +585,12 @@ void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunLi if (!fPaths.empty()) { process->processDevicePaths(SkSpan<const SkGlyphPos>{fPaths}); } + + // fGlyphPos will be reused here. + if (!fARGBGlyphsIDs.empty()) { + this->processARGBFallback(maxFallbackDimension / viewMatrix.getMaxScale(), + runPaint, runFont, viewMatrix, process); + } } } diff --git a/src/core/SkGlyphRunPainter.h b/src/core/SkGlyphRunPainter.h index 5692c85647..1feff2b223 100644 --- a/src/core/SkGlyphRunPainter.h +++ b/src/core/SkGlyphRunPainter.h @@ -95,11 +95,17 @@ private: // TODO: Remove once I can hoist ensureBuffers above the list for loop in all cases. ScopedBuffers SK_WARN_UNUSED_RESULT ensureBuffers(const SkGlyphRun& glyphRun); - void processARGBFallback(SkScalar maxGlyphDimension, + /** + * @param fARGBPositions in source space + * @param fARGBGlyphsIDs the glyphs to process + * @param fGlyphPos used as scratch space + * @param maxSourceGlyphDimension the longest dimension of any glyph as if all fARGBGlyphsIDs + * were drawn in source space (as if viewMatrix were identity) + */ + void processARGBFallback(SkScalar maxSourceGlyphDimension, const SkPaint& runPaint, const SkFont& runFont, const SkMatrix& viewMatrix, - SkScalar cacheToSourceScale, SkGlyphRunPainterInterface* process); // The props as on the actual device. |