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 |