Index: src/gpu/GrStencilAndCoverTextContext.cpp |
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp |
index 9f394f901875364ff3fc59570716a215410f86f1..61f7f864d72ae122bca549a618da7cda9810571c 100644 |
--- a/src/gpu/GrStencilAndCoverTextContext.cpp |
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp |
@@ -92,6 +92,32 @@ void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarg |
//////////////////////////////////////////////////////////////////////////////////////////////////// |
+class GrStencilAndCoverTextContext::FallbackBlobBuilder { |
+public: |
+ FallbackBlobBuilder() : fBuffIdx(0) {} |
+ |
+ bool isInitialized() const { return SkToBool(fBuilder); } |
+ |
+ void init(const SkPaint& font, SkScalar textRatio); |
+ |
+ void appendGlyph(uint16_t glyphId, const SkPoint& pos); |
+ |
+ const SkTextBlob* buildIfInitialized(); |
+ |
+private: |
+ enum { kWriteBufferSize = 1024 }; |
+ |
+ void flush(); |
+ |
+ SkAutoTDelete<SkTextBlobBuilder> fBuilder; |
+ SkPaint fFont; |
+ int fBuffIdx; |
+ uint16_t fGlyphIds[kWriteBufferSize]; |
+ SkPoint fPositions[kWriteBufferSize]; |
+}; |
+ |
+//////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) |
: fStroke(fontAndStroke), |
fFont(fontAndStroke) { |
@@ -198,16 +224,20 @@ void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t by |
SkFixed fx = SkScalarToFixed(x); |
SkFixed fy = SkScalarToFixed(y); |
+ FallbackBlobBuilder fallback; |
while (text < stop) { |
const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); |
fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio); |
if (glyph.fWidth) { |
- this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy))); |
+ this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy)), |
+ &fallback); |
} |
fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio); |
fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); |
} |
+ |
+ fFallbackTextBlob.reset(fallback.buildIfInitialized()); |
} |
void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t byteLength, |
@@ -230,6 +260,7 @@ void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t |
SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); |
SkTextAlignProc alignProc(fFont.getTextAlign()); |
+ FallbackBlobBuilder fallback; |
while (text < stop) { |
const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); |
if (glyph.fWidth) { |
@@ -238,10 +269,12 @@ void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t |
SkPoint loc; |
alignProc(tmsLoc, glyph, &loc); |
- this->appendGlyph(glyph, loc); |
+ this->appendGlyph(glyph, loc, &fallback); |
} |
pos += scalarsPerPosition; |
} |
+ |
+ fFallbackTextBlob.reset(fallback.buildIfInitialized()); |
} |
GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx, |
@@ -275,11 +308,14 @@ GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx, |
} |
inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& glyph, |
- const SkPoint& pos) { |
- // Stick the glyphs we can't draw into the fallback arrays. |
+ const SkPoint& pos, |
+ FallbackBlobBuilder* fallback) { |
+ // Stick the glyphs we can't draw into the fallback text blob. |
if (SkMask::kARGB32_Format == glyph.fMaskFormat) { |
- fFallbackIndices.push_back(glyph.getGlyphID()); |
- fFallbackPositions.push_back(pos); |
+ if (!fallback->isInitialized()) { |
+ fallback->init(fFont, fTextRatio); |
+ } |
+ fallback->appendGlyph(glyph.getGlyphID(), pos); |
} else { |
float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * pos.y() }; |
fDraw->append(glyph.getGlyphID(), translate); |
@@ -318,31 +354,62 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc, |
GrPathRendering::kWinding_FillType); |
} |
- if (fFallbackIndices.count()) { |
- SkASSERT(fFallbackPositions.count() == fFallbackIndices.count()); |
- |
- enum { kPreservedFlags = SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag | |
- SkPaint::kLCDRenderText_Flag | SkPaint::kAutoHinting_Flag }; |
- |
+ if (fFallbackTextBlob) { |
SkPaint fallbackSkPaint(originalSkPaint); |
fStroke.applyToPaint(&fallbackSkPaint); |
if (!fStroke.isFillStyle()) { |
fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); |
} |
- fallbackSkPaint.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for. |
- fallbackSkPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
- fallbackSkPaint.setHinting(fFont.getHinting()); |
- fallbackSkPaint.setFlags((fFont.getFlags() & kPreservedFlags) | |
- (originalSkPaint.getFlags() & ~kPreservedFlags)); |
- // No need for subpixel positioning with bitmap glyphs. TODO: revisit if non-bitmap color |
- // glyphs show up and https://code.google.com/p/skia/issues/detail?id=4408 gets resolved. |
- fallbackSkPaint.setSubpixelText(false); |
- fallbackSkPaint.setTextSize(fFont.getTextSize() * fTextRatio); |
- |
- fallbackTextContext->drawPosText(dc, rt, clip, paint, fallbackSkPaint, viewMatrix, |
- (char*)fFallbackIndices.begin(), |
- sizeof(uint16_t) * fFallbackIndices.count(), |
- fFallbackPositions[0].asScalars(), 2, SkPoint::Make(0, 0), |
- regionClipBounds); |
+ |
+ fallbackTextContext->drawTextBlob(dc, rt, clip, fallbackSkPaint, viewMatrix, |
+ fFallbackTextBlob, 0, 0, nullptr, regionClipBounds); |
+ } |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+void GrStencilAndCoverTextContext::FallbackBlobBuilder::init(const SkPaint& font, |
+ SkScalar textRatio) { |
+ SkASSERT(!this->isInitialized()); |
+ fBuilder.reset(new SkTextBlobBuilder); |
+ fFont = font; |
+ fFont.setTextAlign(SkPaint::kLeft_Align); // The glyph positions will already account for align. |
+ fFont.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
+ // No need for subpixel positioning with bitmap glyphs. TODO: revisit if non-bitmap color glyphs |
+ // show up and https://code.google.com/p/skia/issues/detail?id=4408 gets resolved. |
+ fFont.setSubpixelText(false); |
+ fFont.setTextSize(fFont.getTextSize() * textRatio); |
+ fBuffIdx = 0; |
+} |
+ |
+void GrStencilAndCoverTextContext::FallbackBlobBuilder::appendGlyph(uint16_t glyphId, |
+ const SkPoint& pos) { |
+ SkASSERT(this->isInitialized()); |
+ if (fBuffIdx >= kWriteBufferSize) { |
+ this->flush(); |
+ } |
+ fGlyphIds[fBuffIdx] = glyphId; |
+ fPositions[fBuffIdx] = pos; |
+ fBuffIdx++; |
+} |
+ |
+void GrStencilAndCoverTextContext::FallbackBlobBuilder::flush() { |
+ SkASSERT(this->isInitialized()); |
+ SkASSERT(fBuffIdx <= kWriteBufferSize); |
+ if (!fBuffIdx) { |
+ return; |
+ } |
+ // This will automatically merge with previous runs since we use the same font. |
+ const SkTextBlobBuilder::RunBuffer& buff = fBuilder->allocRunPos(fFont, fBuffIdx); |
+ memcpy(buff.glyphs, fGlyphIds, fBuffIdx * sizeof(uint16_t)); |
+ memcpy(buff.pos, fPositions[0].asScalars(), fBuffIdx * 2 * sizeof(SkScalar)); |
+ fBuffIdx = 0; |
+} |
+ |
+const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfInitialized() { |
+ if (!this->isInitialized()) { |
+ return nullptr; |
} |
+ this->flush(); |
+ return fBuilder->build(); |
} |