| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 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 #include "GrAtlasTextContext.h" | 7 #include "GrAtlasTextContext.h" |
| 8 | 8 |
| 9 #include "GrAtlas.h" | 9 #include "GrAtlas.h" |
| 10 #include "GrBatch.h" | 10 #include "GrBatch.h" |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 if (blob.fViewMatrix.cheapEqualTo(viewMatrix) && x == blob.fX && y == blob.f
Y) { | 280 if (blob.fViewMatrix.cheapEqualTo(viewMatrix) && x == blob.fX && y == blob.f
Y) { |
| 281 return false; | 281 return false; |
| 282 } | 282 } |
| 283 | 283 |
| 284 // Mixed blobs must be regenerated. We could probably figure out a way to d
o integer scrolls | 284 // Mixed blobs must be regenerated. We could probably figure out a way to d
o integer scrolls |
| 285 // for mixed blobs if this becomes an issue. | 285 // for mixed blobs if this becomes an issue. |
| 286 if (blob.hasBitmap() && blob.hasDistanceField()) { | 286 if (blob.hasBitmap() && blob.hasDistanceField()) { |
| 287 return true; | 287 return true; |
| 288 } | 288 } |
| 289 | 289 |
| 290 // TODO distance fields can handle many of these conditions | |
| 291 if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() || | |
| 292 blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() || | |
| 293 blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() || | |
| 294 blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) { | |
| 295 return true; | |
| 296 } | |
| 297 | |
| 298 if (blob.hasBitmap()) { | 290 if (blob.hasBitmap()) { |
| 291 if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() || |
| 292 blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() || |
| 293 blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() || |
| 294 blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) { |
| 295 return true; |
| 296 } |
| 297 |
| 299 // We can update the positions in the cachedtextblobs without regenerati
ng the whole blob, | 298 // We can update the positions in the cachedtextblobs without regenerati
ng the whole blob, |
| 300 // but only for integer translations. | 299 // but only for integer translations. |
| 301 // This cool bit of math will determine the necessary translation to app
ly to the already | 300 // This cool bit of math will determine the necessary translation to app
ly to the already |
| 302 // generated vertex coordinates to move them to the correct position | 301 // generated vertex coordinates to move them to the correct position |
| 303 SkScalar transX = viewMatrix.getTranslateX() + | 302 SkScalar transX = viewMatrix.getTranslateX() + |
| 304 viewMatrix.getScaleX() * (x - blob.fX) + | 303 viewMatrix.getScaleX() * (x - blob.fX) + |
| 305 viewMatrix.getSkewX() * (y - blob.fY) - | 304 viewMatrix.getSkewX() * (y - blob.fY) - |
| 306 blob.fViewMatrix.getTranslateX(); | 305 blob.fViewMatrix.getTranslateX(); |
| 307 SkScalar transY = viewMatrix.getTranslateY() + | 306 SkScalar transY = viewMatrix.getTranslateY() + |
| 308 viewMatrix.getSkewY() * (x - blob.fX) + | 307 viewMatrix.getSkewY() * (x - blob.fX) + |
| (...skipping 12 matching lines...) Expand all Loading... |
| 321 blob.fTotalXError += SkScalarAbs(SkScalarFraction(transX)); | 320 blob.fTotalXError += SkScalarAbs(SkScalarFraction(transX)); |
| 322 blob.fTotalYError += SkScalarAbs(SkScalarFraction(transY)); | 321 blob.fTotalYError += SkScalarAbs(SkScalarFraction(transY)); |
| 323 if (blob.fTotalXError > kMinDiscernableTranslation || | 322 if (blob.fTotalXError > kMinDiscernableTranslation || |
| 324 blob.fTotalYError > kMinDiscernableTranslation) { | 323 blob.fTotalYError > kMinDiscernableTranslation) { |
| 325 SkDebugf("Exceeding error threshold for bitmap text translation"); | 324 SkDebugf("Exceeding error threshold for bitmap text translation"); |
| 326 } | 325 } |
| 327 #endif | 326 #endif |
| 328 (*outTransX) = transX; | 327 (*outTransX) = transX; |
| 329 (*outTransY) = transY; | 328 (*outTransY) = transY; |
| 330 } else { | 329 } else { |
| 331 // blob.hasDistanceField() | 330 SkASSERT(blob.hasDistanceField()); |
| 332 // TODO figure out the regen formula | 331 // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would resul
t in a different |
| 333 return true; | 332 // distance field being generated, so we have to regenerate in those cas
es |
| 333 SkScalar newMaxScale = viewMatrix.getMaxScale(); |
| 334 SkScalar oldMaxScale = blob.fViewMatrix.getMaxScale(); |
| 335 SkScalar scaleAdjust = newMaxScale / oldMaxScale; |
| 336 if (scaleAdjust < blob.fMaxMinScale || scaleAdjust > blob.fMinMaxScale)
{ |
| 337 return true; |
| 338 } |
| 339 |
| 340 (*outTransX) = x - blob.fX; |
| 341 (*outTransY) = y - blob.fY; |
| 334 } | 342 } |
| 335 | 343 |
| 336 return false; | 344 return false; |
| 337 } | 345 } |
| 338 | 346 |
| 339 | 347 |
| 340 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, | 348 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, |
| 341 const SkPaint& skPaint, | 349 const SkPaint& skPaint, |
| 342 const SkMatrix* viewMatrix, | 350 const SkMatrix* viewMatrix, |
| 343 bool noGamma) { | 351 bool noGamma) { |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 496 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; | 504 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; |
| 497 | 505 |
| 498 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; | 506 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; |
| 499 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; | 507 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; |
| 500 } | 508 } |
| 501 | 509 |
| 502 if (this->canDrawAsDistanceFields(runPaint, viewMatrix)) { | 510 if (this->canDrawAsDistanceFields(runPaint, viewMatrix)) { |
| 503 cacheBlob->setHasDistanceField(); | 511 cacheBlob->setHasDistanceField(); |
| 504 SkPaint dfPaint = runPaint; | 512 SkPaint dfPaint = runPaint; |
| 505 SkScalar textRatio; | 513 SkScalar textRatio; |
| 506 this->initDistanceFieldPaint(&dfPaint, &textRatio, viewMatrix); | 514 this->initDistanceFieldPaint(cacheBlob, &dfPaint, &textRatio, viewMa
trix); |
| 507 Run& runIdx = cacheBlob->fRuns[run]; | 515 Run& runIdx = cacheBlob->fRuns[run]; |
| 508 PerSubRunInfo& subRun = runIdx.fSubRunInfo.back(); | 516 PerSubRunInfo& subRun = runIdx.fSubRunInfo.back(); |
| 509 subRun.fUseLCDText = runPaint.isLCDRenderText(); | 517 subRun.fUseLCDText = runPaint.isLCDRenderText(); |
| 510 subRun.fDrawAsDistanceFields = true; | 518 subRun.fDrawAsDistanceFields = true; |
| 511 | 519 |
| 512 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], dfPai
nt, NULL, true); | 520 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], dfPai
nt, NULL, true); |
| 513 | 521 |
| 514 SkTDArray<char> fallbackTxt; | 522 SkTDArray<char> fallbackTxt; |
| 515 SkTDArray<SkScalar> fallbackPos; | 523 SkTDArray<SkScalar> fallbackPos; |
| 516 SkPoint dfOffset; | 524 SkPoint dfOffset; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 SkGlyphCache::AttachCache(cache); | 582 SkGlyphCache::AttachCache(cache); |
| 575 } | 583 } |
| 576 | 584 |
| 577 if (drawFilter) { | 585 if (drawFilter) { |
| 578 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. | 586 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. |
| 579 runPaint = skPaint; | 587 runPaint = skPaint; |
| 580 } | 588 } |
| 581 } | 589 } |
| 582 } | 590 } |
| 583 | 591 |
| 584 inline void GrAtlasTextContext::initDistanceFieldPaint(SkPaint* skPaint, SkScala
r* textRatio, | 592 inline void GrAtlasTextContext::initDistanceFieldPaint(BitmapTextBlob* blob, |
| 593 SkPaint* skPaint, |
| 594 SkScalar* textRatio, |
| 585 const SkMatrix& viewMatri
x) { | 595 const SkMatrix& viewMatri
x) { |
| 586 // getMaxScale doesn't support perspective, so neither do we at the moment | 596 // getMaxScale doesn't support perspective, so neither do we at the moment |
| 587 SkASSERT(!viewMatrix.hasPerspective()); | 597 SkASSERT(!viewMatrix.hasPerspective()); |
| 588 SkScalar maxScale = viewMatrix.getMaxScale(); | 598 SkScalar maxScale = viewMatrix.getMaxScale(); |
| 589 SkScalar textSize = skPaint->getTextSize(); | 599 SkScalar textSize = skPaint->getTextSize(); |
| 590 SkScalar scaledTextSize = textSize; | 600 SkScalar scaledTextSize = textSize; |
| 591 // if we have non-unity scale, we need to choose our base text size | 601 // if we have non-unity scale, we need to choose our base text size |
| 592 // based on the SkPaint's text size multiplied by the max scale factor | 602 // based on the SkPaint's text size multiplied by the max scale factor |
| 593 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? | 603 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? |
| 594 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { | 604 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { |
| 595 scaledTextSize *= maxScale; | 605 scaledTextSize *= maxScale; |
| 596 } | 606 } |
| 597 | 607 |
| 608 // We have three sizes of distance field text, and within each size 'bucket'
there is a floor |
| 609 // and ceiling. A scale outside of this range would require regenerating th
e distance fields |
| 610 SkScalar dfMaskScaleFloor; |
| 611 SkScalar dfMaskScaleCeil; |
| 598 if (scaledTextSize <= kSmallDFFontLimit) { | 612 if (scaledTextSize <= kSmallDFFontLimit) { |
| 613 dfMaskScaleFloor = kMinDFFontSize; |
| 614 dfMaskScaleCeil = kMediumDFFontLimit; |
| 599 *textRatio = textSize / kSmallDFFontSize; | 615 *textRatio = textSize / kSmallDFFontSize; |
| 600 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize)); | 616 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize)); |
| 601 } else if (scaledTextSize <= kMediumDFFontLimit) { | 617 } else if (scaledTextSize <= kMediumDFFontLimit) { |
| 618 dfMaskScaleFloor = kMediumDFFontLimit; |
| 619 dfMaskScaleCeil = kLargeDFFontSize; |
| 602 *textRatio = textSize / kMediumDFFontSize; | 620 *textRatio = textSize / kMediumDFFontSize; |
| 603 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize)); | 621 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize)); |
| 604 } else { | 622 } else { |
| 623 dfMaskScaleFloor = kLargeDFFontSize; |
| 624 dfMaskScaleCeil = 2 * kLargeDFFontSize; |
| 605 *textRatio = textSize / kLargeDFFontSize; | 625 *textRatio = textSize / kLargeDFFontSize; |
| 606 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize)); | 626 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize)); |
| 607 } | 627 } |
| 608 | 628 |
| 629 // Because there can be multiple runs in the blob, we want the overall maxMi
nScale, and |
| 630 // minMaxScale to make regeneration decisions. Specifically, we want the ma
ximum minimum scale |
| 631 // we can tolerate before we'd drop to a lower mip size, and the minimum max
imum scale we can |
| 632 // tolerate before we'd have to move to a large mip size. When we actually
test these values |
| 633 // we look at the delta in scale between the new viewmatrix and the old view
matrix, and test |
| 634 // against these values to decide if we can reuse or not(ie, will a given sc
ale change our mip |
| 635 // level) |
| 636 blob->fMaxMinScale = SkMaxScalar(dfMaskScaleFloor / scaledTextSize, blob->fM
axMinScale); |
| 637 blob->fMinMaxScale = SkMinScalar(dfMaskScaleCeil / scaledTextSize, blob->fMi
nMaxScale); |
| 638 |
| 609 skPaint->setLCDRenderText(false); | 639 skPaint->setLCDRenderText(false); |
| 610 skPaint->setAutohinted(false); | 640 skPaint->setAutohinted(false); |
| 611 skPaint->setHinting(SkPaint::kNormal_Hinting); | 641 skPaint->setHinting(SkPaint::kNormal_Hinting); |
| 612 skPaint->setSubpixelText(true); | 642 skPaint->setSubpixelText(true); |
| 613 } | 643 } |
| 614 | 644 |
| 615 inline void GrAtlasTextContext::fallbackDrawPosText(BitmapTextBlob* blob, | 645 inline void GrAtlasTextContext::fallbackDrawPosText(BitmapTextBlob* blob, |
| 616 int runIndex, | 646 int runIndex, |
| 617 GrRenderTarget* rt, const Gr
Clip& clip, | 647 GrRenderTarget* rt, const Gr
Clip& clip, |
| 618 const GrPaint& paint, | 648 const GrPaint& paint, |
| (...skipping 19 matching lines...) Expand all Loading... |
| 638 SkGlyphCache::AttachCache(cache); | 668 SkGlyphCache::AttachCache(cache); |
| 639 } | 669 } |
| 640 | 670 |
| 641 inline GrAtlasTextContext::BitmapTextBlob* | 671 inline GrAtlasTextContext::BitmapTextBlob* |
| 642 GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, | 672 GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, |
| 643 const SkMatrix& viewMatrix, SkGlyphCache** cache
, | 673 const SkMatrix& viewMatrix, SkGlyphCache** cache
, |
| 644 SkPaint* dfPaint, SkScalar* textRatio) { | 674 SkPaint* dfPaint, SkScalar* textRatio) { |
| 645 BitmapTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); | 675 BitmapTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); |
| 646 | 676 |
| 647 *dfPaint = origPaint; | 677 *dfPaint = origPaint; |
| 648 this->initDistanceFieldPaint(dfPaint, textRatio, viewMatrix); | 678 this->initDistanceFieldPaint(blob, dfPaint, textRatio, viewMatrix); |
| 649 blob->fViewMatrix = viewMatrix; | 679 blob->fViewMatrix = viewMatrix; |
| 650 Run& run = blob->fRuns[0]; | 680 Run& run = blob->fRuns[0]; |
| 651 PerSubRunInfo& subRun = run.fSubRunInfo.back(); | 681 PerSubRunInfo& subRun = run.fSubRunInfo.back(); |
| 652 subRun.fUseLCDText = origPaint.isLCDRenderText(); | 682 subRun.fUseLCDText = origPaint.isLCDRenderText(); |
| 653 subRun.fDrawAsDistanceFields = true; | 683 subRun.fDrawAsDistanceFields = true; |
| 654 | 684 |
| 655 *cache = this->setupCache(&blob->fRuns[0], *dfPaint, NULL, true); | 685 *cache = this->setupCache(&blob->fRuns[0], *dfPaint, NULL, true); |
| 656 return blob; | 686 return blob; |
| 657 } | 687 } |
| 658 | 688 |
| (...skipping 1458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2117 pipelineBuilder.setFromPaint(grPaint, rt, clip); | 2147 pipelineBuilder.setFromPaint(grPaint, rt, clip); |
| 2118 | 2148 |
| 2119 GrColor color = grPaint.getColor(); | 2149 GrColor color = grPaint.getColor(); |
| 2120 for (int run = 0; run < cacheBlob->fRunCount; run++) { | 2150 for (int run = 0; run < cacheBlob->fRunCount; run++) { |
| 2121 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, 0, 0, sk
Paint); | 2151 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, 0, 0, sk
Paint); |
| 2122 } | 2152 } |
| 2123 | 2153 |
| 2124 // Now flush big glyphs | 2154 // Now flush big glyphs |
| 2125 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); | 2155 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); |
| 2126 } | 2156 } |
| OLD | NEW |