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);
|
void initWithGlyphID(SkPackedGlyphID glyph_id);
|
||||||
|
|
||||||
bool isEmpty() {
|
bool isEmpty() const {
|
||||||
return fWidth == 0 || fHeight == 0;
|
return fWidth == 0 || fHeight == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "SkDevice.h"
|
#include "SkDevice.h"
|
||||||
|
#include "SkDistanceFieldGen.h"
|
||||||
#include "SkDraw.h"
|
#include "SkDraw.h"
|
||||||
#include "SkFindAndPlaceGlyph.h"
|
#include "SkFindAndPlaceGlyph.h"
|
||||||
#include "SkGlyphCache.h"
|
#include "SkGlyphCache.h"
|
||||||
@ -137,6 +138,76 @@ SkGlyphRunListDrawer::SkGlyphRunListDrawer(const GrRenderTargetContext& rtc)
|
|||||||
: SkGlyphRunListDrawer{rtc.surfaceProps(), rtc.colorSpaceInfo()} {}
|
: SkGlyphRunListDrawer{rtc.surfaceProps(), rtc.colorSpaceInfo()} {}
|
||||||
#endif
|
#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) {
|
bool SkGlyphRunListDrawer::ShouldDrawAsPath(const SkPaint& paint, const SkMatrix& matrix) {
|
||||||
// hairline glyphs are fast enough so we don't need to cache them
|
// hairline glyphs are fast enough so we don't need to cache them
|
||||||
if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
|
if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
|
||||||
@ -218,6 +289,10 @@ static bool prepare_mask(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool glyph_too_big_for_atlas(const SkGlyph& glyph) {
|
||||||
|
return glyph.fWidth >= 256 || glyph.fHeight >= 256;
|
||||||
|
}
|
||||||
|
|
||||||
void SkGlyphRunListDrawer::drawGlyphRunAsSubpixelMask(
|
void SkGlyphRunListDrawer::drawGlyphRunAsSubpixelMask(
|
||||||
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
||||||
SkPoint origin, const SkMatrix& deviceMatrix,
|
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(
|
void SkGlyphRunListDrawer::drawGlyphRunAsFullpixelMask(
|
||||||
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
||||||
SkPoint origin, const SkMatrix& deviceMatrix,
|
SkPoint origin, const SkMatrix& deviceMatrix,
|
||||||
@ -283,6 +381,7 @@ void SkGlyphRunListDrawer::drawGlyphRunAsFullpixelMask(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SkGlyphRunListDrawer::drawForBitmapDevice(
|
void SkGlyphRunListDrawer::drawForBitmapDevice(
|
||||||
const SkGlyphRunList& glyphRunList, const SkMatrix& deviceMatrix,
|
const SkGlyphRunList& glyphRunList, const SkMatrix& deviceMatrix,
|
||||||
PerMaskCreator perMaskCreator, PerPathCreator perPathCreator) {
|
PerMaskCreator perMaskCreator, PerPathCreator perPathCreator) {
|
||||||
@ -322,8 +421,7 @@ void SkGlyphRunListDrawer::drawForBitmapDevice(
|
|||||||
|
|
||||||
void SkGlyphRunListDrawer::drawUsingMasks(
|
void SkGlyphRunListDrawer::drawUsingMasks(
|
||||||
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
||||||
SkPoint origin, const SkMatrix& deviceMatrix,
|
SkPoint origin, const SkMatrix& deviceMatrix, PerMask perMask) {
|
||||||
SkGlyphRunListDrawer::PerMask perMask) {
|
|
||||||
if (cache->isSubpixel()) {
|
if (cache->isSubpixel()) {
|
||||||
this->drawGlyphRunAsSubpixelMask(cache, glyphRun, origin, deviceMatrix, perMask);
|
this->drawGlyphRunAsSubpixelMask(cache, glyphRun, origin, deviceMatrix, perMask);
|
||||||
} else {
|
} else {
|
||||||
|
@ -117,6 +117,7 @@ public:
|
|||||||
explicit SkGlyphRunListDrawer(const GrRenderTargetContext& renderTargetContext);
|
explicit SkGlyphRunListDrawer(const GrRenderTargetContext& renderTargetContext);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using PerGlyph = std::function<void(const SkGlyph&, SkPoint)>;
|
||||||
using PerMask = std::function<void(const SkMask&, const SkGlyph&, SkPoint)>;
|
using PerMask = std::function<void(const SkMask&, const SkGlyph&, SkPoint)>;
|
||||||
using PerMaskCreator = std::function<PerMask(const SkPaint&, SkArenaAlloc* alloc)>;
|
using PerMaskCreator = std::function<PerMask(const SkPaint&, SkArenaAlloc* alloc)>;
|
||||||
using PerPath = std::function<void(const SkPath*, const SkGlyph&, SkPoint)>;
|
using PerPath = std::function<void(const SkPath*, const SkGlyph&, SkPoint)>;
|
||||||
@ -131,17 +132,31 @@ public:
|
|||||||
void drawUsingPaths(
|
void drawUsingPaths(
|
||||||
const SkGlyphRun& glyphRun, SkPoint origin, SkGlyphCache* cache, PerPath perPath) const;
|
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:
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
template <typename EachGlyph>
|
||||||
|
void forEachMappedDrawableGlyph(
|
||||||
|
const SkGlyphRun& glyphRun, SkPoint origin, const SkMatrix& deviceMatrix,
|
||||||
|
SkGlyphCache* cache, EachGlyph eachGlyph);
|
||||||
|
|
||||||
void drawGlyphRunAsSubpixelMask(
|
void drawGlyphRunAsSubpixelMask(
|
||||||
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
||||||
SkPoint origin, const SkMatrix& deviceMatrix,
|
SkPoint origin, const SkMatrix& deviceMatrix,
|
||||||
PerMask perMask);
|
PerMask perMask);
|
||||||
|
|
||||||
void drawGlyphRunAsFullpixelMask(
|
void drawGlyphRunAsFullpixelMask(
|
||||||
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
SkGlyphCache* cache, const SkGlyphRun& glyphRun,
|
||||||
SkPoint origin, const SkMatrix& deviceMatrix,
|
SkPoint origin, const SkMatrix& deviceMatrix,
|
||||||
PerMask perMask);
|
PerMask perMask);
|
||||||
|
|
||||||
// The props as on the actual device.
|
// The props as on the actual device.
|
||||||
const SkSurfaceProps fDeviceProps;
|
const SkSurfaceProps fDeviceProps;
|
||||||
// The props for when the bitmap device can't draw LCD text.
|
// 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(
|
auto cache = cacheBlob->setupCache(
|
||||||
runIndex, props, scalerContextFlags, runPaint, &viewMatrix);
|
runIndex, props, scalerContextFlags, runPaint, &viewMatrix);
|
||||||
|
|
||||||
auto drawOneGlyph =
|
auto perGlyph =
|
||||||
[cacheBlob, runIndex, glyphCache, &currStrike, runPaint, cache{cache.get()}]
|
[cacheBlob, runIndex, glyphCache, &currStrike, runPaint, cache{cache.get()}]
|
||||||
(const SkMask& mask, const SkGlyph& glyph, SkPoint position) {
|
(const SkGlyph& glyph, SkPoint mappedPt) {
|
||||||
SkScalar sx = SkScalarFloorToScalar(position.fX),
|
SkScalar sx = SkScalarFloorToScalar(mappedPt.fX),
|
||||||
sy = SkScalarFloorToScalar(position.fY);
|
sy = SkScalarFloorToScalar(mappedPt.fY);
|
||||||
|
AppendGlyph(cacheBlob, runIndex, glyphCache, &currStrike,
|
||||||
if (glyph_too_big_for_atlas(glyph)) {
|
glyph, GrGlyph::kCoverage_MaskStyle, sx, sy,
|
||||||
SkRect glyphRect =
|
runPaint.filteredPremulColor(), cache, SK_Scalar1, false);
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
runIndex += 1;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user