Cleanup of large text rendering, take 2.
* Switch all path glyphs to be rendered as part of the fBigGlyphs (now fPathGlyphs) system * Use one flush command for both cached and throwaway blobs * Store and render path glyphs per run rather than one list for the entire blob (fixes a layering bug) * Fix bug with scaled fallback glyphs, where fallback glyphs were trying to use more than one descriptor * Set paint flags correctly for paths Bug: skia:7562 Change-Id: I9455eda2867860a713fbdbbda79c74109e95f9f2 Reviewed-on: https://skia-review.googlesource.com/105020 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
6ba15ecb1c
commit
54d9c889fb
@ -26,7 +26,7 @@ static void drawTestCase(SkCanvas* canvas,
|
||||
static void draw_gm(SkCanvas* canvas,
|
||||
SkScalar strokeWidth,
|
||||
SkPaint::Style strokeStyle) {
|
||||
// There's a black pixel at 40, 40 for reference.
|
||||
// There's a black pixel at 40, 40 for reference.
|
||||
canvas->drawPoint(40, 40, SkPaint());
|
||||
|
||||
// Two reference images.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "SkGlyphCache.h"
|
||||
#include "SkMaskFilterBase.h"
|
||||
#include "SkTextBlobRunIterator.h"
|
||||
#include "SkTextToPathIter.h"
|
||||
#include "ops/GrAtlasTextOp.h"
|
||||
|
||||
sk_sp<GrAtlasTextBlob> GrAtlasTextBlob::Make(GrMemoryPool* pool, int glyphCount, int runCount) {
|
||||
@ -73,14 +74,22 @@ void GrAtlasTextBlob::appendGlyph(int runIndex,
|
||||
GrAtlasTextStrike* strike,
|
||||
GrGlyph* glyph,
|
||||
SkGlyphCache* cache, const SkGlyph& skGlyph,
|
||||
SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP) {
|
||||
SkScalar x, SkScalar y, SkScalar scale, bool preTransformed) {
|
||||
if (positions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the glyph is too large we fall back to paths
|
||||
if (glyph->fTooLargeForAtlas) {
|
||||
this->appendBigGlyph(glyph, cache, skGlyph, x, y, scale, treatAsBMP);
|
||||
if (nullptr == glyph->fPath) {
|
||||
const SkPath* glyphPath = cache->findPath(skGlyph);
|
||||
if (!glyphPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
glyph->fPath = new SkPath(*glyphPath);
|
||||
}
|
||||
this->appendPathGlyph(runIndex, *glyph->fPath, x, y, scale, preTransformed);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -140,17 +149,10 @@ void GrAtlasTextBlob::appendGlyph(int runIndex,
|
||||
subRun->glyphAppended();
|
||||
}
|
||||
|
||||
void GrAtlasTextBlob::appendBigGlyph(GrGlyph* glyph, SkGlyphCache* cache, const SkGlyph& skGlyph,
|
||||
SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP) {
|
||||
if (nullptr == glyph->fPath) {
|
||||
const SkPath* glyphPath = cache->findPath(skGlyph);
|
||||
if (!glyphPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
glyph->fPath = new SkPath(*glyphPath);
|
||||
}
|
||||
fBigGlyphs.push_back(GrAtlasTextBlob::BigGlyph(*glyph->fPath, x, y, scale, treatAsBMP));
|
||||
void GrAtlasTextBlob::appendPathGlyph(int runIndex, const SkPath& path, SkScalar x, SkScalar y,
|
||||
SkScalar scale, bool preTransformed) {
|
||||
Run& run = fRuns[runIndex];
|
||||
run.fPathGlyphs.push_back(GrAtlasTextBlob::Run::PathGlyph(path, x, y, scale, preTransformed));
|
||||
}
|
||||
|
||||
bool GrAtlasTextBlob::mustRegenerate(const GrTextUtils::Paint& paint,
|
||||
@ -273,62 +275,6 @@ inline std::unique_ptr<GrAtlasTextOp> GrAtlasTextBlob::makeOp(
|
||||
return op;
|
||||
}
|
||||
|
||||
inline void GrAtlasTextBlob::flushRun(GrTextUtils::Target* target, const GrClip& clip, int run,
|
||||
const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
|
||||
const GrTextUtils::Paint& paint, const SkSurfaceProps& props,
|
||||
const GrDistanceFieldAdjustTable* distanceAdjustTable,
|
||||
GrAtlasGlyphCache* cache) {
|
||||
// GrAtlasTextBlob::makeOp only takes uint16_t values for run and subRun indices.
|
||||
// Encountering something larger than this is highly unlikely, so we'll just not draw it.
|
||||
if (run >= (1 << 16)) {
|
||||
return;
|
||||
}
|
||||
int lastRun = SkTMin(fRuns[run].fSubRunInfo.count(), 1 << 16) - 1;
|
||||
for (int subRun = 0; subRun <= lastRun; subRun++) {
|
||||
const Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun];
|
||||
int glyphCount = info.glyphCount();
|
||||
if (0 == glyphCount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool skipClip = false;
|
||||
bool submitOp = true;
|
||||
SkIRect clipRect = SkIRect::MakeEmpty();
|
||||
SkRect rtBounds = SkRect::MakeWH(target->width(), target->height());
|
||||
SkRRect clipRRect;
|
||||
GrAA aa;
|
||||
// We can clip geometrically if we're not using SDFs,
|
||||
// and we have an axis-aligned rectangular non-AA clip
|
||||
if (!info.drawAsDistanceFields() && clip.isRRect(rtBounds, &clipRRect, &aa) &&
|
||||
clipRRect.isRect() && GrAA::kNo == aa) {
|
||||
skipClip = true;
|
||||
// We only need to do clipping work if the subrun isn't contained by the clip
|
||||
SkRect subRunBounds;
|
||||
this->computeSubRunBounds(&subRunBounds, run, subRun, viewMatrix, x, y);
|
||||
if (!clipRRect.getBounds().contains(subRunBounds)) {
|
||||
// If the subrun is completely outside, don't add an op for it
|
||||
if (!clipRRect.getBounds().intersects(subRunBounds)) {
|
||||
submitOp = false;
|
||||
} else {
|
||||
clipRRect.getBounds().round(&clipRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (submitOp) {
|
||||
auto op = this->makeOp(info, glyphCount, run, subRun, viewMatrix, x, y, clipRect,
|
||||
std::move(paint), props, distanceAdjustTable, cache, target);
|
||||
if (op) {
|
||||
if (skipClip) {
|
||||
target->addDrawOp(GrNoClip(), std::move(op));
|
||||
} else {
|
||||
target->addDrawOp(clip, std::move(op));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void calculate_translation(bool applyVM,
|
||||
const SkMatrix& newViewMatrix, SkScalar newX, SkScalar newY,
|
||||
const SkMatrix& currentViewMatrix, SkScalar currentX,
|
||||
@ -349,94 +295,95 @@ static void calculate_translation(bool applyVM,
|
||||
}
|
||||
}
|
||||
|
||||
void GrAtlasTextBlob::flushBigGlyphs(GrTextUtils::Target* target,
|
||||
const GrClip& clip, const SkPaint& paint,
|
||||
const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
|
||||
const SkIRect& clipBounds) {
|
||||
SkScalar transX, transY;
|
||||
for (int i = 0; i < fBigGlyphs.count(); i++) {
|
||||
GrAtlasTextBlob::BigGlyph& bigGlyph = fBigGlyphs[i];
|
||||
calculate_translation(bigGlyph.fTreatAsBMP, viewMatrix, x, y,
|
||||
fInitialViewMatrix, fInitialX, fInitialY, &transX, &transY);
|
||||
SkMatrix ctm;
|
||||
ctm.setScale(bigGlyph.fScale, bigGlyph.fScale);
|
||||
ctm.postTranslate(bigGlyph.fX + transX, bigGlyph.fY + transY);
|
||||
if (!bigGlyph.fTreatAsBMP) {
|
||||
ctm.postConcat(viewMatrix);
|
||||
void GrAtlasTextBlob::flush(GrAtlasGlyphCache* atlasGlyphCache, GrTextUtils::Target* target,
|
||||
const SkSurfaceProps& props,
|
||||
const GrDistanceFieldAdjustTable* distanceAdjustTable,
|
||||
const GrTextUtils::Paint& paint, const GrClip& clip,
|
||||
const SkMatrix& viewMatrix, const SkIRect& clipBounds,
|
||||
SkScalar x, SkScalar y) {
|
||||
|
||||
// GrAtlasTextBlob::makeOp only takes uint16_t values for run and subRun indices.
|
||||
// Encountering something larger than this is highly unlikely, so we'll just not draw it.
|
||||
int lastRun = SkTMin(fRunCount, (1 << 16)) - 1;
|
||||
GrTextUtils::RunPaint runPaint(&paint, nullptr, props);
|
||||
for (int runIndex = 0; runIndex <= lastRun; runIndex++) {
|
||||
Run& run = fRuns[runIndex];
|
||||
|
||||
// first flush any path glyphs
|
||||
if (run.fPathGlyphs.count()) {
|
||||
SkScalar transX, transY;
|
||||
uint16_t paintFlags = run.fPaintFlags;
|
||||
if (!runPaint.modifyForRun(
|
||||
[paintFlags](SkPaint* p) {
|
||||
p->setFlags((p->getFlags() & ~Run::kPaintFlagsMask) | paintFlags);
|
||||
})) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < run.fPathGlyphs.count(); i++) {
|
||||
GrAtlasTextBlob::Run::PathGlyph& pathGlyph = run.fPathGlyphs[i];
|
||||
calculate_translation(pathGlyph.fPreTransformed, viewMatrix, x, y,
|
||||
fInitialViewMatrix, fInitialX, fInitialY, &transX, &transY);
|
||||
const SkMatrix& ctm = pathGlyph.fPreTransformed ? SkMatrix::I() : viewMatrix;
|
||||
SkMatrix pathMatrix;
|
||||
pathMatrix.setScale(pathGlyph.fScale, pathGlyph.fScale);
|
||||
pathMatrix.postTranslate(pathGlyph.fX + transX, pathGlyph.fY + transY);
|
||||
target->drawPath(clip, pathGlyph.fPath, runPaint, ctm, &pathMatrix, clipBounds);
|
||||
}
|
||||
}
|
||||
target->drawPath(clip, bigGlyph.fPath, paint, ctm, nullptr, clipBounds);
|
||||
}
|
||||
}
|
||||
|
||||
void GrAtlasTextBlob::flushBigRun(GrTextUtils::Target* target,
|
||||
const SkSurfaceProps& props, const SkTextBlobRunIterator& it,
|
||||
const GrClip& clip, const GrTextUtils::Paint& paint,
|
||||
SkDrawFilter* drawFilter, const SkMatrix& viewMatrix,
|
||||
const SkIRect& clipBounds, SkScalar x, SkScalar y) {
|
||||
size_t textLen = it.glyphCount() * sizeof(uint16_t);
|
||||
const SkPoint& offset = it.offset();
|
||||
|
||||
GrTextUtils::RunPaint runPaint(&paint, drawFilter, props);
|
||||
if (!runPaint.modifyForRun(it)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (it.positioning()) {
|
||||
case SkTextBlob::kDefault_Positioning:
|
||||
GrTextUtils::DrawBigText(target, clip, runPaint, viewMatrix,
|
||||
(const char*)it.glyphs(), textLen, x + offset.x(),
|
||||
y + offset.y(), clipBounds);
|
||||
break;
|
||||
case SkTextBlob::kHorizontal_Positioning:
|
||||
GrTextUtils::DrawBigPosText(target, props, clip, runPaint, viewMatrix,
|
||||
(const char*)it.glyphs(), textLen, it.pos(), 1,
|
||||
SkPoint::Make(x, y + offset.y()), clipBounds);
|
||||
break;
|
||||
case SkTextBlob::kFull_Positioning:
|
||||
GrTextUtils::DrawBigPosText(target, props, clip, runPaint, viewMatrix,
|
||||
(const char*)it.glyphs(), textLen, it.pos(), 2,
|
||||
SkPoint::Make(x, y), clipBounds);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GrAtlasTextBlob::flushCached(GrAtlasGlyphCache* atlasGlyphCache, GrTextUtils::Target* target,
|
||||
const SkTextBlob* blob, const SkSurfaceProps& props,
|
||||
const GrDistanceFieldAdjustTable* distanceAdjustTable,
|
||||
const GrTextUtils::Paint& paint, SkDrawFilter* drawFilter,
|
||||
const GrClip& clip, const SkMatrix& viewMatrix,
|
||||
const SkIRect& clipBounds, SkScalar x, SkScalar y) {
|
||||
// We loop through the runs of the blob, flushing each. If any run is too large, then we flush
|
||||
// it as paths
|
||||
SkTextBlobRunIterator it(blob);
|
||||
for (int run = 0; !it.done(); it.next(), run++) {
|
||||
if (fRuns[run].fTooBigForAtlas) {
|
||||
this->flushBigRun(target, props, it, clip, paint, drawFilter, viewMatrix,
|
||||
clipBounds, x, y);
|
||||
// then flush each subrun, if any
|
||||
if (!run.fInitialized) {
|
||||
continue;
|
||||
}
|
||||
this->flushRun(target, clip, run, viewMatrix, x, y, paint, props, distanceAdjustTable,
|
||||
atlasGlyphCache);
|
||||
int lastSubRun = SkTMin(run.fSubRunInfo.count(), 1 << 16) - 1;
|
||||
for (int subRun = 0; subRun <= lastSubRun; subRun++) {
|
||||
const Run::SubRunInfo& info = run.fSubRunInfo[subRun];
|
||||
int glyphCount = info.glyphCount();
|
||||
if (0 == glyphCount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool skipClip = false;
|
||||
bool submitOp = true;
|
||||
SkIRect clipRect = SkIRect::MakeEmpty();
|
||||
SkRect rtBounds = SkRect::MakeWH(target->width(), target->height());
|
||||
SkRRect clipRRect;
|
||||
GrAA aa;
|
||||
// We can clip geometrically if we're not using SDFs,
|
||||
// and we have an axis-aligned rectangular non-AA clip
|
||||
if (!info.drawAsDistanceFields() && clip.isRRect(rtBounds, &clipRRect, &aa) &&
|
||||
clipRRect.isRect() && GrAA::kNo == aa) {
|
||||
skipClip = true;
|
||||
// We only need to do clipping work if the subrun isn't contained by the clip
|
||||
SkRect subRunBounds;
|
||||
this->computeSubRunBounds(&subRunBounds, runIndex, subRun, viewMatrix, x, y);
|
||||
if (!clipRRect.getBounds().contains(subRunBounds)) {
|
||||
// If the subrun is completely outside, don't add an op for it
|
||||
if (!clipRRect.getBounds().intersects(subRunBounds)) {
|
||||
submitOp = false;
|
||||
}
|
||||
else {
|
||||
clipRRect.getBounds().round(&clipRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (submitOp) {
|
||||
auto op = this->makeOp(info, glyphCount, runIndex, subRun, viewMatrix, x, y,
|
||||
clipRect, std::move(paint), props, distanceAdjustTable,
|
||||
atlasGlyphCache, target);
|
||||
if (op) {
|
||||
if (skipClip) {
|
||||
target->addDrawOp(GrNoClip(), std::move(op));
|
||||
}
|
||||
else {
|
||||
target->addDrawOp(clip, std::move(op));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Now flush big glyphs
|
||||
this->flushBigGlyphs(target, clip, paint, viewMatrix, x, y, clipBounds);
|
||||
}
|
||||
|
||||
void GrAtlasTextBlob::flushThrowaway(GrAtlasGlyphCache* atlasGlyphCache,
|
||||
GrTextUtils::Target* target,
|
||||
const SkSurfaceProps& props,
|
||||
const GrDistanceFieldAdjustTable* distanceAdjustTable,
|
||||
const GrTextUtils::Paint& paint, const GrClip& clip,
|
||||
const SkMatrix& viewMatrix, const SkIRect& clipBounds,
|
||||
SkScalar x, SkScalar y) {
|
||||
for (int run = 0; run < fRunCount; run++) {
|
||||
this->flushRun(target, clip, run, viewMatrix, x, y, paint, props, distanceAdjustTable,
|
||||
atlasGlyphCache);
|
||||
}
|
||||
|
||||
// Now flush big glyphs
|
||||
this->flushBigGlyphs(target, clip, paint, viewMatrix, x, y, clipBounds);
|
||||
}
|
||||
|
||||
std::unique_ptr<GrDrawOp> GrAtlasTextBlob::test_makeOp(
|
||||
@ -462,15 +409,6 @@ void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlo
|
||||
SkASSERT_RELEASE(l.fStrokeInfo.fMiterLimit == r.fStrokeInfo.fMiterLimit);
|
||||
SkASSERT_RELEASE(l.fStrokeInfo.fJoin == r.fStrokeInfo.fJoin);
|
||||
|
||||
SkASSERT_RELEASE(l.fBigGlyphs.count() == r.fBigGlyphs.count());
|
||||
for (int i = 0; i < l.fBigGlyphs.count(); i++) {
|
||||
const BigGlyph& lBigGlyph = l.fBigGlyphs[i];
|
||||
const BigGlyph& rBigGlyph = r.fBigGlyphs[i];
|
||||
|
||||
SkASSERT_RELEASE(lBigGlyph.fPath == rBigGlyph.fPath);
|
||||
// We can't assert that these have the same translations
|
||||
}
|
||||
|
||||
SkASSERT_RELEASE(l.fKey == r.fKey);
|
||||
//SkASSERT_RELEASE(l.fPaintColor == r.fPaintColor); // Colors might not actually be identical
|
||||
SkASSERT_RELEASE(l.fMaxMinScale == r.fMaxMinScale);
|
||||
@ -506,7 +444,6 @@ void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlo
|
||||
// color can be changed
|
||||
//SkASSERT(lRun.fColor == rRun.fColor);
|
||||
SkASSERT_RELEASE(lRun.fInitialized == rRun.fInitialized);
|
||||
SkASSERT_RELEASE(lRun.fTooBigForAtlas == rRun.fTooBigForAtlas);
|
||||
|
||||
SkASSERT_RELEASE(lRun.fSubRunInfo.count() == rRun.fSubRunInfo.count());
|
||||
for(int j = 0; j < lRun.fSubRunInfo.count(); j++) {
|
||||
@ -533,6 +470,15 @@ void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlo
|
||||
SkASSERT_RELEASE(lSubRun.drawAsDistanceFields() == rSubRun.drawAsDistanceFields());
|
||||
SkASSERT_RELEASE(lSubRun.hasUseLCDText() == rSubRun.hasUseLCDText());
|
||||
}
|
||||
|
||||
SkASSERT_RELEASE(lRun.fPathGlyphs.count() == rRun.fPathGlyphs.count());
|
||||
for (int i = 0; i < lRun.fPathGlyphs.count(); i++) {
|
||||
const Run::PathGlyph& lPathGlyph = lRun.fPathGlyphs[i];
|
||||
const Run::PathGlyph& rPathGlyph = rRun.fPathGlyphs[i];
|
||||
|
||||
SkASSERT_RELEASE(lPathGlyph.fPath == rPathGlyph.fPath);
|
||||
// We can't assert that these have the same translations
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,8 +142,8 @@ public:
|
||||
subRun.setHasWCoord(hasWCoord);
|
||||
}
|
||||
|
||||
void setRunTooBigForAtlas(int runIndex) {
|
||||
fRuns[runIndex].fTooBigForAtlas = true;
|
||||
void setRunPaintFlags(int runIndex, uint16_t paintFlags) {
|
||||
fRuns[runIndex].fPaintFlags = paintFlags & Run::kPaintFlagsMask;
|
||||
}
|
||||
|
||||
void setMinAndMaxScale(SkScalar scaledMax, SkScalar scaledMin) {
|
||||
@ -175,7 +175,11 @@ public:
|
||||
GrAtlasTextStrike* strike,
|
||||
GrGlyph* glyph,
|
||||
SkGlyphCache*, const SkGlyph& skGlyph,
|
||||
SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP);
|
||||
SkScalar x, SkScalar y, SkScalar scale, bool preTransformed);
|
||||
|
||||
// Appends a glyph to the blob as a path only.
|
||||
void appendPathGlyph(int runIndex, const SkPath& path,
|
||||
SkScalar x, SkScalar y, SkScalar scale, bool preTransformed);
|
||||
|
||||
static size_t GetVertexStride(GrMaskFormat maskFormat, bool isDistanceFieldWithWCoord) {
|
||||
switch (maskFormat) {
|
||||
@ -193,19 +197,11 @@ public:
|
||||
bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilterBase::BlurRec& blurRec,
|
||||
const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
|
||||
|
||||
// flush a GrAtlasTextBlob associated with a SkTextBlob
|
||||
void flushCached(GrAtlasGlyphCache*, GrTextUtils::Target*, const SkTextBlob* blob,
|
||||
const SkSurfaceProps& props,
|
||||
const GrDistanceFieldAdjustTable* distanceAdjustTable,
|
||||
const GrTextUtils::Paint&, SkDrawFilter* drawFilter, const GrClip& clip,
|
||||
const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y);
|
||||
|
||||
// flush a throwaway GrAtlasTextBlob *not* associated with an SkTextBlob
|
||||
void flushThrowaway(GrAtlasGlyphCache*, GrTextUtils::Target*, const SkSurfaceProps& props,
|
||||
const GrDistanceFieldAdjustTable* distanceAdjustTable,
|
||||
const GrTextUtils::Paint& paint, const GrClip& clip,
|
||||
const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x,
|
||||
SkScalar y);
|
||||
void flush(GrAtlasGlyphCache*, GrTextUtils::Target*, const SkSurfaceProps& props,
|
||||
const GrDistanceFieldAdjustTable* distanceAdjustTable,
|
||||
const GrTextUtils::Paint& paint, const GrClip& clip,
|
||||
const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x,
|
||||
SkScalar y);
|
||||
|
||||
void computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex,
|
||||
const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
|
||||
@ -285,24 +281,6 @@ private:
|
||||
, fMinMaxScale(SK_ScalarMax)
|
||||
, fTextType(0) {}
|
||||
|
||||
void appendBigGlyph(GrGlyph* glyph, SkGlyphCache* cache, const SkGlyph& skGlyph,
|
||||
SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP);
|
||||
|
||||
inline void flushRun(GrTextUtils::Target*, const GrClip&, int run, const SkMatrix& viewMatrix,
|
||||
SkScalar x, SkScalar y, const GrTextUtils::Paint& paint,
|
||||
const SkSurfaceProps& props,
|
||||
const GrDistanceFieldAdjustTable* distanceAdjustTable,
|
||||
GrAtlasGlyphCache* cache);
|
||||
|
||||
void flushBigGlyphs(GrTextUtils::Target*, const GrClip& clip,
|
||||
const SkPaint& paint, const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
|
||||
const SkIRect& clipBounds);
|
||||
|
||||
void flushBigRun(GrTextUtils::Target*, const SkSurfaceProps& props,
|
||||
const SkTextBlobRunIterator& it, const GrClip& clip,
|
||||
const GrTextUtils::Paint& paint, SkDrawFilter* drawFilter,
|
||||
const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x,
|
||||
SkScalar y);
|
||||
|
||||
// This function will only be called when we are generating a blob from scratch. We record the
|
||||
// initial view matrix and initial offsets(x,y), because we record vertex bounds relative to
|
||||
@ -347,9 +325,8 @@ private:
|
||||
* would greatly increase the memory of these cached items.
|
||||
*/
|
||||
struct Run {
|
||||
Run()
|
||||
: fInitialized(false)
|
||||
, fTooBigForAtlas(false) {
|
||||
Run() : fPaintFlags(0)
|
||||
, fInitialized(false) {
|
||||
// To ensure we always have one subrun, we push back a fresh run here
|
||||
fSubRunInfo.push_back();
|
||||
}
|
||||
@ -495,8 +472,31 @@ private:
|
||||
// will have different descriptors. If fOverrideDescriptor is non-nullptr, then it
|
||||
// will be used in place of the run's descriptor to regen texture coords
|
||||
std::unique_ptr<SkAutoDescriptor> fOverrideDescriptor; // df properties
|
||||
bool fInitialized;
|
||||
bool fTooBigForAtlas;
|
||||
|
||||
// Any glyphs that can't be rendered with the base or override descriptor
|
||||
// are rendered as paths
|
||||
struct PathGlyph {
|
||||
PathGlyph(const SkPath& path, SkScalar x, SkScalar y, SkScalar scale, bool preXformed)
|
||||
: fPath(path)
|
||||
, fX(x)
|
||||
, fY(y)
|
||||
, fScale(scale)
|
||||
, fPreTransformed(preXformed) {}
|
||||
SkPath fPath;
|
||||
SkScalar fX;
|
||||
SkScalar fY;
|
||||
SkScalar fScale;
|
||||
bool fPreTransformed;
|
||||
};
|
||||
|
||||
SkTArray<PathGlyph> fPathGlyphs;
|
||||
|
||||
struct {
|
||||
unsigned fPaintFlags : 16; // needed mainly for rendering paths
|
||||
bool fInitialized : 1;
|
||||
};
|
||||
// the only flags we need to set
|
||||
static constexpr auto kPaintFlagsMask = SkPaint::kAntiAlias_Flag;
|
||||
}; // Run
|
||||
|
||||
inline std::unique_ptr<GrAtlasTextOp> makeOp(
|
||||
@ -506,20 +506,6 @@ private:
|
||||
const GrDistanceFieldAdjustTable* distanceAdjustTable, GrAtlasGlyphCache* cache,
|
||||
GrTextUtils::Target*);
|
||||
|
||||
struct BigGlyph {
|
||||
BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy, SkScalar scale, bool treatAsBMP)
|
||||
: fPath(path)
|
||||
, fScale(scale)
|
||||
, fX(vx)
|
||||
, fY(vy)
|
||||
, fTreatAsBMP(treatAsBMP) {}
|
||||
SkPath fPath;
|
||||
SkScalar fScale;
|
||||
SkScalar fX;
|
||||
SkScalar fY;
|
||||
bool fTreatAsBMP;
|
||||
};
|
||||
|
||||
struct StrokeInfo {
|
||||
SkScalar fFrameWidth;
|
||||
SkScalar fMiterLimit;
|
||||
@ -538,7 +524,6 @@ private:
|
||||
GrMemoryPool* fPool;
|
||||
SkMaskFilterBase::BlurRec fBlurRec;
|
||||
StrokeInfo fStrokeInfo;
|
||||
SkTArray<BigGlyph> fBigGlyphs;
|
||||
Key fKey;
|
||||
SkMatrix fInitialViewMatrix;
|
||||
SkMatrix fInitialViewMatrixInverse;
|
||||
|
@ -11,11 +11,15 @@
|
||||
#include "SkDistanceFieldGen.h"
|
||||
#include "SkDraw.h"
|
||||
#include "SkDrawFilter.h"
|
||||
#include "SkDrawProcs.h"
|
||||
#include "SkFindAndPlaceGlyph.h"
|
||||
#include "SkGr.h"
|
||||
#include "SkGraphics.h"
|
||||
#include "SkMakeUnique.h"
|
||||
#include "SkMaskFilterBase.h"
|
||||
#include "SkTextMapStateProc.h"
|
||||
#include "SkTextToPathIter.h"
|
||||
|
||||
#include "ops/GrMeshDrawOp.h"
|
||||
|
||||
// DF sizes and thresholds for usage of the small and medium sizes. For example, above
|
||||
@ -49,15 +53,6 @@ std::unique_ptr<GrAtlasTextContext> GrAtlasTextContext::Make(const Options& opti
|
||||
return std::unique_ptr<GrAtlasTextContext>(new GrAtlasTextContext(options));
|
||||
}
|
||||
|
||||
bool GrAtlasTextContext::canDraw(const GrAtlasGlyphCache* fontCache,
|
||||
const SkPaint& skPaint,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkSurfaceProps& props,
|
||||
const GrShaderCaps& shaderCaps) {
|
||||
return this->canDrawAsDistanceFields(skPaint, viewMatrix, props, shaderCaps) ||
|
||||
!SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix, fontCache->getGlyphSizeLimit());
|
||||
}
|
||||
|
||||
SkColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd) {
|
||||
SkColor canonicalColor = paint.computeLuminanceColor();
|
||||
if (lcd) {
|
||||
@ -186,8 +181,8 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t
|
||||
viewMatrix, props, blob, x, y, drawFilter);
|
||||
}
|
||||
|
||||
cacheBlob->flushCached(atlasGlyphCache, target, blob, props, fDistanceAdjustTable.get(), paint,
|
||||
drawFilter, clip, viewMatrix, clipBounds, x, y);
|
||||
cacheBlob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint,
|
||||
clip, viewMatrix, clipBounds, x, y);
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob,
|
||||
@ -209,9 +204,11 @@ void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob,
|
||||
size_t textLen = glyphCount * sizeof(uint16_t);
|
||||
const SkPoint& offset = it.offset();
|
||||
cacheBlob->push_back_run(run);
|
||||
if (!runPaint.modifyForRun(it)) {
|
||||
if (!runPaint.modifyForRun([it](SkPaint* p) { it.applyFontToPaint(p); })) {
|
||||
continue;
|
||||
}
|
||||
cacheBlob->setRunPaintFlags(run, runPaint.skPaint().getFlags());
|
||||
|
||||
if (this->canDrawAsDistanceFields(runPaint, viewMatrix, props, shaderCaps)) {
|
||||
switch (it.positioning()) {
|
||||
case SkTextBlob::kDefault_Positioning: {
|
||||
@ -235,8 +232,6 @@ void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob,
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) {
|
||||
cacheBlob->setRunTooBigForAtlas(run);
|
||||
} else {
|
||||
switch (it.positioning()) {
|
||||
case SkTextBlob::kDefault_Positioning:
|
||||
@ -275,6 +270,7 @@ GrAtlasTextContext::makeDrawTextBlob(GrTextBlobCache* blobCache,
|
||||
}
|
||||
sk_sp<GrAtlasTextBlob> blob = blobCache->makeBlob(glyphCount, 1);
|
||||
blob->initThrowawayBlob(viewMatrix, x, y);
|
||||
blob->setRunPaintFlags(0, paint.skPaint().getFlags());
|
||||
|
||||
if (this->canDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) {
|
||||
this->drawDFText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix,
|
||||
@ -304,6 +300,7 @@ GrAtlasTextContext::makeDrawPosTextBlob(GrTextBlobCache* blobCache,
|
||||
|
||||
sk_sp<GrAtlasTextBlob> blob = blobCache->makeBlob(glyphCount, 1);
|
||||
blob->initThrowawayBlob(viewMatrix, offset.x(), offset.y());
|
||||
blob->setRunPaintFlags(0, paint.skPaint().getFlags());
|
||||
|
||||
if (this->canDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) {
|
||||
this->drawDFPosText(blob.get(), 0, fontCache, props, paint, scalerContextFlags, viewMatrix,
|
||||
@ -328,23 +325,15 @@ void GrAtlasTextContext::drawText(GrContext* context, GrTextUtils::Target* targe
|
||||
auto textBlobCache = context->contextPriv().getTextBlobCache();
|
||||
|
||||
GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo());
|
||||
if (this->canDraw(atlasGlyphCache, skPaint, viewMatrix, props,
|
||||
*context->caps()->shaderCaps())) {
|
||||
sk_sp<GrAtlasTextBlob> blob(
|
||||
this->makeDrawTextBlob(textBlobCache, atlasGlyphCache,
|
||||
*context->caps()->shaderCaps(), paint,
|
||||
ComputeScalerContextFlags(target->colorSpaceInfo()),
|
||||
viewMatrix, props, text, byteLength, x, y));
|
||||
if (blob) {
|
||||
blob->flushThrowaway(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint,
|
||||
clip, viewMatrix, regionClipBounds, x, y);
|
||||
}
|
||||
return;
|
||||
sk_sp<GrAtlasTextBlob> blob(
|
||||
this->makeDrawTextBlob(textBlobCache, atlasGlyphCache,
|
||||
*context->caps()->shaderCaps(), paint,
|
||||
ComputeScalerContextFlags(target->colorSpaceInfo()),
|
||||
viewMatrix, props, text, byteLength, x, y));
|
||||
if (blob) {
|
||||
blob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint,
|
||||
clip, viewMatrix, regionClipBounds, x, y);
|
||||
}
|
||||
|
||||
// fall back to drawing as a path or scaled glyph
|
||||
GrTextUtils::DrawBigText(target, clip, paint, viewMatrix, text, byteLength, x, y,
|
||||
regionClipBounds);
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::drawPosText(GrContext* context, GrTextUtils::Target* target,
|
||||
@ -361,23 +350,15 @@ void GrAtlasTextContext::drawPosText(GrContext* context, GrTextUtils::Target* ta
|
||||
auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache();
|
||||
auto textBlobCache = context->contextPriv().getTextBlobCache();
|
||||
|
||||
if (this->canDraw(atlasGlyphCache, skPaint, viewMatrix, props,
|
||||
*context->caps()->shaderCaps())) {
|
||||
sk_sp<GrAtlasTextBlob> blob(this->makeDrawPosTextBlob(
|
||||
textBlobCache, atlasGlyphCache,
|
||||
*context->caps()->shaderCaps(), paint,
|
||||
ComputeScalerContextFlags(target->colorSpaceInfo()), viewMatrix, props, text,
|
||||
byteLength, pos, scalarsPerPosition, offset));
|
||||
if (blob) {
|
||||
blob->flushThrowaway(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint,
|
||||
clip, viewMatrix, regionClipBounds, offset.fX, offset.fY);
|
||||
}
|
||||
return;
|
||||
sk_sp<GrAtlasTextBlob> blob(this->makeDrawPosTextBlob(
|
||||
textBlobCache, atlasGlyphCache,
|
||||
*context->caps()->shaderCaps(), paint,
|
||||
ComputeScalerContextFlags(target->colorSpaceInfo()), viewMatrix, props, text,
|
||||
byteLength, pos, scalarsPerPosition, offset));
|
||||
if (blob) {
|
||||
blob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint,
|
||||
clip, viewMatrix, regionClipBounds, offset.fX, offset.fY);
|
||||
}
|
||||
|
||||
// fall back to drawing as a path or scaled glyph
|
||||
GrTextUtils::DrawBigPosText(target, props, clip, paint, viewMatrix, text,
|
||||
byteLength, pos, scalarsPerPosition, offset, regionClipBounds);
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex,
|
||||
@ -396,8 +377,11 @@ void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex,
|
||||
// Ensure the blob is set for bitmaptext
|
||||
blob->setHasBitmap();
|
||||
|
||||
if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) {
|
||||
DrawBmpTextAsPaths(blob, runIndex, paint, text, byteLength, x, y);
|
||||
return;
|
||||
}
|
||||
GrAtlasTextStrike* currStrike = nullptr;
|
||||
|
||||
SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix);
|
||||
SkFindAndPlaceGlyph::ProcessText(paint.skPaint().getTextEncoding(), text, byteLength, {x, y},
|
||||
viewMatrix, paint.skPaint().getTextAlign(), cache,
|
||||
@ -432,10 +416,15 @@ void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex,
|
||||
// Ensure the blob is set for bitmaptext
|
||||
blob->setHasBitmap();
|
||||
|
||||
if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) {
|
||||
DrawBmpPosTextAsPaths(blob, runIndex, props, paint, text, byteLength,
|
||||
pos, scalarsPerPosition, offset, textRatio);
|
||||
return;
|
||||
}
|
||||
|
||||
GrAtlasTextStrike* currStrike = nullptr;
|
||||
|
||||
SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix);
|
||||
|
||||
SkFindAndPlaceGlyph::ProcessPosText(
|
||||
paint.skPaint().getTextEncoding(), text, byteLength, offset, viewMatrix, pos,
|
||||
scalarsPerPosition, paint.skPaint().getTextAlign(), cache,
|
||||
@ -450,6 +439,77 @@ void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex,
|
||||
SkGlyphCache::AttachCache(cache);
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::DrawBmpTextAsPaths(GrAtlasTextBlob* blob, int runIndex,
|
||||
const GrTextUtils::Paint& origPaint, const char text[],
|
||||
size_t byteLength, SkScalar x, SkScalar y) {
|
||||
// nothing to draw
|
||||
if (text == nullptr || byteLength == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
|
||||
SkPaint paint(origPaint);
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
paint.setPathEffect(nullptr);
|
||||
|
||||
SkTextToPathIter iter(text, byteLength, paint, true);
|
||||
const SkPath* iterPath;
|
||||
SkScalar xpos = 0;
|
||||
while (iter.next(&iterPath, &xpos)) {
|
||||
if (iterPath) {
|
||||
blob->appendPathGlyph(runIndex, *iterPath, xpos + x, y, iter.getPathScale(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::DrawBmpPosTextAsPaths(GrAtlasTextBlob* blob, int runIndex,
|
||||
const SkSurfaceProps& props,
|
||||
const GrTextUtils::Paint& origPaint,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
const SkPoint& offset, SkScalar textRatio) {
|
||||
SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
|
||||
|
||||
// nothing to draw
|
||||
if (text == nullptr || byteLength == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// setup our std paint, in hopes of getting hits in the cache
|
||||
SkPaint paint(origPaint);
|
||||
SkScalar matrixScale = paint.setupForAsPaths();
|
||||
matrixScale *= textRatio;
|
||||
|
||||
// Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
paint.setPathEffect(nullptr);
|
||||
|
||||
SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
|
||||
paint.isDevKernText(),
|
||||
true);
|
||||
SkAutoGlyphCache autoCache(paint, &props, nullptr);
|
||||
SkGlyphCache* cache = autoCache.getCache();
|
||||
|
||||
const char* stop = text + byteLength;
|
||||
SkTextAlignProc alignProc(paint.getTextAlign());
|
||||
SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
|
||||
|
||||
while (text < stop) {
|
||||
const SkGlyph& glyph = glyphCacheProc(cache, &text);
|
||||
if (glyph.fWidth) {
|
||||
const SkPath* path = cache->findPath(glyph);
|
||||
if (path) {
|
||||
SkPoint tmsLoc;
|
||||
tmsProc(pos, &tmsLoc);
|
||||
SkPoint loc;
|
||||
alignProc(tmsLoc, glyph, &loc);
|
||||
blob->appendPathGlyph(runIndex, *path, loc.fX, loc.fY, matrixScale, false);
|
||||
}
|
||||
}
|
||||
pos += scalarsPerPosition;
|
||||
}
|
||||
}
|
||||
|
||||
void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex,
|
||||
GrAtlasGlyphCache* fontCache, GrAtlasTextStrike** strike,
|
||||
const SkGlyph& skGlyph, SkScalar sx, SkScalar sy,
|
||||
@ -467,6 +527,7 @@ void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex,
|
||||
if (!glyph) {
|
||||
return;
|
||||
}
|
||||
glyph->fTooLargeForAtlas = glyph->fTooLargeForAtlas;
|
||||
|
||||
SkASSERT(skGlyph.fWidth == glyph->width());
|
||||
SkASSERT(skGlyph.fHeight == glyph->height());
|
||||
@ -675,11 +736,10 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex,
|
||||
SkTDArray<char> fallbackTxt;
|
||||
SkTDArray<SkScalar> fallbackPos;
|
||||
|
||||
SkTDArray<char> bigFallbackTxt;
|
||||
SkTDArray<SkScalar> bigFallbackPos;
|
||||
bool useScaledFallback = false;
|
||||
SkScalar textSize = paint.skPaint().getTextSize();
|
||||
SkScalar maxTextSize = fontCache->getGlyphSizeLimit();
|
||||
SkScalar bigFallbackTextSize = maxTextSize;
|
||||
SkScalar scaledFallbackTextSize = maxTextSize;
|
||||
SkScalar maxScale = viewMatrix.getMaxScale();
|
||||
|
||||
bool hasWCoord = viewMatrix.hasPerspective() || fDistanceFieldVerticesAlwaysHaveW;
|
||||
@ -723,19 +783,30 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex,
|
||||
y - advanceY, paint.filteredPremulColor(), cache, textRatio);
|
||||
} else {
|
||||
// can't append color glyph to SDF batch, send to fallback
|
||||
SkScalar maxDim = SkTMax(glyph.fWidth, glyph.fHeight)*textRatio;
|
||||
SkScalar scaledGlyphSize = maxDim*maxScale;
|
||||
|
||||
if (!viewMatrix.hasPerspective() && scaledGlyphSize > maxTextSize) {
|
||||
bigFallbackTxt.append(SkToInt(text - lastText), lastText);
|
||||
*bigFallbackPos.append() = maxScale*pos[0];
|
||||
// all fallback glyphs need to use the same descriptor, so once
|
||||
// we have to scale one, we have to scale all of them
|
||||
SkScalar maxDim = SkTMax(glyph.fWidth, glyph.fHeight)*textRatio;
|
||||
if (!useScaledFallback) {
|
||||
SkScalar scaledGlyphSize = maxDim * maxScale;
|
||||
if (!viewMatrix.hasPerspective() && scaledGlyphSize > maxTextSize) {
|
||||
useScaledFallback = true;
|
||||
// rescale previous glyph positions to match text scale
|
||||
for (int i = 0; i < fallbackPos.count(); ++i) {
|
||||
fallbackPos[i] *= maxScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fallbackTxt.append(SkToInt(text - lastText), lastText);
|
||||
if (useScaledFallback) {
|
||||
*fallbackPos.append() = maxScale*pos[0];
|
||||
if (2 == scalarsPerPosition) {
|
||||
*bigFallbackPos.append() = maxScale*pos[1];
|
||||
*fallbackPos.append() = maxScale*pos[1];
|
||||
}
|
||||
SkScalar glyphTextSize = SkScalarFloorToScalar(maxTextSize*textSize/maxDim);
|
||||
bigFallbackTextSize = SkTMin(glyphTextSize, bigFallbackTextSize);
|
||||
scaledFallbackTextSize = SkTMin(glyphTextSize, scaledFallbackTextSize);
|
||||
} else {
|
||||
fallbackTxt.append(SkToInt(text - lastText), lastText);
|
||||
*fallbackPos.append() = pos[0];
|
||||
if (2 == scalarsPerPosition) {
|
||||
*fallbackPos.append() = pos[1];
|
||||
@ -747,33 +818,35 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex,
|
||||
}
|
||||
|
||||
SkGlyphCache::AttachCache(cache);
|
||||
|
||||
if (fallbackTxt.count()) {
|
||||
blob->initOverride(runIndex);
|
||||
GrAtlasTextContext::DrawBmpPosText(blob, runIndex, fontCache, props, paint,
|
||||
scalerContextFlags, viewMatrix, fallbackTxt.begin(),
|
||||
fallbackTxt.count(), fallbackPos.begin(),
|
||||
scalarsPerPosition, offset, SK_Scalar1);
|
||||
if (useScaledFallback) {
|
||||
// Set up paint and matrix to scale glyphs
|
||||
SkPaint scaledPaint(paint);
|
||||
scaledPaint.setTextSize(scaledFallbackTextSize);
|
||||
// remove maxScale from viewMatrix and move it into textRatio
|
||||
// this keeps the base glyph size consistent regardless of matrix scale
|
||||
SkMatrix modMatrix(viewMatrix);
|
||||
SkScalar invScale = SkScalarInvert(maxScale);
|
||||
modMatrix.preScale(invScale, invScale);
|
||||
SkScalar scaledFallbackTextRatio = textSize * maxScale / scaledFallbackTextSize;
|
||||
SkPoint modOffset(offset);
|
||||
modOffset *= maxScale;
|
||||
GrTextUtils::Paint textPaint(&scaledPaint, paint.dstColorSpaceInfo());
|
||||
GrAtlasTextContext::DrawBmpPosText(blob, runIndex, fontCache, props, textPaint,
|
||||
scalerContextFlags, modMatrix, fallbackTxt.begin(),
|
||||
fallbackTxt.count(), fallbackPos.begin(),
|
||||
scalarsPerPosition, modOffset,
|
||||
scaledFallbackTextRatio);
|
||||
} else {
|
||||
GrAtlasTextContext::DrawBmpPosText(blob, runIndex, fontCache, props, paint,
|
||||
scalerContextFlags, viewMatrix, fallbackTxt.begin(),
|
||||
fallbackTxt.count(), fallbackPos.begin(),
|
||||
scalarsPerPosition, offset, SK_Scalar1);
|
||||
}
|
||||
}
|
||||
|
||||
if (bigFallbackTxt.count()) {
|
||||
// Set up paint and matrix to scale glyphs
|
||||
blob->initOverride(runIndex);
|
||||
SkPaint largePaint(paint);
|
||||
largePaint.setTextSize(bigFallbackTextSize);
|
||||
// remove maxScale from viewMatrix and move it into textRatio
|
||||
// this keeps the base glyph size consistent regardless of matrix scale
|
||||
SkMatrix modMatrix(viewMatrix);
|
||||
SkScalar invScale = SkScalarInvert(maxScale);
|
||||
modMatrix.preScale(invScale, invScale);
|
||||
SkScalar bigFallbackTextRatio = textSize*maxScale/bigFallbackTextSize;
|
||||
SkPoint modOffset(offset);
|
||||
modOffset *= maxScale;
|
||||
GrTextUtils::Paint textPaint(&largePaint, paint.dstColorSpaceInfo());
|
||||
GrAtlasTextContext::DrawBmpPosText(blob, runIndex, fontCache, props, textPaint,
|
||||
scalerContextFlags, modMatrix, bigFallbackTxt.begin(),
|
||||
bigFallbackTxt.count(), bigFallbackPos.begin(),
|
||||
scalarsPerPosition, modOffset, bigFallbackTextRatio);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: merge with BmpAppendGlyph
|
||||
|
@ -44,9 +44,6 @@ public:
|
||||
|
||||
static std::unique_ptr<GrAtlasTextContext> Make(const Options& options);
|
||||
|
||||
bool canDraw(const GrAtlasGlyphCache* fontCache, const SkPaint&, const SkMatrix& viewMatrix,
|
||||
const SkSurfaceProps&, const GrShaderCaps&);
|
||||
|
||||
void drawText(GrContext*, GrTextUtils::Target*, const GrClip&, const SkPaint&,
|
||||
const SkMatrix& viewMatrix, const SkSurfaceProps&, const char text[],
|
||||
size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds);
|
||||
@ -110,6 +107,16 @@ private:
|
||||
int scalarsPerPosition, const SkPoint& offset,
|
||||
SkScalar textRatio);
|
||||
|
||||
static void DrawBmpTextAsPaths(GrAtlasTextBlob* blob, int runIndex,
|
||||
const GrTextUtils::Paint& paint, const char text[],
|
||||
size_t byteLength, SkScalar x, SkScalar y);
|
||||
|
||||
static void DrawBmpPosTextAsPaths(GrAtlasTextBlob*, int runIndex,
|
||||
const SkSurfaceProps& props, const GrTextUtils::Paint& paint,
|
||||
const char text[], size_t byteLength,
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
const SkPoint& offset, SkScalar textRatio);
|
||||
|
||||
// functions for appending distance field text
|
||||
bool canDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix& viewMatrix,
|
||||
const SkSurfaceProps& props, const GrShaderCaps& caps) const;
|
||||
|
@ -8,13 +8,10 @@
|
||||
#include "GrTextUtils.h"
|
||||
#include "GrContext.h"
|
||||
#include "SkDrawFilter.h"
|
||||
#include "SkDrawProcs.h"
|
||||
#include "SkGlyphCache.h"
|
||||
#include "SkGr.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkTextBlobRunIterator.h"
|
||||
#include "SkTextMapStateProc.h"
|
||||
#include "SkTextToPathIter.h"
|
||||
|
||||
void GrTextUtils::Paint::initFilteredColor() {
|
||||
// This mirrors the logic in skpaint_to_grpaint_impl for handling paint colors
|
||||
@ -35,7 +32,8 @@ void GrTextUtils::Paint::initFilteredColor() {
|
||||
}
|
||||
}
|
||||
|
||||
bool GrTextUtils::RunPaint::modifyForRun(const SkTextBlobRunIterator& run) {
|
||||
|
||||
bool GrTextUtils::RunPaint::modifyForRun(std::function<void(SkPaint*)> paintModFunc) {
|
||||
if (!fModifiedPaint.isValid()) {
|
||||
fModifiedPaint.init(fOriginalPaint->skPaint());
|
||||
fPaint = fModifiedPaint.get();
|
||||
@ -44,7 +42,7 @@ bool GrTextUtils::RunPaint::modifyForRun(const SkTextBlobRunIterator& run) {
|
||||
// changed the paint.
|
||||
*fModifiedPaint.get() = fOriginalPaint->skPaint();
|
||||
}
|
||||
run.applyFontToPaint(fModifiedPaint.get());
|
||||
paintModFunc(fModifiedPaint.get());
|
||||
|
||||
if (fFilter) {
|
||||
if (!fFilter->filter(fModifiedPaint.get(), SkDrawFilter::kText_Type)) {
|
||||
@ -77,82 +75,3 @@ bool GrTextUtils::ShouldDisableLCD(const SkPaint& paint) {
|
||||
return paint.getMaskFilter() || paint.getPathEffect() ||
|
||||
paint.isFakeBoldText() || paint.getStyle() != SkPaint::kFill_Style;
|
||||
}
|
||||
|
||||
void GrTextUtils::DrawBigText(GrTextUtils::Target* target,
|
||||
const GrClip& clip, const SkPaint& paint,
|
||||
const SkMatrix& viewMatrix, const char text[], size_t byteLength,
|
||||
SkScalar x, SkScalar y, const SkIRect& clipBounds) {
|
||||
if (!paint.countText(text, byteLength)) {
|
||||
return;
|
||||
}
|
||||
SkTextToPathIter iter(text, byteLength, paint, true);
|
||||
|
||||
SkMatrix matrix;
|
||||
matrix.setScale(iter.getPathScale(), iter.getPathScale());
|
||||
matrix.postTranslate(x, y);
|
||||
|
||||
const SkPath* iterPath;
|
||||
SkScalar xpos, prevXPos = 0;
|
||||
|
||||
while (iter.next(&iterPath, &xpos)) {
|
||||
matrix.postTranslate(xpos - prevXPos, 0);
|
||||
if (iterPath) {
|
||||
const SkPaint& pnt = iter.getPaint();
|
||||
target->drawPath(clip, *iterPath, pnt, viewMatrix, &matrix, clipBounds);
|
||||
}
|
||||
prevXPos = xpos;
|
||||
}
|
||||
}
|
||||
|
||||
void GrTextUtils::DrawBigPosText(GrTextUtils::Target* target,
|
||||
const SkSurfaceProps& props, const GrClip& clip,
|
||||
const SkPaint& origPaint, const SkMatrix& viewMatrix,
|
||||
const char text[], size_t byteLength, const SkScalar pos[],
|
||||
int scalarsPerPosition, const SkPoint& offset,
|
||||
const SkIRect& clipBounds) {
|
||||
if (!origPaint.countText(text, byteLength)) {
|
||||
return;
|
||||
}
|
||||
// setup our std paint, in hopes of getting hits in the cache
|
||||
SkPaint paint(origPaint);
|
||||
SkScalar matrixScale = paint.setupForAsPaths();
|
||||
|
||||
SkMatrix matrix;
|
||||
matrix.setScale(matrixScale, matrixScale);
|
||||
|
||||
// Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
paint.setPathEffect(nullptr);
|
||||
|
||||
SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
|
||||
paint.isDevKernText(),
|
||||
true);
|
||||
SkAutoGlyphCache autoCache(paint, &props, nullptr);
|
||||
SkGlyphCache* cache = autoCache.getCache();
|
||||
|
||||
const char* stop = text + byteLength;
|
||||
SkTextAlignProc alignProc(paint.getTextAlign());
|
||||
SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
|
||||
|
||||
// Now restore the original settings, so we "draw" with whatever style/stroking.
|
||||
paint.setStyle(origPaint.getStyle());
|
||||
paint.setPathEffect(origPaint.refPathEffect());
|
||||
|
||||
while (text < stop) {
|
||||
const SkGlyph& glyph = glyphCacheProc(cache, &text);
|
||||
if (glyph.fWidth) {
|
||||
const SkPath* path = cache->findPath(glyph);
|
||||
if (path) {
|
||||
SkPoint tmsLoc;
|
||||
tmsProc(pos, &tmsLoc);
|
||||
SkPoint loc;
|
||||
alignProc(tmsLoc, glyph, &loc);
|
||||
|
||||
matrix[SkMatrix::kMTransX] = loc.fX;
|
||||
matrix[SkMatrix::kMTransY] = loc.fY;
|
||||
target->drawPath(clip, *path, paint, viewMatrix, &matrix, clipBounds);
|
||||
}
|
||||
}
|
||||
pos += scalarsPerPosition;
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ public:
|
||||
fFilteredPremulColor = fOriginalPaint->filteredPremulColor();
|
||||
}
|
||||
|
||||
bool modifyForRun(const SkTextBlobRunIterator&);
|
||||
bool modifyForRun(std::function<void(SkPaint*)> paintModFunc);
|
||||
|
||||
private:
|
||||
SkTLazy<SkPaint> fModifiedPaint;
|
||||
@ -127,19 +127,6 @@ public:
|
||||
static uint32_t FilterTextFlags(const SkSurfaceProps& surfaceProps, const SkPaint& paint);
|
||||
|
||||
static bool ShouldDisableLCD(const SkPaint& paint);
|
||||
|
||||
// Functions for drawing large text either as paths or (for color emoji) as scaled glyphs
|
||||
static void DrawBigText(GrTextUtils::Target*, const GrClip& clip,
|
||||
const SkPaint& paint, const SkMatrix& viewMatrix, const char text[],
|
||||
size_t byteLength, SkScalar x, SkScalar y,
|
||||
const SkIRect& clipBounds);
|
||||
|
||||
static void DrawBigPosText(GrTextUtils::Target*,
|
||||
const SkSurfaceProps& props, const GrClip& clip,
|
||||
const SkPaint& paint, const SkMatrix& viewMatrix,
|
||||
const char text[], size_t byteLength, const SkScalar pos[],
|
||||
int scalarsPerPosition, const SkPoint& offset,
|
||||
const SkIRect& clipBounds);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user