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