OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 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 "GrDistanceFieldTextContext.h" | 8 #include "GrDistanceFieldTextContext.h" |
9 #include "GrAtlas.h" | 9 #include "GrAtlas.h" |
10 #include "GrBitmapTextContext.h" | 10 #include "GrBitmapTextContext.h" |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
72 (context, props, enable
)); | 72 (context, props, enable
)); |
73 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, pro
ps); | 73 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, pro
ps); |
74 | 74 |
75 return textContext; | 75 return textContext; |
76 } | 76 } |
77 | 77 |
78 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() { | 78 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() { |
79 SkSafeSetNull(fGammaTexture); | 79 SkSafeSetNull(fGammaTexture); |
80 } | 80 } |
81 | 81 |
82 bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) { | 82 bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint, const SkMatrix& v
iewMatrix) { |
83 if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) { | 83 if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) { |
84 return false; | 84 return false; |
85 } | 85 } |
86 | 86 |
87 // rasterizers and mask filters modify alpha, which doesn't | 87 // rasterizers and mask filters modify alpha, which doesn't |
88 // translate well to distance | 88 // translate well to distance |
89 if (paint.getRasterizer() || paint.getMaskFilter() || | 89 if (paint.getRasterizer() || paint.getMaskFilter() || |
90 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) { | 90 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) { |
91 return false; | 91 return false; |
92 } | 92 } |
93 | 93 |
94 // TODO: add some stroking support | 94 // TODO: add some stroking support |
95 if (paint.getStyle() != SkPaint::kFill_Style) { | 95 if (paint.getStyle() != SkPaint::kFill_Style) { |
96 return false; | 96 return false; |
97 } | 97 } |
98 | 98 |
99 // TODO: choose an appropriate maximum scale for distance fields and | 99 // TODO: choose an appropriate maximum scale for distance fields and |
100 // enable perspective | 100 // enable perspective |
101 if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) { | 101 if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) { |
102 return false; | 102 return false; |
103 } | 103 } |
104 | 104 |
105 return true; | 105 return true; |
106 } | 106 } |
107 | 107 |
108 inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint
& skPaint) { | 108 inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint
& skPaint) { |
109 GrTextContext::init(paint, skPaint); | 109 GrTextContext::init(paint, skPaint); |
110 | 110 |
111 fStrike = NULL; | 111 fStrike = NULL; |
112 | 112 |
113 const SkMatrix& ctm = fContext->getMatrix(); | 113 const SkMatrix& ctm = fViewMatrix; |
114 | 114 |
115 // getMaxScale doesn't support perspective, so neither do we at the moment | 115 // getMaxScale doesn't support perspective, so neither do we at the moment |
116 SkASSERT(!ctm.hasPerspective()); | 116 SkASSERT(!ctm.hasPerspective()); |
117 SkScalar maxScale = ctm.getMaxScale(); | 117 SkScalar maxScale = ctm.getMaxScale(); |
118 SkScalar textSize = fSkPaint.getTextSize(); | 118 SkScalar textSize = fSkPaint.getTextSize(); |
119 SkScalar scaledTextSize = textSize; | 119 SkScalar scaledTextSize = textSize; |
120 // if we have non-unity scale, we need to choose our base text size | 120 // if we have non-unity scale, we need to choose our base text size |
121 // based on the SkPaint's text size multiplied by the max scale factor | 121 // based on the SkPaint's text size multiplied by the max scale factor |
122 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? | 122 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? |
123 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { | 123 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 return; | 193 return; |
194 } | 194 } |
195 | 195 |
196 (*gammaTexture)->writePixels(0, 0, width, height, | 196 (*gammaTexture)->writePixels(0, 0, width, height, |
197 (*gammaTexture)->config(), data.get(), 0, | 197 (*gammaTexture)->config(), data.get(), 0, |
198 GrContext::kDontFlush_PixelOpsFlag); | 198 GrContext::kDontFlush_PixelOpsFlag); |
199 } | 199 } |
200 } | 200 } |
201 | 201 |
202 void GrDistanceFieldTextContext::onDrawText(const GrPaint& paint, const SkPaint&
skPaint, | 202 void GrDistanceFieldTextContext::onDrawText(const GrPaint& paint, const SkPaint&
skPaint, |
203 const char text[], size_t byteLength, | 203 const SkMatrix& viewMatrix, |
204 SkScalar x, SkScalar y) { | 204 const char text[], size_t byteLength
, |
| 205 SkScalar x, SkScalar y) { |
205 SkASSERT(byteLength == 0 || text != NULL); | 206 SkASSERT(byteLength == 0 || text != NULL); |
206 | 207 |
207 // nothing to draw | 208 // nothing to draw |
208 if (text == NULL || byteLength == 0) { | 209 if (text == NULL || byteLength == 0) { |
209 return; | 210 return; |
210 } | 211 } |
211 | 212 |
| 213 fViewMatrix = viewMatrix; |
212 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); | 214 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); |
213 SkAutoGlyphCache autoCache(skPaint, &fDeviceProperties, NULL); | 215 SkAutoGlyphCache autoCache(skPaint, &fDeviceProperties, NULL); |
214 SkGlyphCache* cache = autoCache.getCache(); | 216 SkGlyphCache* cache = autoCache.getCache(); |
215 | 217 |
216 SkTArray<SkScalar> positions; | 218 SkTArray<SkScalar> positions; |
217 | 219 |
218 const char* textPtr = text; | 220 const char* textPtr = text; |
219 SkFixed stopX = 0; | 221 SkFixed stopX = 0; |
220 SkFixed stopY = 0; | 222 SkFixed stopY = 0; |
221 SkFixed origin; | 223 SkFixed origin; |
(...skipping 29 matching lines...) Expand all Loading... |
251 alignX = SkScalarHalf(alignX); | 253 alignX = SkScalarHalf(alignX); |
252 alignY = SkScalarHalf(alignY); | 254 alignY = SkScalarHalf(alignY); |
253 } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) { | 255 } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) { |
254 alignX = 0; | 256 alignX = 0; |
255 alignY = 0; | 257 alignY = 0; |
256 } | 258 } |
257 x -= alignX; | 259 x -= alignX; |
258 y -= alignY; | 260 y -= alignY; |
259 SkPoint offset = SkPoint::Make(x, y); | 261 SkPoint offset = SkPoint::Make(x, y); |
260 | 262 |
261 this->drawPosText(paint, skPaint, text, byteLength, positions.begin(), 2, of
fset); | 263 this->drawPosText(paint, skPaint, viewMatrix, text, byteLength, positions.be
gin(), 2, offset); |
262 } | 264 } |
263 | 265 |
264 void GrDistanceFieldTextContext::onDrawPosText(const GrPaint& paint, const SkPai
nt& skPaint, | 266 void GrDistanceFieldTextContext::onDrawPosText(const GrPaint& paint, const SkPai
nt& skPaint, |
265 const char text[], size_t byteLengt
h, | 267 const SkMatrix& viewMatrix, |
266 const SkScalar pos[], int scalarsPe
rPosition, | 268 const char text[], size_t byteLen
gth, |
267 const SkPoint& offset) { | 269 const SkScalar pos[], int scalars
PerPosition, |
| 270 const SkPoint& offset) { |
268 | 271 |
269 SkASSERT(byteLength == 0 || text != NULL); | 272 SkASSERT(byteLength == 0 || text != NULL); |
270 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 273 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
271 | 274 |
272 // nothing to draw | 275 // nothing to draw |
273 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/)
{ | 276 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/)
{ |
274 return; | 277 return; |
275 } | 278 } |
276 | 279 |
| 280 fViewMatrix = viewMatrix; |
277 this->init(paint, skPaint); | 281 this->init(paint, skPaint); |
278 | 282 |
279 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 283 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
280 | 284 |
281 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL); | 285 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL); |
282 SkGlyphCache* cache = autoCache.getCache(); | 286 SkGlyphCache* cache = autoCache.getCache(); |
283 GrFontScaler* fontScaler = GetGrFontScaler(cache); | 287 GrFontScaler* fontScaler = GetGrFontScaler(cache); |
284 | 288 |
285 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture); | 289 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture); |
286 | 290 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 } | 346 } |
343 } | 347 } |
344 } | 348 } |
345 pos += scalarsPerPosition; | 349 pos += scalarsPerPosition; |
346 } | 350 } |
347 } | 351 } |
348 | 352 |
349 this->finish(); | 353 this->finish(); |
350 | 354 |
351 if (fallbackTxt.count() > 0) { | 355 if (fallbackTxt.count() > 0) { |
352 fFallbackTextContext->drawPosText(paint, skPaint, fallbackTxt.begin(), f
allbackTxt.count(), | 356 fFallbackTextContext->drawPosText(paint, skPaint, viewMatrix, fallbackTx
t.begin(), |
353 fallbackPos.begin(), scalarsPerPositio
n, offset); | 357 fallbackTxt.count(), fallbackPos.begin
(), |
| 358 scalarsPerPosition, offset); |
354 } | 359 } |
355 } | 360 } |
356 | 361 |
357 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { | 362 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { |
358 unsigned r = SkColorGetR(c); | 363 unsigned r = SkColorGetR(c); |
359 unsigned g = SkColorGetG(c); | 364 unsigned g = SkColorGetG(c); |
360 unsigned b = SkColorGetB(c); | 365 unsigned b = SkColorGetB(c); |
361 return GrColorPackRGBA(r, g, b, 0xff); | 366 return GrColorPackRGBA(r, g, b, 0xff); |
362 } | 367 } |
363 | 368 |
(...skipping 17 matching lines...) Expand all Loading... |
381 NULL); | 386 NULL); |
382 GrAlwaysAssert(success); | 387 GrAlwaysAssert(success); |
383 return vertices; | 388 return vertices; |
384 } | 389 } |
385 | 390 |
386 void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColo
r) { | 391 void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColo
r) { |
387 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_
FilterMode); | 392 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_
FilterMode); |
388 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNon
e_FilterMode); | 393 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNon
e_FilterMode); |
389 | 394 |
390 uint32_t textureUniqueID = fCurrTexture->getUniqueID(); | 395 uint32_t textureUniqueID = fCurrTexture->getUniqueID(); |
391 const SkMatrix& ctm = fContext->getMatrix(); | 396 const SkMatrix& ctm = fViewMatrix; |
392 | 397 |
393 // set up any flags | 398 // set up any flags |
394 uint32_t flags = 0; | 399 uint32_t flags = 0; |
395 flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; | 400 flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; |
396 flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0; | 401 flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0; |
397 flags |= fUseLCDText && ctm.rectStaysRect() ? | 402 flags |= fUseLCDText && ctm.rectStaysRect() ? |
398 kRectToRect_DistanceFieldEffectFlag : 0; | 403 kRectToRect_DistanceFieldEffectFlag : 0; |
399 bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.pixelGeometry()); | 404 bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.pixelGeometry()); |
400 flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0; | 405 flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0; |
401 | 406 |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
510 dx *= scale; | 515 dx *= scale; |
511 dy *= scale; | 516 dy *= scale; |
512 sx += dx; | 517 sx += dx; |
513 sy += dy; | 518 sy += dy; |
514 width *= scale; | 519 width *= scale; |
515 height *= scale; | 520 height *= scale; |
516 SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); | 521 SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); |
517 | 522 |
518 // check if we clipped out | 523 // check if we clipped out |
519 SkRect dstRect; | 524 SkRect dstRect; |
520 const SkMatrix& ctm = fContext->getMatrix(); | 525 const SkMatrix& ctm = fViewMatrix; |
521 (void) ctm.mapRect(&dstRect, glyphRect); | 526 (void) ctm.mapRect(&dstRect, glyphRect); |
522 if (fClipRect.quickReject(SkScalarTruncToInt(dstRect.left()), | 527 if (fClipRect.quickReject(SkScalarTruncToInt(dstRect.left()), |
523 SkScalarTruncToInt(dstRect.top()), | 528 SkScalarTruncToInt(dstRect.top()), |
524 SkScalarTruncToInt(dstRect.right()), | 529 SkScalarTruncToInt(dstRect.right()), |
525 SkScalarTruncToInt(dstRect.bottom()))) { | 530 SkScalarTruncToInt(dstRect.bottom()))) { |
526 // SkCLZ(3); // so we can set a break-point in the debugger | 531 // SkCLZ(3); // so we can set a break-point in the debugger |
527 return true; | 532 return true; |
528 } | 533 } |
529 | 534 |
530 if (NULL == glyph->fPlot) { | 535 if (NULL == glyph->fPlot) { |
531 // needs to be a separate conditional to avoid over-optimization | 536 // needs to be a separate conditional to avoid over-optimization |
532 // on Nexus 7 and Nexus 10 | 537 // on Nexus 7 and Nexus 10 |
533 if (!uploadGlyph(glyph, scaler)) { | 538 if (!uploadGlyph(glyph, scaler)) { |
534 if (NULL == glyph->fPath) { | 539 if (NULL == glyph->fPath) { |
535 SkPath* path = SkNEW(SkPath); | 540 SkPath* path = SkNEW(SkPath); |
536 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { | 541 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { |
537 // flag the glyph as being dead? | 542 // flag the glyph as being dead? |
538 delete path; | 543 delete path; |
539 return true; | 544 return true; |
540 } | 545 } |
541 glyph->fPath = path; | 546 glyph->fPath = path; |
542 } | 547 } |
543 | 548 |
544 // flush any accumulated draws before drawing this glyph as a path. | 549 // flush any accumulated draws before drawing this glyph as a path. |
545 this->flush(); | 550 this->flush(); |
546 | 551 |
547 GrContext::AutoMatrix am; | |
548 SkMatrix ctm; | 552 SkMatrix ctm; |
549 ctm.setScale(fTextRatio, fTextRatio); | 553 ctm.setScale(fTextRatio, fTextRatio); |
550 ctm.postTranslate(sx - dx, sy - dy); | 554 ctm.postTranslate(sx - dx, sy - dy); |
551 GrPaint tmpPaint(fPaint); | 555 GrPaint tmpPaint(fPaint); |
552 am.setPreConcat(fContext, ctm, &tmpPaint); | 556 tmpPaint.localCoordChange(ctm); |
| 557 |
| 558 SkMatrix viewM = fViewMatrix; |
| 559 viewM.preConcat(ctm); |
553 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); | 560 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); |
554 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo); | 561 fContext->drawPath(tmpPaint, viewM, *glyph->fPath, strokeInfo); |
555 | 562 |
556 // remove this glyph from the vertices we need to allocate | 563 // remove this glyph from the vertices we need to allocate |
557 fTotalVertexCount -= kVerticesPerGlyph; | 564 fTotalVertexCount -= kVerticesPerGlyph; |
558 return true; | 565 return true; |
559 } | 566 } |
560 } | 567 } |
561 | 568 |
562 SkASSERT(glyph->fPlot); | 569 SkASSERT(glyph->fPlot); |
563 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken(); | 570 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken(); |
564 glyph->fPlot->setDrawToken(drawToken); | 571 glyph->fPlot->setDrawToken(drawToken); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 return true; | 625 return true; |
619 } | 626 } |
620 | 627 |
621 void GrDistanceFieldTextContext::flush() { | 628 void GrDistanceFieldTextContext::flush() { |
622 if (NULL == fDrawTarget) { | 629 if (NULL == fDrawTarget) { |
623 return; | 630 return; |
624 } | 631 } |
625 | 632 |
626 if (fCurrVertex > 0) { | 633 if (fCurrVertex > 0) { |
627 GrDrawState drawState; | 634 GrDrawState drawState; |
628 drawState.setFromPaint(fPaint, fContext->getMatrix(), fContext->getRende
rTarget()); | 635 drawState.setFromPaint(fPaint, fViewMatrix, fContext->getRenderTarget())
; |
629 | 636 |
630 // setup our sampler state for our text texture/atlas | 637 // setup our sampler state for our text texture/atlas |
631 SkASSERT(SkIsAlign4(fCurrVertex)); | 638 SkASSERT(SkIsAlign4(fCurrVertex)); |
632 | 639 |
633 // get our current color | 640 // get our current color |
634 SkColor filteredColor; | 641 SkColor filteredColor; |
635 SkColorFilter* colorFilter = fSkPaint.getColorFilter(); | 642 SkColorFilter* colorFilter = fSkPaint.getColorFilter(); |
636 if (colorFilter) { | 643 if (colorFilter) { |
637 filteredColor = colorFilter->filterColor(fSkPaint.getColor()); | 644 filteredColor = colorFilter->filterColor(fSkPaint.getColor()); |
638 } else { | 645 } else { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
671 } | 678 } |
672 } | 679 } |
673 | 680 |
674 inline void GrDistanceFieldTextContext::finish() { | 681 inline void GrDistanceFieldTextContext::finish() { |
675 this->flush(); | 682 this->flush(); |
676 fTotalVertexCount = 0; | 683 fTotalVertexCount = 0; |
677 | 684 |
678 GrTextContext::finish(); | 685 GrTextContext::finish(); |
679 } | 686 } |
680 | 687 |
OLD | NEW |