Move path fallback logic into drawer
Change-Id: I6960b775f92b1013e0a826ac6aa1f8464ebf99f8 Reviewed-on: https://skia-review.googlesource.com/145000 Commit-Queue: Herb Derby <herb@google.com> Reviewed-by: Mike Klein <mtklein@google.com> Reviewed-by: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
f83cacb770
commit
9a52a39468
@ -162,7 +162,7 @@ public:
|
||||
|
||||
void initWithGlyphID(SkPackedGlyphID glyph_id);
|
||||
|
||||
bool isEmpty() {
|
||||
bool isEmpty() const {
|
||||
return fWidth == 0 || fHeight == 0;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#endif
|
||||
|
||||
#include "SkDevice.h"
|
||||
#include "SkDistanceFieldGen.h"
|
||||
#include "SkDraw.h"
|
||||
#include "SkFindAndPlaceGlyph.h"
|
||||
#include "SkGlyphCache.h"
|
||||
@ -137,6 +138,76 @@ SkGlyphRunListDrawer::SkGlyphRunListDrawer(const GrRenderTargetContext& rtc)
|
||||
: SkGlyphRunListDrawer{rtc.surfaceProps(), rtc.colorSpaceInfo()} {}
|
||||
#endif
|
||||
|
||||
// TODO: all this logic should move to the glyph cache.
|
||||
static const SkGlyph& lookup_glyph_by_subpixel(
|
||||
SkAxisAlignment axisAlignment, SkPoint position, SkGlyphID glyphID, SkGlyphCache* cache) {
|
||||
SkFixed lookupX = SkScalarToFixed(SkScalarFraction(position.x())),
|
||||
lookupY = SkScalarToFixed(SkScalarFraction(position.y()));
|
||||
|
||||
// Snap to a given axis if alignment is requested.
|
||||
if (axisAlignment == kX_SkAxisAlignment) {
|
||||
lookupY = 0;
|
||||
} else if (axisAlignment == kY_SkAxisAlignment) {
|
||||
lookupX = 0;
|
||||
}
|
||||
|
||||
return cache->getGlyphIDMetrics(glyphID, lookupX, lookupY);
|
||||
}
|
||||
|
||||
|
||||
// forEachMappedDrawableGlyph handles positioning for mask type glyph handling for both sub-pixel
|
||||
// and full pixel positioning.
|
||||
template <typename EachGlyph>
|
||||
void SkGlyphRunListDrawer::forEachMappedDrawableGlyph(
|
||||
const SkGlyphRun& glyphRun, SkPoint origin, const SkMatrix& deviceMatrix,
|
||||
SkGlyphCache* cache, EachGlyph eachGlyph) {
|
||||
bool isSubpixel = cache->isSubpixel();
|
||||
|
||||
SkAxisAlignment axisAlignment = kNone_SkAxisAlignment;
|
||||
SkMatrix mapping = deviceMatrix;
|
||||
mapping.preTranslate(origin.x(), origin.y());
|
||||
// TODO: all this logic should move to the glyph cache.
|
||||
if (isSubpixel) {
|
||||
axisAlignment = cache->getScalerContext()->computeAxisAlignmentForHText();
|
||||
SkPoint rounding = SkFindAndPlaceGlyph::SubpixelPositionRounding(axisAlignment);
|
||||
mapping.postTranslate(rounding.x(), rounding.y());
|
||||
} else {
|
||||
mapping.postTranslate(SK_ScalarHalf, SK_ScalarHalf);
|
||||
}
|
||||
|
||||
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())) {
|
||||
// TODO: all this logic should move to the glyph cache.
|
||||
const SkGlyph& glyph =
|
||||
isSubpixel ? lookup_glyph_by_subpixel(axisAlignment, mappedPt, glyphID, cache)
|
||||
: cache->getGlyphIDMetrics(glyphID);
|
||||
if (!glyph.isEmpty()) {
|
||||
// Prevent glyphs from being drawn outside of or straddling the edge
|
||||
// of device space. Comparisons written a little weirdly so that NaN
|
||||
// coordinates are treated safely.
|
||||
auto le = [](float a, int b) { return a <= (float)b; };
|
||||
auto ge = [](float a, int b) { return a >= (float)b; };
|
||||
if (le(mappedPt.fX, INT_MAX - (INT16_MAX + SkTo<int>(UINT16_MAX))) &&
|
||||
ge(mappedPt.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) &&
|
||||
le(mappedPt.fY, INT_MAX - (INT16_MAX + SkTo<int>(UINT16_MAX))) &&
|
||||
ge(mappedPt.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)))
|
||||
{
|
||||
eachGlyph(glyph, pt, mappedPt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SkGlyphRunListDrawer::ShouldDrawAsPath(const SkPaint& paint, const SkMatrix& matrix) {
|
||||
// hairline glyphs are fast enough so we don't need to cache them
|
||||
if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
|
||||
@ -218,6 +289,10 @@ static bool prepare_mask(
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool glyph_too_big_for_atlas(const SkGlyph& glyph) {
|
||||
return glyph.fWidth >= 256 || glyph.fHeight >= 256;
|
||||
}
|
||||
|
||||
void SkGlyphRunListDrawer::drawGlyphRunAsSubpixelMask(
|
||||
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
||||
SkPoint origin, const SkMatrix& deviceMatrix,
|
||||
@ -256,6 +331,29 @@ void SkGlyphRunListDrawer::drawGlyphRunAsSubpixelMask(
|
||||
}
|
||||
}
|
||||
|
||||
void SkGlyphRunListDrawer::drawGlyphRunAsGlyphWithPathFallback(
|
||||
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
||||
SkPoint origin, const SkMatrix& deviceMatrix,
|
||||
PerGlyph perGlyph, PerPath perPath) {
|
||||
auto eachGlyph =
|
||||
[cache, perGlyph{std::move(perGlyph)}, perPath{std::move(perPath)}]
|
||||
(const SkGlyph& glyph, SkPoint pt, SkPoint mappedPt) {
|
||||
if (glyph_too_big_for_atlas(glyph)) {
|
||||
const SkPath* glyphPath = cache->findPath(glyph);
|
||||
if (glyphPath != nullptr) {
|
||||
perPath(glyphPath, glyph, mappedPt);
|
||||
}
|
||||
} else {
|
||||
const void* glyphImage = cache->findImage(glyph);
|
||||
if (glyphImage != nullptr) {
|
||||
perGlyph(glyph, mappedPt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this->forEachMappedDrawableGlyph(glyphRun, origin, deviceMatrix, cache, eachGlyph);
|
||||
}
|
||||
|
||||
void SkGlyphRunListDrawer::drawGlyphRunAsFullpixelMask(
|
||||
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
||||
SkPoint origin, const SkMatrix& deviceMatrix,
|
||||
@ -283,6 +381,7 @@ void SkGlyphRunListDrawer::drawGlyphRunAsFullpixelMask(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SkGlyphRunListDrawer::drawForBitmapDevice(
|
||||
const SkGlyphRunList& glyphRunList, const SkMatrix& deviceMatrix,
|
||||
PerMaskCreator perMaskCreator, PerPathCreator perPathCreator) {
|
||||
@ -322,8 +421,7 @@ void SkGlyphRunListDrawer::drawForBitmapDevice(
|
||||
|
||||
void SkGlyphRunListDrawer::drawUsingMasks(
|
||||
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
||||
SkPoint origin, const SkMatrix& deviceMatrix,
|
||||
SkGlyphRunListDrawer::PerMask perMask) {
|
||||
SkPoint origin, const SkMatrix& deviceMatrix, PerMask perMask) {
|
||||
if (cache->isSubpixel()) {
|
||||
this->drawGlyphRunAsSubpixelMask(cache, glyphRun, origin, deviceMatrix, perMask);
|
||||
} else {
|
||||
|
@ -117,6 +117,7 @@ public:
|
||||
explicit SkGlyphRunListDrawer(const GrRenderTargetContext& renderTargetContext);
|
||||
#endif
|
||||
|
||||
using PerGlyph = std::function<void(const SkGlyph&, SkPoint)>;
|
||||
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)>;
|
||||
@ -131,17 +132,31 @@ public:
|
||||
void drawUsingPaths(
|
||||
const SkGlyphRun& glyphRun, SkPoint origin, SkGlyphCache* cache, PerPath perPath) const;
|
||||
|
||||
void drawGlyphRunAsGlyphWithPathFallback(
|
||||
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
||||
SkPoint origin, const SkMatrix& deviceMatrix,
|
||||
PerGlyph perGlyph, PerPath perPath);
|
||||
|
||||
private:
|
||||
static bool ShouldDrawAsPath(const SkPaint& paint, const SkMatrix& matrix);
|
||||
bool ensureBitmapBuffers(size_t runSize);
|
||||
|
||||
|
||||
template <typename EachGlyph>
|
||||
void forEachMappedDrawableGlyph(
|
||||
const SkGlyphRun& glyphRun, SkPoint origin, const SkMatrix& deviceMatrix,
|
||||
SkGlyphCache* 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.
|
||||
|
@ -238,31 +238,27 @@ void GrTextContext::regenerateGlyphRunList(GrTextBlob* cacheBlob,
|
||||
auto cache = cacheBlob->setupCache(
|
||||
runIndex, props, scalerContextFlags, runPaint, &viewMatrix);
|
||||
|
||||
auto drawOneGlyph =
|
||||
auto perGlyph =
|
||||
[cacheBlob, runIndex, glyphCache, &currStrike, runPaint, cache{cache.get()}]
|
||||
(const SkMask& mask, const SkGlyph& glyph, SkPoint position) {
|
||||
SkScalar sx = SkScalarFloorToScalar(position.fX),
|
||||
sy = SkScalarFloorToScalar(position.fY);
|
||||
|
||||
if (glyph_too_big_for_atlas(glyph)) {
|
||||
SkRect glyphRect =
|
||||
rect_to_draw(glyph, {sx, sy}, SK_Scalar1,
|
||||
GrGlyph::kCoverage_MaskStyle);
|
||||
if (!glyphRect.isEmpty()) {
|
||||
const SkPath* glyphPath = cache->findPath(glyph);
|
||||
if (glyphPath != nullptr) {
|
||||
cacheBlob->appendPathGlyph(
|
||||
runIndex, *glyphPath, sx, sy, SK_Scalar1, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AppendGlyph(cacheBlob, runIndex, glyphCache, &currStrike,
|
||||
glyph, GrGlyph::kCoverage_MaskStyle, sx, sy,
|
||||
runPaint.filteredPremulColor(), cache, SK_Scalar1, false);
|
||||
}
|
||||
(const SkGlyph& glyph, SkPoint mappedPt) {
|
||||
SkScalar sx = SkScalarFloorToScalar(mappedPt.fX),
|
||||
sy = SkScalarFloorToScalar(mappedPt.fY);
|
||||
AppendGlyph(cacheBlob, runIndex, glyphCache, &currStrike,
|
||||
glyph, GrGlyph::kCoverage_MaskStyle, sx, sy,
|
||||
runPaint.filteredPremulColor(), cache, SK_Scalar1, false);
|
||||
};
|
||||
|
||||
glyphDrawer->drawUsingMasks(cache.get(), glyphRun, origin, viewMatrix, drawOneGlyph);
|
||||
auto perPath =
|
||||
[cacheBlob, runIndex]
|
||||
(const SkPath* path, const SkGlyph& glyph, SkPoint position) {
|
||||
SkScalar sx = SkScalarFloorToScalar(position.fX),
|
||||
sy = SkScalarFloorToScalar(position.fY);
|
||||
cacheBlob->appendPathGlyph(
|
||||
runIndex, *path, sx, sy, SK_Scalar1, true);
|
||||
};
|
||||
|
||||
glyphDrawer->drawGlyphRunAsGlyphWithPathFallback(
|
||||
cache.get(), glyphRun, origin, viewMatrix, perGlyph, perPath);
|
||||
}
|
||||
runIndex += 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user