| 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 |