blob: 64f8444a41e9a78074eb6bd47f1c610a508c2b32 [file] [log] [blame]
/*
* Copyright 2018 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGlyphRunPainter_DEFINED
#define SkGlyphRunPainter_DEFINED
#include "SkGlyphRun.h"
#if SK_SUPPORT_GPU
class GrColorSpaceInfo;
class GrRenderTargetContext;
#endif
class SkGlyphRunListPainter {
public:
// Constructor for SkBitmpapDevice.
SkGlyphRunListPainter(
const SkSurfaceProps& props, SkColorType colorType, SkScalerContextFlags flags);
#if SK_SUPPORT_GPU
SkGlyphRunListPainter(const SkSurfaceProps&, const GrColorSpaceInfo&);
explicit SkGlyphRunListPainter(const GrRenderTargetContext& renderTargetContext);
#endif
using PerMask = std::function<void(const SkMask&, const SkGlyph&, SkPoint)>;
using PerMaskCreator = std::function<PerMask(const SkPaint&, SkArenaAlloc* alloc)>;
using PerPath = std::function<void(const SkPath*, const SkGlyph&, SkPoint)>;
using PerPathCreator = std::function<PerPath(
const SkPaint&, SkScalar matrixScale, SkArenaAlloc* alloc)>;
void drawForBitmapDevice(
const SkGlyphRunList& glyphRunList, const SkMatrix& deviceMatrix,
PerMaskCreator perMaskCreator, PerPathCreator perPathCreator);
void drawUsingMasks(
SkGlyphCache* cache, const SkGlyphRun& glyphRun, SkPoint origin,
const SkMatrix& deviceMatrix, PerMask perMask);
void drawUsingPaths(
const SkGlyphRun& glyphRun, SkPoint origin, SkGlyphCache* cache, PerPath perPath) const;
template <typename PerGlyphT, typename PerPathT>
void drawGlyphRunAsBMPWithPathFallback(
SkGlyphCacheInterface* cache, const SkGlyphRun& glyphRun,
SkPoint origin, const SkMatrix& deviceMatrix,
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.
// PerPath - perPath(const SkGlyph&, SkPoint position)
// 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
// and the position in fallback vectors. After all the glyphs are processed, pass the
// fallback glyphIDs and positions to fallbackARGB.
template <typename PerPath>
void drawGlyphRunAsPathWithARGBFallback(
SkGlyphCacheInterface* cache, const SkGlyphRun& glyphRun,
SkPoint origin, const SkMatrix& viewMatrix, SkScalar textScale,
PerPath perPath, ARGBFallback fallbackARGB);
template <typename PerSDFT, typename PerPathT, typename PerFallbackT>
void drawGlyphRunAsSDFWithFallback(
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
SkPoint origin, SkScalar textRatio,
PerSDFT perSDF, PerPathT perPath, PerFallbackT perFallback);
private:
static bool ShouldDrawAsPath(const SkPaint& paint, const SkMatrix& matrix);
bool ensureBitmapBuffers(size_t runSize);
void processARGBFallback(
SkScalar maxGlyphDimension, const SkPaint& runPaint, SkPoint origin,
const SkMatrix& viewMatrix, SkScalar textScale, ARGBFallback argbFallback);
template <typename EachGlyph>
void forEachMappedDrawableGlyph(
const SkGlyphRun& glyphRun, SkPoint origin, const SkMatrix& deviceMatrix,
SkGlyphCacheInterface* cache, EachGlyph eachGlyph);
void drawGlyphRunAsSubpixelMask(
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
SkPoint origin, const SkMatrix& deviceMatrix,
PerMask perMask);
void drawGlyphRunAsFullpixelMask(
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
SkPoint origin, const SkMatrix& deviceMatrix,
PerMask perMask);
// The props as on the actual device.
const SkSurfaceProps fDeviceProps;
// The props for when the bitmap device can't draw LCD text.
const SkSurfaceProps fBitmapFallbackProps;
const SkColorType fColorType;
const SkScalerContextFlags fScalerContextFlags;
size_t fMaxRunSize{0};
SkAutoTMalloc<SkPoint> fPositions;
// Vectors for tracking ARGB fallback information.
std::vector<SkGlyphID> fARGBGlyphsIDs;
std::vector<SkPoint> fARGBPositions;
};
inline static SkRect rect_to_draw(
const SkGlyph& glyph, SkPoint origin, SkScalar textScale, bool isDFT) {
SkScalar dx = SkIntToScalar(glyph.fLeft);
SkScalar dy = SkIntToScalar(glyph.fTop);
SkScalar width = SkIntToScalar(glyph.fWidth);
SkScalar height = SkIntToScalar(glyph.fHeight);
if (isDFT) {
dx += SK_DistanceFieldInset;
dy += SK_DistanceFieldInset;
width -= 2 * SK_DistanceFieldInset;
height -= 2 * SK_DistanceFieldInset;
}
dx *= textScale;
dy *= textScale;
width *= textScale;
height *= textScale;
return SkRect::MakeXYWH(origin.x() + dx, origin.y() + dy, width, height);
}
// forEachMappedDrawableGlyph handles positioning for mask type glyph handling for both sub-pixel
// and full pixel positioning.
template <typename EachGlyph>
void SkGlyphRunListPainter::forEachMappedDrawableGlyph(
const SkGlyphRun& glyphRun, SkPoint origin, const SkMatrix& deviceMatrix,
SkGlyphCacheInterface* cache, EachGlyph eachGlyph) {
SkMatrix mapping = deviceMatrix;
mapping.preTranslate(origin.x(), origin.y());
SkVector rounding = cache->rounding();
mapping.postTranslate(rounding.x(), rounding.y());
auto runSize = glyphRun.runSize();
if (this->ensureBitmapBuffers(runSize)) {
mapping.mapPoints(fPositions, glyphRun.positions().data(), runSize);
const SkPoint* mappedPtCursor = fPositions;
const SkPoint* ptCursor = glyphRun.positions().data();
for (auto glyphID : glyphRun.shuntGlyphsIDs()) {
auto mappedPt = *mappedPtCursor++;
auto pt = origin + *ptCursor++;
if (SkScalarsAreFinite(mappedPt.x(), mappedPt.y())) {
const SkGlyph& glyph = cache->getGlyphMetrics(glyphID, mappedPt);
eachGlyph(glyph, pt, mappedPt);
}
}
}
}
template <typename PerPathT>
void SkGlyphRunListPainter::drawGlyphRunAsPathWithARGBFallback(
SkGlyphCacheInterface* pathCache, const SkGlyphRun& glyphRun,
SkPoint origin, const SkMatrix& viewMatrix, SkScalar textScale,
PerPathT perPath, ARGBFallback argbFallback) {
fARGBGlyphsIDs.clear();
fARGBPositions.clear();
SkScalar maxFallbackDimension{-SK_ScalarInfinity};
auto eachGlyph =
[this, pathCache, origin, perPath{std::move(perPath)}, &maxFallbackDimension]
(SkGlyphID glyphID, SkPoint position) {
if (SkScalarsAreFinite(position.x(), position.y())) {
const SkGlyph& glyph = pathCache->getGlyphMetrics(glyphID, {0, 0});
if (!glyph.isEmpty()) {
if (glyph.fMaskFormat != SkMask::kARGB32_Format) {
perPath(glyph, origin + position);
} else {
SkScalar largestDimension = std::max(glyph.fWidth, glyph.fHeight);
maxFallbackDimension = std::max(maxFallbackDimension, largestDimension);
fARGBGlyphsIDs.push_back(glyphID);
fARGBPositions.push_back(position);
}
}
}
};
glyphRun.forEachGlyphAndPosition(eachGlyph);
if (!fARGBGlyphsIDs.empty()) {
this->processARGBFallback(
maxFallbackDimension, glyphRun.paint(), origin, viewMatrix, textScale, argbFallback);
}
}
template <typename PerGlyphT, typename PerPathT>
void SkGlyphRunListPainter::drawGlyphRunAsBMPWithPathFallback(
SkGlyphCacheInterface* cache, const SkGlyphRun& glyphRun,
SkPoint origin, const SkMatrix& deviceMatrix,
PerGlyphT perGlyph, PerPathT perPath) {
auto eachGlyph =
[perGlyph{std::move(perGlyph)}, perPath{std::move(perPath)}]
(const SkGlyph& glyph, SkPoint pt, SkPoint mappedPt) {
if (SkGlyphCacheCommon::GlyphTooBigForAtlas(glyph)) {
SkScalar sx = SkScalarFloorToScalar(mappedPt.fX),
sy = SkScalarFloorToScalar(mappedPt.fY);
SkRect glyphRect =
rect_to_draw(glyph, {sx, sy}, SK_Scalar1, false);
if (!glyphRect.isEmpty()) {
perPath(glyph, mappedPt);
}
} else {
perGlyph(glyph, mappedPt);
}
};
this->forEachMappedDrawableGlyph(glyphRun, origin, deviceMatrix, cache, eachGlyph);
}
#endif // SkGlyphRunPainter_DEFINED