Move ARGB fallback helper into Painter

Currently, the fallback helper is a static used by the GPU
code to handle fallback glyphs. This code must be common to
both GPU and Renderer so it needs to be in the Painter.

Change-Id: I367a87b1dc785d67996a13ee42d74f2162c1b765
Reviewed-on: https://skia-review.googlesource.com/157300
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
Herb Derby 2018-09-26 17:01:18 -04:00 committed by Skia Commit-Bot
parent b6ef9e43d7
commit 93ba1e0041
2 changed files with 49 additions and 55 deletions

View File

@ -413,8 +413,6 @@ void GrTextContext::AppendGlyph(GrTextBlob* blob, int runIndex,
} }
} }
enum NeedsTransform : bool {kTransformDone = false, kDoTransform = true };
// Getting glyphs to the screen in a fallback situation can be complex. Here is the set of // Getting glyphs to the screen in a fallback situation can be complex. Here is the set of
// transformations that have to happen. Normally, they would all be accommodated by the font // transformations that have to happen. Normally, they would all be accommodated by the font
// scaler, but the atlas has an upper limit to the glyphs it can handle. So the GPU is used to // scaler, but the atlas has an upper limit to the glyphs it can handle. So the GPU is used to
@ -437,49 +435,37 @@ enum NeedsTransform : bool {kTransformDone = false, kDoTransform = true };
// scale factor is used to increase the size of the destination rectangles. The destination // 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. // rectangles are then scaled, rotated, etc. by the GPU using the view matrix.
using ARGBFallback = void SkGlyphRunListPainter::processARGBFallback(
std::function<void(const SkPaint& fallbackPaint, // The run paint maybe with a new text size SkScalar maxGlyphDimension, const SkPaint& runPaint, SkPoint origin,
SkSpan<const SkGlyphID> fallbackGlyphIDs, // Colored glyphs that need to be handled const SkMatrix& viewMatrix, SkScalar textScale, ARGBFallback argbFallback) {
SkSpan<const SkPoint> fallbackPositions, // Positions of above glyphs SkASSERT(!fARGBGlyphsIDs.empty());
SkScalar fallbackTextScale, // Factor to go from text size to final size
const SkMatrix& glyphCacheMatrix, // Transformation performed by the glyph cache
NeedsTransform handleTransformLater)>;
static void ARGB_fallback_helper(
SkSpan<const SkGlyphID> glyphIDs,
SkSpan<const SkPoint> positions,
SkScalar maxGlyphDimension,
const SkPaint& runPaint,
const SkMatrix& viewMatrix,
SkScalar pathScale,
ARGBFallback fallback) {
SkASSERT(!glyphIDs.empty());
SkScalar maxScale = viewMatrix.getMaxScale(); SkScalar maxScale = viewMatrix.getMaxScale();
// This is a conservative estimate of the longest dimension among all the glyph widths and // This is a conservative estimate of the longest dimension among all the glyph widths and
// heights. // heights.
SkScalar conservativeMaxGlyphDimension = maxGlyphDimension * pathScale * maxScale; SkScalar conservativeMaxGlyphDimension = maxGlyphDimension * textScale * maxScale;
// If the situation that the matrix is simple, and all the glyphs are small enough. Go fast! // If the situation that the matrix is simple, and all the glyphs are small enough. Go fast!
bool useFastPath = bool useFastPath =
viewMatrix.isScaleTranslate() && conservativeMaxGlyphDimension <= maxGlyphDimension; viewMatrix.isScaleTranslate() && conservativeMaxGlyphDimension <= maxGlyphDimension;
auto glyphIDs = SkSpan<const SkGlyphID>{fARGBGlyphsIDs};
// A scaled and translated transform is the common case, and is handled directly in fallback. // A scaled and translated transform is the common case, and is handled directly in fallback.
// Even if the transform is scale and translate, fallback must be careful to use glyphs that // Even if the transform is scale and translate, fallback must be careful to use glyphs that
// fit in the atlas. If a glyph will not fit in the atlas, then the general transform case is // fit in the atlas. If a glyph will not fit in the atlas, then the general transform case is
// used to render the glyphs. // used to render the glyphs.
if (useFastPath) { if (useFastPath) {
// Translate the positions to device space. // Translate the positions to device space.
std::vector<SkPoint> transformedPositions{positions.begin(), positions.end()}; viewMatrix.mapPoints(fARGBPositions.data(), fARGBPositions.size());
viewMatrix.mapPoints(transformedPositions.data(), transformedPositions.size()); for (SkPoint& point : fARGBPositions) {
for (SkPoint& point : transformedPositions) {
point.fX = SkScalarFloorToScalar(point.fX); point.fX = SkScalarFloorToScalar(point.fX);
point.fY = SkScalarFloorToScalar(point.fY); point.fY = SkScalarFloorToScalar(point.fY);
} }
auto pos = SkSpan<const SkPoint>{transformedPositions}; auto positions = SkSpan<const SkPoint>{fARGBPositions};
fallback(runPaint, glyphIDs, pos, SK_Scalar1, viewMatrix, kTransformDone); argbFallback(runPaint, glyphIDs, positions, SK_Scalar1, viewMatrix, kTransformDone);
} else { } else {
// If the matrix is complicated or if scaling is used to fit the glyphs in the cache, // If the matrix is complicated or if scaling is used to fit the glyphs in the cache,
@ -508,13 +494,12 @@ static void ARGB_fallback_helper(
SkPaint fallbackPaint{runPaint}; SkPaint fallbackPaint{runPaint};
fallbackPaint.setTextSize(fallbackTextSize); fallbackPaint.setTextSize(fallbackTextSize);
SkScalar fallbackTextScale = runPaintTextSize / fallbackTextSize; SkScalar fallbackTextScale = runPaintTextSize / fallbackTextSize;
auto positions = SkSpan<const SkPoint>{fARGBPositions};
fallback( argbFallback(
fallbackPaint, glyphIDs, positions, fallbackTextScale, SkMatrix::I(), kDoTransform); fallbackPaint, glyphIDs, positions, fallbackTextScale, SkMatrix::I(), kDoTransform);
} }
} }
void GrTextContext::regenerateGlyphRunList(GrTextBlob* cacheBlob, void GrTextContext::regenerateGlyphRunList(GrTextBlob* cacheBlob,
GrGlyphCache* glyphCache, GrGlyphCache* glyphCache,
const GrShaderCaps& shaderCaps, const GrShaderCaps& shaderCaps,
@ -622,7 +607,8 @@ void GrTextContext::regenerateGlyphRunList(GrTextBlob* cacheBlob,
[blob{cacheBlob}, runIndex, props, scalerContextFlags, glyphCache, filteredColor] [blob{cacheBlob}, runIndex, props, scalerContextFlags, glyphCache, filteredColor]
(const SkPaint& fallbackPaint, SkSpan<const SkGlyphID> glyphIDs, (const SkPaint& fallbackPaint, SkSpan<const SkGlyphID> glyphIDs,
SkSpan<const SkPoint> positions, SkScalar textScale, SkSpan<const SkPoint> positions, SkScalar textScale,
const SkMatrix& glyphCacheMatrix, NeedsTransform needsTransform) { const SkMatrix& glyphCacheMatrix,
SkGlyphRunListPainter::NeedsTransform needsTransform) {
blob->initOverride(runIndex); blob->initOverride(runIndex);
blob->setHasBitmap(); blob->setHasBitmap();
blob->setSubRunHasW(runIndex, glyphCacheMatrix.hasPerspective()); blob->setSubRunHasW(runIndex, glyphCacheMatrix.hasPerspective());
@ -641,18 +627,8 @@ void GrTextContext::regenerateGlyphRunList(GrTextBlob* cacheBlob,
} }
}; };
// Calculate paint, matrix, scale and positions for the fallback glyphs.
auto fallbackARGB = [&runPaint, &viewMatrix, textScale, argbFallback]
(SkSpan<const SkGlyphID> glyphIDs,
SkSpan<const SkPoint>positions,
SkScalar maxGlyphDimension) {
ARGB_fallback_helper(glyphIDs, positions, maxGlyphDimension, runPaint,
viewMatrix, textScale, argbFallback);
};
glyphPainter->drawGlyphRunAsPathWithARGBFallback( glyphPainter->drawGlyphRunAsPathWithARGBFallback(
pathCache.get(), glyphRun, origin, perPath, fallbackARGB); pathCache.get(), glyphRun, origin, viewMatrix, textScale, perPath, argbFallback);
} else { } else {
// Ensure the blob is set for bitmaptext // Ensure the blob is set for bitmaptext
cacheBlob->setHasBitmap(); cacheBlob->setHasBitmap();

View File

@ -46,16 +46,27 @@ public:
SkPoint origin, const SkMatrix& deviceMatrix, SkPoint origin, const SkMatrix& deviceMatrix,
PerGlyphT perGlyph, PerPathT perPath); PerGlyphT perGlyph, PerPathT perPath);
enum NeedsTransform : bool { kTransformDone = false, kDoTransform = true };
using ARGBFallback =
std::function<void(const SkPaint& fallbackPaint, // The run paint maybe with a new text size
SkSpan<const SkGlyphID> fallbackGlyphIDs, // Colored glyphs
SkSpan<const SkPoint> fallbackPositions, // Positions of above glyphs
SkScalar fallbackTextScale, // Scale factor for glyph
const SkMatrix& glyphCacheMatrix, // Matrix of glyph cache
NeedsTransform handleTransformLater)>; // Positions / glyph transformed
// Draw glyphs as paths with fallback to scaled ARGB glyphs if color is needed. // Draw glyphs as paths with fallback to scaled ARGB glyphs if color is needed.
// PerPath - perPath(const SkGlyph&, SkPoint position) // PerPath - perPath(const SkGlyph&, SkPoint position)
// FallbackARGB - fallbackARGB(SkSpan<const SkGlyphID>, SkSpan<const SkPoint>) // FallbackARGB - fallbackARGB(SkSpan<const SkGlyphID>, SkSpan<const SkPoint>)
// For each glyph that is not ARGB call perPath. If the glyph is ARGB then store the glyphID // For each glyph that is not ARGB call perPath. If the glyph is ARGB then store the glyphID
// and the position in fallback vectors. After all the glyphs are processed, pass the // and the position in fallback vectors. After all the glyphs are processed, pass the
// fallback glyphIDs and positions to fallbackARGB. // fallback glyphIDs and positions to fallbackARGB.
template <typename PerPath, typename FallbackARGB> template <typename PerPath>
void drawGlyphRunAsPathWithARGBFallback( void drawGlyphRunAsPathWithARGBFallback(
SkGlyphCacheInterface* cache, const SkGlyphRun& glyphRun, SkGlyphCacheInterface* cache, const SkGlyphRun& glyphRun,
SkPoint origin, PerPath perPath, FallbackARGB fallbackARGB); SkPoint origin, const SkMatrix& viewMatrix, SkScalar textScale,
PerPath perPath, ARGBFallback fallbackARGB);
template <typename PerSDFT, typename PerPathT, typename PerFallbackT> template <typename PerSDFT, typename PerPathT, typename PerFallbackT>
void drawGlyphRunAsSDFWithFallback( void drawGlyphRunAsSDFWithFallback(
@ -67,6 +78,9 @@ private:
static bool ShouldDrawAsPath(const SkPaint& paint, const SkMatrix& matrix); static bool ShouldDrawAsPath(const SkPaint& paint, const SkMatrix& matrix);
bool ensureBitmapBuffers(size_t runSize); bool ensureBitmapBuffers(size_t runSize);
void processARGBFallback(
SkScalar maxGlyphDimension, const SkPaint& runPaint, SkPoint origin,
const SkMatrix& viewMatrix, SkScalar textScale, ARGBFallback argbFallback);
template <typename EachGlyph> template <typename EachGlyph>
void forEachMappedDrawableGlyph( void forEachMappedDrawableGlyph(
@ -91,6 +105,10 @@ private:
const SkScalerContextFlags fScalerContextFlags; const SkScalerContextFlags fScalerContextFlags;
size_t fMaxRunSize{0}; size_t fMaxRunSize{0};
SkAutoTMalloc<SkPoint> fPositions; SkAutoTMalloc<SkPoint> fPositions;
// Vectors for tracking ARGB fallback information.
std::vector<SkGlyphID> fARGBGlyphsIDs;
std::vector<SkPoint> fARGBPositions;
}; };
inline static SkRect rect_to_draw( inline static SkRect rect_to_draw(
@ -143,17 +161,17 @@ void SkGlyphRunListPainter::forEachMappedDrawableGlyph(
} }
} }
template <typename PerPathT, typename FallbackARGB> template <typename PerPathT>
void SkGlyphRunListPainter::drawGlyphRunAsPathWithARGBFallback( void SkGlyphRunListPainter::drawGlyphRunAsPathWithARGBFallback(
SkGlyphCacheInterface* pathCache, const SkGlyphRun& glyphRun, SkGlyphCacheInterface* pathCache, const SkGlyphRun& glyphRun,
SkPoint origin, PerPathT perPath, FallbackARGB fallbackARGB) { SkPoint origin, const SkMatrix& viewMatrix, SkScalar textScale,
std::vector<SkGlyphID> fallbackGlyphIDs; PerPathT perPath, ARGBFallback argbFallback) {
std::vector<SkPoint> fallbackPositions; fARGBGlyphsIDs.clear();
fARGBPositions.clear();
SkScalar maxFallbackDimension{-SK_ScalarInfinity}; SkScalar maxFallbackDimension{-SK_ScalarInfinity};
auto eachGlyph = auto eachGlyph =
[pathCache, origin, perPath{std::move(perPath)}, [this, pathCache, origin, perPath{std::move(perPath)}, &maxFallbackDimension]
&fallbackGlyphIDs, &fallbackPositions, &maxFallbackDimension]
(SkGlyphID glyphID, SkPoint position) { (SkGlyphID glyphID, SkPoint position) {
if (SkScalarsAreFinite(position.x(), position.y())) { if (SkScalarsAreFinite(position.x(), position.y())) {
const SkGlyph& glyph = pathCache->getGlyphMetrics(glyphID, {0, 0}); const SkGlyph& glyph = pathCache->getGlyphMetrics(glyphID, {0, 0});
@ -163,8 +181,8 @@ void SkGlyphRunListPainter::drawGlyphRunAsPathWithARGBFallback(
} else { } else {
SkScalar largestDimension = std::max(glyph.fWidth, glyph.fHeight); SkScalar largestDimension = std::max(glyph.fWidth, glyph.fHeight);
maxFallbackDimension = std::max(maxFallbackDimension, largestDimension); maxFallbackDimension = std::max(maxFallbackDimension, largestDimension);
fallbackGlyphIDs.push_back(glyphID); fARGBGlyphsIDs.push_back(glyphID);
fallbackPositions.push_back(position); fARGBPositions.push_back(position);
} }
} }
} }
@ -172,10 +190,10 @@ void SkGlyphRunListPainter::drawGlyphRunAsPathWithARGBFallback(
glyphRun.forEachGlyphAndPosition(eachGlyph); glyphRun.forEachGlyphAndPosition(eachGlyph);
if (!fallbackGlyphIDs.empty()) { if (!fARGBGlyphsIDs.empty()) {
fallbackARGB(SkSpan<const SkGlyphID>{fallbackGlyphIDs}, this->processARGBFallback(
SkSpan<const SkPoint>{fallbackPositions}, maxFallbackDimension, glyphRun.paint(), origin, viewMatrix, textScale, argbFallback);
maxFallbackDimension);
} }
} }