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 |