OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrStencilAndCoverTextContext.h" | 8 #include "GrStencilAndCoverTextContext.h" |
9 #include "GrAtlasTextContext.h" | 9 #include "GrAtlasTextContext.h" |
10 #include "GrDrawContext.h" | 10 #include "GrDrawContext.h" |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 int scalarsPerPosition, | 85 int scalarsPerPosition, |
86 const SkPoint& offset, | 86 const SkPoint& offset, |
87 const SkIRect& regionClipBounds
) { | 87 const SkIRect& regionClipBounds
) { |
88 TextRun run(skPaint); | 88 TextRun run(skPaint); |
89 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset, fContext,
&fSurfaceProps); | 89 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset, fContext,
&fSurfaceProps); |
90 run.draw(dc, rt, clip, paint, viewMatrix, regionClipBounds, fFallbackTextCon
text, skPaint); | 90 run.draw(dc, rt, clip, paint, viewMatrix, regionClipBounds, fFallbackTextCon
text, skPaint); |
91 } | 91 } |
92 | 92 |
93 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 93 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
94 | 94 |
| 95 class GrStencilAndCoverTextContext::FallbackBlobBuilder { |
| 96 public: |
| 97 FallbackBlobBuilder() : fBuffIdx(0) {} |
| 98 |
| 99 bool isInitialized() const { return SkToBool(fBuilder); } |
| 100 |
| 101 void init(const SkPaint& font, SkScalar textRatio); |
| 102 |
| 103 void appendGlyph(uint16_t glyphId, const SkPoint& pos); |
| 104 |
| 105 const SkTextBlob* buildIfInitialized(); |
| 106 |
| 107 private: |
| 108 enum { kWriteBufferSize = 1024 }; |
| 109 |
| 110 void flush(); |
| 111 |
| 112 SkAutoTDelete<SkTextBlobBuilder> fBuilder; |
| 113 SkPaint fFont; |
| 114 int fBuffIdx; |
| 115 uint16_t fGlyphIds[kWriteBufferSize]; |
| 116 SkPoint fPositions[kWriteBufferSize]; |
| 117 }; |
| 118 |
| 119 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 120 |
95 GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) | 121 GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) |
96 : fStroke(fontAndStroke), | 122 : fStroke(fontAndStroke), |
97 fFont(fontAndStroke) { | 123 fFont(fontAndStroke) { |
98 SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. | 124 SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. |
99 | 125 |
100 // Setting to "fill" ensures that no strokes get baked into font outlines. (
We use the GPU path | 126 // Setting to "fill" ensures that no strokes get baked into font outlines. (
We use the GPU path |
101 // rendering API for stroking). | 127 // rendering API for stroking). |
102 fFont.setStyle(SkPaint::kFill_Style); | 128 fFont.setStyle(SkPaint::kFill_Style); |
103 | 129 |
104 if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle
()) { | 130 if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle
()) { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 x -= alignX; | 217 x -= alignX; |
192 y -= alignY; | 218 y -= alignY; |
193 } | 219 } |
194 | 220 |
195 SkAutoKern autokern; | 221 SkAutoKern autokern; |
196 | 222 |
197 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); | 223 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); |
198 | 224 |
199 SkFixed fx = SkScalarToFixed(x); | 225 SkFixed fx = SkScalarToFixed(x); |
200 SkFixed fy = SkScalarToFixed(y); | 226 SkFixed fy = SkScalarToFixed(y); |
| 227 FallbackBlobBuilder fallback; |
201 while (text < stop) { | 228 while (text < stop) { |
202 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); | 229 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); |
203 fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio); | 230 fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio); |
204 if (glyph.fWidth) { | 231 if (glyph.fWidth) { |
205 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedT
oScalar(fy))); | 232 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedT
oScalar(fy)), |
| 233 &fallback); |
206 } | 234 } |
207 | 235 |
208 fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio); | 236 fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio); |
209 fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); | 237 fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); |
210 } | 238 } |
| 239 |
| 240 fFallbackTextBlob.reset(fallback.buildIfInitialized()); |
211 } | 241 } |
212 | 242 |
213 void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t
byteLength, | 243 void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t
byteLength, |
214 const SkScalar pos[], int
scalarsPerPosition, | 244 const SkScalar pos[], int
scalarsPerPosition, |
215 const SkPoint& offset, Gr
Context* ctx, | 245 const SkPoint& offset, Gr
Context* ctx, |
216 const SkSurfaceProps* sur
faceProps) { | 246 const SkSurfaceProps* sur
faceProps) { |
217 SkASSERT(byteLength == 0 || text != nullptr); | 247 SkASSERT(byteLength == 0 || text != nullptr); |
218 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 248 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
219 | 249 |
220 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); | 250 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); |
221 SkGlyphCache* glyphCache = autoGlyphCache.getCache(); | 251 SkGlyphCache* glyphCache = autoGlyphCache.getCache(); |
222 | 252 |
223 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), | 253 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), |
224 GrPathRendering::kTranslate_PathTransfor
mType, | 254 GrPathRendering::kTranslate_PathTransfor
mType, |
225 fFont.countText(text, byteLength))); | 255 fFont.countText(text, byteLength))); |
226 | 256 |
227 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); | 257 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); |
228 | 258 |
229 const char* stop = text + byteLength; | 259 const char* stop = text + byteLength; |
230 | 260 |
231 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); | 261 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); |
232 SkTextAlignProc alignProc(fFont.getTextAlign()); | 262 SkTextAlignProc alignProc(fFont.getTextAlign()); |
| 263 FallbackBlobBuilder fallback; |
233 while (text < stop) { | 264 while (text < stop) { |
234 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); | 265 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); |
235 if (glyph.fWidth) { | 266 if (glyph.fWidth) { |
236 SkPoint tmsLoc; | 267 SkPoint tmsLoc; |
237 tmsProc(pos, &tmsLoc); | 268 tmsProc(pos, &tmsLoc); |
238 SkPoint loc; | 269 SkPoint loc; |
239 alignProc(tmsLoc, glyph, &loc); | 270 alignProc(tmsLoc, glyph, &loc); |
240 | 271 |
241 this->appendGlyph(glyph, loc); | 272 this->appendGlyph(glyph, loc, &fallback); |
242 } | 273 } |
243 pos += scalarsPerPosition; | 274 pos += scalarsPerPosition; |
244 } | 275 } |
| 276 |
| 277 fFallbackTextBlob.reset(fallback.buildIfInitialized()); |
245 } | 278 } |
246 | 279 |
247 GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx, | 280 GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx, |
248 SkGlyphCache* g
lyphCache) { | 281 SkGlyphCache* g
lyphCache) { |
249 SkTypeface* typeface = fUsingRawGlyphPaths ? fFont.getTypeface() | 282 SkTypeface* typeface = fUsingRawGlyphPaths ? fFont.getTypeface() |
250 : glyphCache->getScalerContext()-
>getTypeface(); | 283 : glyphCache->getScalerContext()-
>getTypeface(); |
251 const SkDescriptor* desc = fUsingRawGlyphPaths ? nullptr : &glyphCache->getD
escriptor(); | 284 const SkDescriptor* desc = fUsingRawGlyphPaths ? nullptr : &glyphCache->getD
escriptor(); |
252 | 285 |
253 static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDom
ain(); | 286 static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDom
ain(); |
254 int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt(); | 287 int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt(); |
(...skipping 13 matching lines...) Expand all Loading... |
268 glyphs.reset(ctx->resourceProvider()->createGlyphs(typeface, desc, fStro
ke)); | 301 glyphs.reset(ctx->resourceProvider()->createGlyphs(typeface, desc, fStro
ke)); |
269 ctx->resourceProvider()->assignUniqueKeyToResource(glyphKey, glyphs); | 302 ctx->resourceProvider()->assignUniqueKeyToResource(glyphKey, glyphs); |
270 } else { | 303 } else { |
271 SkASSERT(nullptr == desc || glyphs->isEqualTo(*desc)); | 304 SkASSERT(nullptr == desc || glyphs->isEqualTo(*desc)); |
272 } | 305 } |
273 | 306 |
274 return glyphs.detach(); | 307 return glyphs.detach(); |
275 } | 308 } |
276 | 309 |
277 inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& gl
yph, | 310 inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& gl
yph, |
278 const SkPoint& po
s) { | 311 const SkPoint& po
s, |
279 // Stick the glyphs we can't draw into the fallback arrays. | 312 FallbackBlobBuild
er* fallback) { |
| 313 // Stick the glyphs we can't draw into the fallback text blob. |
280 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { | 314 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { |
281 fFallbackIndices.push_back(glyph.getGlyphID()); | 315 if (!fallback->isInitialized()) { |
282 fFallbackPositions.push_back(pos); | 316 fallback->init(fFont, fTextRatio); |
| 317 } |
| 318 fallback->appendGlyph(glyph.getGlyphID(), pos); |
283 } else { | 319 } else { |
284 float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * p
os.y() }; | 320 float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * p
os.y() }; |
285 fDraw->append(glyph.getGlyphID(), translate); | 321 fDraw->append(glyph.getGlyphID(), translate); |
286 } | 322 } |
287 } | 323 } |
288 | 324 |
289 void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc, | 325 void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc, |
290 GrRenderTarget* rt, | 326 GrRenderTarget* rt, |
291 const GrClip& clip, | 327 const GrClip& clip, |
292 const GrPaint& paint, | 328 const GrPaint& paint, |
(...skipping 18 matching lines...) Expand all Loading... |
311 | 347 |
312 *pipelineBuilder.stencil() = kStencilPass; | 348 *pipelineBuilder.stencil() = kStencilPass; |
313 | 349 |
314 SkMatrix drawMatrix(viewMatrix); | 350 SkMatrix drawMatrix(viewMatrix); |
315 drawMatrix.preScale(fTextRatio, fTextRatio); | 351 drawMatrix.preScale(fTextRatio, fTextRatio); |
316 | 352 |
317 dc->drawPathsFromRange(&pipelineBuilder, drawMatrix, fLocalMatrix, paint
.getColor(), fDraw, | 353 dc->drawPathsFromRange(&pipelineBuilder, drawMatrix, fLocalMatrix, paint
.getColor(), fDraw, |
318 GrPathRendering::kWinding_FillType); | 354 GrPathRendering::kWinding_FillType); |
319 } | 355 } |
320 | 356 |
321 if (fFallbackIndices.count()) { | 357 if (fFallbackTextBlob) { |
322 SkASSERT(fFallbackPositions.count() == fFallbackIndices.count()); | |
323 | |
324 enum { kPreservedFlags = SkPaint::kFakeBoldText_Flag | SkPaint::kLinearT
ext_Flag | | |
325 SkPaint::kLCDRenderText_Flag | SkPaint::kAutoHi
nting_Flag }; | |
326 | |
327 SkPaint fallbackSkPaint(originalSkPaint); | 358 SkPaint fallbackSkPaint(originalSkPaint); |
328 fStroke.applyToPaint(&fallbackSkPaint); | 359 fStroke.applyToPaint(&fallbackSkPaint); |
329 if (!fStroke.isFillStyle()) { | 360 if (!fStroke.isFillStyle()) { |
330 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); | 361 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); |
331 } | 362 } |
332 fallbackSkPaint.setTextAlign(SkPaint::kLeft_Align); // Align has already
been accounted for. | |
333 fallbackSkPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | |
334 fallbackSkPaint.setHinting(fFont.getHinting()); | |
335 fallbackSkPaint.setFlags((fFont.getFlags() & kPreservedFlags) | | |
336 (originalSkPaint.getFlags() & ~kPreservedFlags)
); | |
337 // No need for subpixel positioning with bitmap glyphs. TODO: revisit if
non-bitmap color | |
338 // glyphs show up and https://code.google.com/p/skia/issues/detail?id=44
08 gets resolved. | |
339 fallbackSkPaint.setSubpixelText(false); | |
340 fallbackSkPaint.setTextSize(fFont.getTextSize() * fTextRatio); | |
341 | 363 |
342 fallbackTextContext->drawPosText(dc, rt, clip, paint, fallbackSkPaint, v
iewMatrix, | 364 fallbackTextContext->drawTextBlob(dc, rt, clip, fallbackSkPaint, viewMat
rix, |
343 (char*)fFallbackIndices.begin(), | 365 fFallbackTextBlob, 0, 0, nullptr, regi
onClipBounds); |
344 sizeof(uint16_t) * fFallbackIndices.cou
nt(), | |
345 fFallbackPositions[0].asScalars(), 2, S
kPoint::Make(0, 0), | |
346 regionClipBounds); | |
347 } | 366 } |
348 } | 367 } |
| 368 |
| 369 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 370 |
| 371 void GrStencilAndCoverTextContext::FallbackBlobBuilder::init(const SkPaint& font
, |
| 372 SkScalar textRatio)
{ |
| 373 SkASSERT(!this->isInitialized()); |
| 374 fBuilder.reset(new SkTextBlobBuilder); |
| 375 fFont = font; |
| 376 fFont.setTextAlign(SkPaint::kLeft_Align); // The glyph positions will alread
y account for align. |
| 377 fFont.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| 378 // No need for subpixel positioning with bitmap glyphs. TODO: revisit if non
-bitmap color glyphs |
| 379 // show up and https://code.google.com/p/skia/issues/detail?id=4408 gets res
olved. |
| 380 fFont.setSubpixelText(false); |
| 381 fFont.setTextSize(fFont.getTextSize() * textRatio); |
| 382 fBuffIdx = 0; |
| 383 } |
| 384 |
| 385 void GrStencilAndCoverTextContext::FallbackBlobBuilder::appendGlyph(uint16_t gly
phId, |
| 386 const SkPoin
t& pos) { |
| 387 SkASSERT(this->isInitialized()); |
| 388 if (fBuffIdx >= kWriteBufferSize) { |
| 389 this->flush(); |
| 390 } |
| 391 fGlyphIds[fBuffIdx] = glyphId; |
| 392 fPositions[fBuffIdx] = pos; |
| 393 fBuffIdx++; |
| 394 } |
| 395 |
| 396 void GrStencilAndCoverTextContext::FallbackBlobBuilder::flush() { |
| 397 SkASSERT(this->isInitialized()); |
| 398 SkASSERT(fBuffIdx <= kWriteBufferSize); |
| 399 if (!fBuffIdx) { |
| 400 return; |
| 401 } |
| 402 // This will automatically merge with previous runs since we use the same fo
nt. |
| 403 const SkTextBlobBuilder::RunBuffer& buff = fBuilder->allocRunPos(fFont, fBuf
fIdx); |
| 404 memcpy(buff.glyphs, fGlyphIds, fBuffIdx * sizeof(uint16_t)); |
| 405 memcpy(buff.pos, fPositions[0].asScalars(), fBuffIdx * 2 * sizeof(SkScalar))
; |
| 406 fBuffIdx = 0; |
| 407 } |
| 408 |
| 409 const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfInit
ialized() { |
| 410 if (!this->isInitialized()) { |
| 411 return nullptr; |
| 412 } |
| 413 this->flush(); |
| 414 return fBuilder->build(); |
| 415 } |
OLD | NEW |