aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/text/GrAtlasTextBlob.cpp253
-rw-r--r--src/gpu/text/GrAtlasTextBlob.h85
-rw-r--r--src/gpu/text/GrAtlasTextContext.cpp229
-rw-r--r--src/gpu/text/GrAtlasTextContext.h13
-rw-r--r--src/gpu/text/GrTextUtils.cpp82
-rw-r--r--src/gpu/text/GrTextUtils.h13
6 files changed, 394 insertions, 281 deletions
diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp
index 12ad89a62a..887addd25c 100644
--- a/src/gpu/text/GrAtlasTextBlob.cpp
+++ b/src/gpu/text/GrAtlasTextBlob.cpp
@@ -73,22 +73,14 @@ void GrAtlasTextBlob::appendGlyph(int runIndex,
GrAtlasTextStrike* strike,
GrGlyph* glyph,
SkGlyphCache* cache, const SkGlyph& skGlyph,
- SkScalar x, SkScalar y, SkScalar scale, bool preTransformed) {
+ SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP) {
if (positions.isEmpty()) {
return;
}
// If the glyph is too large we fall back to paths
if (glyph->fTooLargeForAtlas) {
- 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);
+ this->appendBigGlyph(glyph, cache, skGlyph, x, y, scale, treatAsBMP);
return;
}
@@ -148,10 +140,17 @@ void GrAtlasTextBlob::appendGlyph(int runIndex,
subRun->glyphAppended();
}
-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));
+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));
}
bool GrAtlasTextBlob::mustRegenerate(const GrTextUtils::Paint& paint,
@@ -274,6 +273,62 @@ 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,
@@ -294,81 +349,94 @@ static void calculate_translation(bool applyVM,
}
}
-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) {
+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);
+ }
+ target->drawPath(clip, bigGlyph.fPath, paint, ctm, nullptr, clipBounds);
+ }
+}
- // 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;
- for (int runIndex = 0; runIndex <= lastRun; runIndex++) {
- Run& run = fRuns[runIndex];
-
- // first flush each subrun
- 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;
- }
+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();
- 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);
- }
- }
- }
+ GrTextUtils::RunPaint runPaint(&paint, drawFilter, props);
+ if (!runPaint.modifyForRun(it)) {
+ return;
+ }
- 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));
- }
- }
- }
- }
+ 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;
+ }
+}
- // now flush any path glyphs
- SkScalar transX, transY;
- 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, paint, ctm, &pathMatrix, clipBounds);
+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);
+ continue;
}
+ 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);
+}
+
+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(
@@ -394,6 +462,15 @@ 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);
@@ -429,6 +506,7 @@ 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++) {
@@ -455,15 +533,6 @@ 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
- }
}
}
diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h
index a75d9f2a38..12a80c49d3 100644
--- a/src/gpu/text/GrAtlasTextBlob.h
+++ b/src/gpu/text/GrAtlasTextBlob.h
@@ -142,6 +142,10 @@ public:
subRun.setHasWCoord(hasWCoord);
}
+ void setRunTooBigForAtlas(int runIndex) {
+ fRuns[runIndex].fTooBigForAtlas = true;
+ }
+
void setMinAndMaxScale(SkScalar scaledMax, SkScalar scaledMin) {
// we init fMaxMinScale and fMinMaxScale in the constructor
fMaxMinScale = SkMaxScalar(scaledMax, fMaxMinScale);
@@ -171,11 +175,7 @@ public:
GrAtlasTextStrike* strike,
GrGlyph* glyph,
SkGlyphCache*, const SkGlyph& skGlyph,
- 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);
+ SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP);
static size_t GetVertexStride(GrMaskFormat maskFormat, bool isDistanceFieldWithWCoord) {
switch (maskFormat) {
@@ -193,11 +193,19 @@ public:
bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilterBase::BlurRec& blurRec,
const SkMatrix& viewMatrix, 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);
+ // 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 computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
@@ -277,6 +285,24 @@ 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
@@ -321,7 +347,9 @@ private:
* would greatly increase the memory of these cached items.
*/
struct Run {
- Run() : fInitialized(false) {
+ Run()
+ : fInitialized(false)
+ , fTooBigForAtlas(false) {
// To ensure we always have one subrun, we push back a fresh run here
fSubRunInfo.push_back();
}
@@ -467,26 +495,8 @@ 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
-
- // 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;
-
bool fInitialized;
+ bool fTooBigForAtlas;
}; // Run
inline std::unique_ptr<GrAtlasTextOp> makeOp(
@@ -496,6 +506,20 @@ 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;
@@ -514,6 +538,7 @@ private:
GrMemoryPool* fPool;
SkMaskFilterBase::BlurRec fBlurRec;
StrokeInfo fStrokeInfo;
+ SkTArray<BigGlyph> fBigGlyphs;
Key fKey;
SkMatrix fInitialViewMatrix;
SkMatrix fInitialViewMatrixInverse;
diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp
index 3155153289..1dce4e0d44 100644
--- a/src/gpu/text/GrAtlasTextContext.cpp
+++ b/src/gpu/text/GrAtlasTextContext.cpp
@@ -11,15 +11,11 @@
#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
@@ -53,6 +49,15 @@ 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) {
@@ -181,8 +186,8 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* t
viewMatrix, props, blob, x, y, drawFilter);
}
- cacheBlob->flush(atlasGlyphCache, target, props, fDistanceAdjustTable.get(), paint,
- clip, viewMatrix, clipBounds, x, y);
+ cacheBlob->flushCached(atlasGlyphCache, target, blob, props, fDistanceAdjustTable.get(), paint,
+ drawFilter, clip, viewMatrix, clipBounds, x, y);
}
void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob,
@@ -230,6 +235,8 @@ void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob,
break;
}
}
+ } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) {
+ cacheBlob->setRunTooBigForAtlas(run);
} else {
switch (it.positioning()) {
case SkTextBlob::kDefault_Positioning:
@@ -321,15 +328,23 @@ void GrAtlasTextContext::drawText(GrContext* context, GrTextUtils::Target* targe
auto textBlobCache = context->contextPriv().getTextBlobCache();
GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo());
- 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);
+ 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;
}
+
+ // 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,
@@ -346,15 +361,23 @@ void GrAtlasTextContext::drawPosText(GrContext* context, GrTextUtils::Target* ta
auto atlasGlyphCache = context->contextPriv().getAtlasGlyphCache();
auto textBlobCache = context->contextPriv().getTextBlobCache();
- 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);
+ 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;
}
+
+ // 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,
@@ -373,11 +396,8 @@ 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,
@@ -412,15 +432,10 @@ 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,
@@ -435,77 +450,6 @@ 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,
@@ -523,7 +467,6 @@ void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex,
if (!glyph) {
return;
}
- glyph->fTooLargeForAtlas = glyph->fTooLargeForAtlas;
SkASSERT(skGlyph.fWidth == glyph->width());
SkASSERT(skGlyph.fHeight == glyph->height());
@@ -732,10 +675,11 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex,
SkTDArray<char> fallbackTxt;
SkTDArray<SkScalar> fallbackPos;
- bool useScaledFallback = false;
+ SkTDArray<char> bigFallbackTxt;
+ SkTDArray<SkScalar> bigFallbackPos;
SkScalar textSize = paint.skPaint().getTextSize();
SkScalar maxTextSize = fontCache->getGlyphSizeLimit();
- SkScalar scaledFallbackTextSize = maxTextSize;
+ SkScalar bigFallbackTextSize = maxTextSize;
SkScalar maxScale = viewMatrix.getMaxScale();
bool hasWCoord = viewMatrix.hasPerspective() || fDistanceFieldVerticesAlwaysHaveW;
@@ -779,30 +723,19 @@ 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
-
- // 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;
- }
- }
- }
+ SkScalar scaledGlyphSize = maxDim*maxScale;
- fallbackTxt.append(SkToInt(text - lastText), lastText);
- if (useScaledFallback) {
- *fallbackPos.append() = maxScale*pos[0];
+ if (!viewMatrix.hasPerspective() && scaledGlyphSize > maxTextSize) {
+ bigFallbackTxt.append(SkToInt(text - lastText), lastText);
+ *bigFallbackPos.append() = maxScale*pos[0];
if (2 == scalarsPerPosition) {
- *fallbackPos.append() = maxScale*pos[1];
+ *bigFallbackPos.append() = maxScale*pos[1];
}
SkScalar glyphTextSize = SkScalarFloorToScalar(maxTextSize*textSize/maxDim);
- scaledFallbackTextSize = SkTMin(glyphTextSize, scaledFallbackTextSize);
+ bigFallbackTextSize = SkTMin(glyphTextSize, bigFallbackTextSize);
} else {
+ fallbackTxt.append(SkToInt(text - lastText), lastText);
*fallbackPos.append() = pos[0];
if (2 == scalarsPerPosition) {
*fallbackPos.append() = pos[1];
@@ -814,35 +747,33 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex,
}
SkGlyphCache::AttachCache(cache);
-
if (fallbackTxt.count()) {
blob->initOverride(runIndex);
- 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);
- }
+ 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
diff --git a/src/gpu/text/GrAtlasTextContext.h b/src/gpu/text/GrAtlasTextContext.h
index 360f6ddbec..36e83c4574 100644
--- a/src/gpu/text/GrAtlasTextContext.h
+++ b/src/gpu/text/GrAtlasTextContext.h
@@ -44,6 +44,9 @@ 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);
@@ -107,16 +110,6 @@ 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;
diff --git a/src/gpu/text/GrTextUtils.cpp b/src/gpu/text/GrTextUtils.cpp
index c2a7d1136f..d354619a43 100644
--- a/src/gpu/text/GrTextUtils.cpp
+++ b/src/gpu/text/GrTextUtils.cpp
@@ -8,10 +8,13 @@
#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
@@ -74,3 +77,82 @@ 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;
+ }
+}
diff --git a/src/gpu/text/GrTextUtils.h b/src/gpu/text/GrTextUtils.h
index 1301b8457b..252cd7c626 100644
--- a/src/gpu/text/GrTextUtils.h
+++ b/src/gpu/text/GrTextUtils.h
@@ -127,6 +127,19 @@ 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