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:
Herb Derby 2018-08-01 21:13:23 -04:00 committed by Skia Commit-Bot
parent f83cacb770
commit 9a52a39468
4 changed files with 134 additions and 25 deletions

View File

@ -162,7 +162,7 @@ public:
void initWithGlyphID(SkPackedGlyphID glyph_id);
bool isEmpty() {
bool isEmpty() const {
return fWidth == 0 || fHeight == 0;
}

View File

@ -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 {

View File

@ -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.

View File

@ -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;
}