| 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 "GrBatchFontCache.h" | |
| 10 #include "GrBatchFlushState.h" | |
| 11 #include "GrBatchTest.h" | |
| 12 #include "GrBlurUtils.h" | 9 #include "GrBlurUtils.h" |
| 13 #include "GrDefaultGeoProcFactory.h" | |
| 14 #include "GrDrawContext.h" | 10 #include "GrDrawContext.h" |
| 15 #include "GrDrawTarget.h" | 11 #include "GrDrawTarget.h" |
| 16 #include "GrFontScaler.h" | 12 #include "GrFontScaler.h" |
| 17 #include "GrResourceProvider.h" | |
| 18 #include "GrStrokeInfo.h" | 13 #include "GrStrokeInfo.h" |
| 19 #include "GrTextBlobCache.h" | 14 #include "GrTextBlobCache.h" |
| 20 #include "GrTexturePriv.h" | 15 #include "GrTexturePriv.h" |
| 21 #include "GrVertexBuffer.h" | 16 #include "GrVertexBuffer.h" |
| 22 | 17 |
| 23 #include "SkAutoKern.h" | 18 #include "SkAutoKern.h" |
| 24 #include "SkColorPriv.h" | 19 #include "SkColorPriv.h" |
| 25 #include "SkColorFilter.h" | 20 #include "SkColorFilter.h" |
| 26 #include "SkDistanceFieldGen.h" | 21 #include "SkDistanceFieldGen.h" |
| 27 #include "SkDraw.h" | 22 #include "SkDraw.h" |
| 28 #include "SkDrawFilter.h" | 23 #include "SkDrawFilter.h" |
| 29 #include "SkDrawProcs.h" | 24 #include "SkDrawProcs.h" |
| 30 #include "SkFindAndPlaceGlyph.h" | 25 #include "SkFindAndPlaceGlyph.h" |
| 31 #include "SkGlyphCache.h" | 26 #include "SkGlyphCache.h" |
| 32 #include "SkGpuDevice.h" | 27 #include "SkGpuDevice.h" |
| 33 #include "SkGrPriv.h" | 28 #include "SkGrPriv.h" |
| 34 #include "SkPath.h" | 29 #include "SkPath.h" |
| 35 #include "SkRTConf.h" | 30 #include "SkRTConf.h" |
| 36 #include "SkStrokeRec.h" | 31 #include "SkStrokeRec.h" |
| 37 #include "SkTextBlob.h" | 32 #include "SkTextBlob.h" |
| 38 #include "SkTextMapStateProc.h" | 33 #include "SkTextMapStateProc.h" |
| 39 | 34 |
| 40 #include "batches/GrVertexBatch.h" | 35 #include "batches/GrAtlasTextBatch.h" |
| 41 | |
| 42 #include "effects/GrBitmapTextGeoProc.h" | |
| 43 #include "effects/GrDistanceFieldGeoProc.h" | |
| 44 | 36 |
| 45 namespace { | 37 namespace { |
| 46 static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); | |
| 47 | |
| 48 // position + local coord | |
| 49 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); | |
| 50 | |
| 51 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof
(SkIPoint16); | |
| 52 | |
| 53 static const int kMinDFFontSize = 18; | 38 static const int kMinDFFontSize = 18; |
| 54 static const int kSmallDFFontSize = 32; | 39 static const int kSmallDFFontSize = 32; |
| 55 static const int kSmallDFFontLimit = 32; | 40 static const int kSmallDFFontLimit = 32; |
| 56 static const int kMediumDFFontSize = 72; | 41 static const int kMediumDFFontSize = 72; |
| 57 static const int kMediumDFFontLimit = 72; | 42 static const int kMediumDFFontLimit = 72; |
| 58 static const int kLargeDFFontSize = 162; | 43 static const int kLargeDFFontSize = 162; |
| 59 #ifdef SK_BUILD_FOR_ANDROID | 44 #ifdef SK_BUILD_FOR_ANDROID |
| 60 static const int kLargeDFFontLimit = 384; | 45 static const int kLargeDFFontLimit = 384; |
| 61 #else | 46 #else |
| 62 static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; | 47 static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; |
| 63 #endif | 48 #endif |
| 64 | 49 |
| 65 SkDEBUGCODE(static const int kExpectedDistanceAdjustTableSize = 8;) | 50 SkDEBUGCODE(static const int kExpectedDistanceAdjustTableSize = 8;) |
| 66 static const int kDistanceAdjustLumShift = 5; | |
| 67 | |
| 68 static const int kVerticesPerGlyph = 4; | |
| 69 static const int kIndicesPerGlyph = 6; | |
| 70 | |
| 71 static size_t get_vertex_stride(GrMaskFormat maskFormat) { | |
| 72 switch (maskFormat) { | |
| 73 case kA8_GrMaskFormat: | |
| 74 return kGrayTextVASize; | |
| 75 case kARGB_GrMaskFormat: | |
| 76 return kColorTextVASize; | |
| 77 default: | |
| 78 return kLCDTextVASize; | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 static size_t get_vertex_stride_df(GrMaskFormat maskFormat, bool useLCDText) { | |
| 83 SkASSERT(maskFormat == kA8_GrMaskFormat); | |
| 84 if (useLCDText) { | |
| 85 return kLCDTextVASize; | |
| 86 } else { | |
| 87 return kGrayTextVASize; | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { | |
| 92 unsigned r = SkColorGetR(c); | |
| 93 unsigned g = SkColorGetG(c); | |
| 94 unsigned b = SkColorGetB(c); | |
| 95 return GrColorPackRGBA(r, g, b, 0xff); | |
| 96 } | |
| 97 | |
| 98 }; | 51 }; |
| 99 | 52 |
| 100 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps&
surfaceProps) | 53 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps&
surfaceProps) |
| 101 : INHERITED(context, surfaceProps) | 54 : INHERITED(context, surfaceProps) |
| 102 , fDistanceAdjustTable(new DistanceAdjustTable) { | 55 , fDistanceAdjustTable(new DistanceAdjustTable) { |
| 103 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest | 56 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest |
| 104 // vertexStride | 57 // vertexStride |
| 105 static_assert(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >= kLCD
TextVASize, | 58 static_assert(GrAtlasTextBatch::kGrayTextVASize >= GrAtlasTextBatch::kColorT
extVASize && |
| 59 GrAtlasTextBatch::kGrayTextVASize >= GrAtlasTextBatch::kLCDTex
tVASize, |
| 106 "vertex_attribute_changed"); | 60 "vertex_attribute_changed"); |
| 107 fCurrStrike = nullptr; | 61 fCurrStrike = nullptr; |
| 108 fCache = context->getTextBlobCache(); | 62 fCache = context->getTextBlobCache(); |
| 109 } | 63 } |
| 110 | 64 |
| 111 void GrAtlasTextContext::DistanceAdjustTable::buildDistanceAdjustTable() { | 65 void GrAtlasTextContext::DistanceAdjustTable::buildDistanceAdjustTable() { |
| 112 | 66 |
| 113 // This is used for an approximation of the mask gamma hack, used by raster
and bitmap | 67 // This is used for an approximation of the mask gamma hack, used by raster
and bitmap |
| 114 // text. The mask gamma hack is based off of guessing what the blend color i
s going to | 68 // text. The mask gamma hack is based off of guessing what the blend color i
s going to |
| 115 // be, and adjusting the mask so that when run through the linear blend will | 69 // be, and adjusting the mask so that when run through the linear blend will |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 } | 349 } |
| 396 | 350 |
| 397 if (cacheBlob) { | 351 if (cacheBlob) { |
| 398 if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, grPaint.ge
tColor(), blurRec, | 352 if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, grPaint.ge
tColor(), blurRec, |
| 399 viewMatrix, x, y)) { | 353 viewMatrix, x, y)) { |
| 400 // We have to remake the blob because changes may invalidate our mas
ks. | 354 // We have to remake the blob because changes may invalidate our mas
ks. |
| 401 // TODO we could probably get away reuse most of the time if the poi
nter is unique, | 355 // TODO we could probably get away reuse most of the time if the poi
nter is unique, |
| 402 // but we'd have to clear the subrun information | 356 // but we'd have to clear the subrun information |
| 403 fCache->remove(cacheBlob); | 357 fCache->remove(cacheBlob); |
| 404 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, s
kPaint, | 358 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, s
kPaint, |
| 405 kGrayTextVASize))); | 359 GrAtlasTextBatch::kGr
ayTextVASize))); |
| 406 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), vie
wMatrix, | 360 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), vie
wMatrix, |
| 407 blob, x, y, drawFilter, clipRect, rt, clip)
; | 361 blob, x, y, drawFilter, clipRect, rt, clip)
; |
| 408 } else { | 362 } else { |
| 409 // If we can reuse the blob, then make sure we update the blob's vie
wmatrix, and x/y | 363 // If we can reuse the blob, then make sure we update the blob's vie
wmatrix, and x/y |
| 410 // offsets. Note, we offset the vertex bounds right before flushing | 364 // offsets. Note, we offset the vertex bounds right before flushing |
| 411 cacheBlob->fViewMatrix = viewMatrix; | 365 cacheBlob->fViewMatrix = viewMatrix; |
| 412 cacheBlob->fX = x; | 366 cacheBlob->fX = x; |
| 413 cacheBlob->fY = y; | 367 cacheBlob->fY = y; |
| 414 fCache->makeMRU(cacheBlob); | 368 fCache->makeMRU(cacheBlob); |
| 415 #ifdef CACHE_SANITY_CHECK | 369 #ifdef CACHE_SANITY_CHECK |
| 416 { | 370 { |
| 417 int glyphCount = 0; | 371 int glyphCount = 0; |
| 418 int runCount = 0; | 372 int runCount = 0; |
| 419 GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob); | 373 GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob); |
| 420 SkAutoTUnref<GrAtlasTextBlob> sanityBlob(fCache->createBlob(glyp
hCount, runCount, | 374 SkAutoTUnref<GrAtlasTextBlob> sanityBlob(fCache->createBlob(glyp
hCount, runCount, |
| 421 kGra
yTextVASize)); | 375 kGra
yTextVASize)); |
| 422 GrTextBlobCache::SetupCacheBlobKey(sanityBlob, key, blurRec, skP
aint); | 376 GrTextBlobCache::SetupCacheBlobKey(sanityBlob, key, blurRec, skP
aint); |
| 423 this->regenerateTextBlob(sanityBlob, skPaint, grPaint.getColor()
, viewMatrix, | 377 this->regenerateTextBlob(sanityBlob, skPaint, grPaint.getColor()
, viewMatrix, |
| 424 blob, x, y, drawFilter, clipRect, rt, c
lip); | 378 blob, x, y, drawFilter, clipRect, rt, c
lip); |
| 425 GrAtlasTextBlob::AssertEqual(*sanityBlob, *cacheBlob); | 379 GrAtlasTextBlob::AssertEqual(*sanityBlob, *cacheBlob); |
| 426 } | 380 } |
| 427 | 381 |
| 428 #endif | 382 #endif |
| 429 } | 383 } |
| 430 } else { | 384 } else { |
| 431 if (canCache) { | 385 if (canCache) { |
| 432 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, s
kPaint, | 386 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, s
kPaint, |
| 433 kGrayTextVASize))); | 387 GrAtlasTextBatch::kGr
ayTextVASize))); |
| 434 } else { | 388 } else { |
| 435 cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize)); | 389 cacheBlob.reset(fCache->createBlob(blob, GrAtlasTextBatch::kGrayText
VASize)); |
| 436 } | 390 } |
| 437 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat
rix, | 391 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat
rix, |
| 438 blob, x, y, drawFilter, clipRect, rt, clip); | 392 blob, x, y, drawFilter, clipRect, rt, clip); |
| 439 } | 393 } |
| 440 | 394 |
| 441 this->flush(blob, cacheBlob, dc, rt, skPaint, grPaint, drawFilter, | 395 this->flush(blob, cacheBlob, dc, rt, skPaint, grPaint, drawFilter, |
| 442 clip, viewMatrix, clipBounds, x, y, transX, transY); | 396 clip, viewMatrix, clipBounds, x, y, transX, transY); |
| 443 } | 397 } |
| 444 | 398 |
| 445 inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint, | 399 inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint, |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 682 this->internalDrawBMPPosText(blob, runIndex, cache, skPaint, color, viewMatr
ix, | 636 this->internalDrawBMPPosText(blob, runIndex, cache, skPaint, color, viewMatr
ix, |
| 683 fallbackTxt.begin(), fallbackTxt.count(), | 637 fallbackTxt.begin(), fallbackTxt.count(), |
| 684 fallbackPos.begin(), scalarsPerPosition, offset
, clipRect); | 638 fallbackPos.begin(), scalarsPerPosition, offset
, clipRect); |
| 685 SkGlyphCache::AttachCache(cache); | 639 SkGlyphCache::AttachCache(cache); |
| 686 } | 640 } |
| 687 | 641 |
| 688 inline GrAtlasTextBlob* | 642 inline GrAtlasTextBlob* |
| 689 GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, | 643 GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, |
| 690 const SkMatrix& viewMatrix, SkPaint* dfPaint, | 644 const SkMatrix& viewMatrix, SkPaint* dfPaint, |
| 691 SkScalar* textRatio) { | 645 SkScalar* textRatio) { |
| 692 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); | 646 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBatch::
kGrayTextVASize); |
| 693 | 647 |
| 694 *dfPaint = origPaint; | 648 *dfPaint = origPaint; |
| 695 this->initDistanceFieldPaint(blob, dfPaint, textRatio, viewMatrix); | 649 this->initDistanceFieldPaint(blob, dfPaint, textRatio, viewMatrix); |
| 696 blob->fViewMatrix = viewMatrix; | 650 blob->fViewMatrix = viewMatrix; |
| 697 Run& run = blob->fRuns[0]; | 651 Run& run = blob->fRuns[0]; |
| 698 PerSubRunInfo& subRun = run.fSubRunInfo.back(); | 652 PerSubRunInfo& subRun = run.fSubRunInfo.back(); |
| 699 subRun.fUseLCDText = origPaint.isLCDRenderText(); | 653 subRun.fUseLCDText = origPaint.isLCDRenderText(); |
| 700 subRun.fDrawAsDistanceFields = true; | 654 subRun.fDrawAsDistanceFields = true; |
| 701 | 655 |
| 702 return blob; | 656 return blob; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 722 SkTDArray<SkScalar> fallbackPos; | 676 SkTDArray<SkScalar> fallbackPos; |
| 723 SkPoint offset; | 677 SkPoint offset; |
| 724 this->internalDrawDFText(blob, 0, dfPaint, paint.getColor(), viewMatrix,
text, | 678 this->internalDrawDFText(blob, 0, dfPaint, paint.getColor(), viewMatrix,
text, |
| 725 byteLength, x, y, clipRect, textRatio, &fallbac
kTxt, &fallbackPos, | 679 byteLength, x, y, clipRect, textRatio, &fallbac
kTxt, &fallbackPos, |
| 726 &offset, skPaint); | 680 &offset, skPaint); |
| 727 if (fallbackTxt.count()) { | 681 if (fallbackTxt.count()) { |
| 728 this->fallbackDrawPosText(blob, 0, rt, clip, paint.getColor(), skPai
nt, viewMatrix, | 682 this->fallbackDrawPosText(blob, 0, rt, clip, paint.getColor(), skPai
nt, viewMatrix, |
| 729 fallbackTxt, fallbackPos, 2, offset, clipR
ect); | 683 fallbackTxt, fallbackPos, 2, offset, clipR
ect); |
| 730 } | 684 } |
| 731 } else { | 685 } else { |
| 732 blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); | 686 blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBatch::kGrayTextVASi
ze); |
| 733 blob->fViewMatrix = viewMatrix; | 687 blob->fViewMatrix = viewMatrix; |
| 734 | 688 |
| 735 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMa
trix, false); | 689 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMa
trix, false); |
| 736 this->internalDrawBMPText(blob, 0, cache, skPaint, paint.getColor(), vie
wMatrix, text, | 690 this->internalDrawBMPText(blob, 0, cache, skPaint, paint.getColor(), vie
wMatrix, text, |
| 737 byteLength, x, y, clipRect); | 691 byteLength, x, y, clipRect); |
| 738 SkGlyphCache::AttachCache(cache); | 692 SkGlyphCache::AttachCache(cache); |
| 739 } | 693 } |
| 740 return blob; | 694 return blob; |
| 741 } | 695 } |
| 742 | 696 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 762 SkTDArray<SkScalar> fallbackPos; | 716 SkTDArray<SkScalar> fallbackPos; |
| 763 this->internalDrawDFPosText(blob, 0, dfPaint, paint.getColor(), viewMatr
ix, text, | 717 this->internalDrawDFPosText(blob, 0, dfPaint, paint.getColor(), viewMatr
ix, text, |
| 764 byteLength, pos, scalarsPerPosition, offset,
clipRect, | 718 byteLength, pos, scalarsPerPosition, offset,
clipRect, |
| 765 textRatio, &fallbackTxt, &fallbackPos); | 719 textRatio, &fallbackTxt, &fallbackPos); |
| 766 if (fallbackTxt.count()) { | 720 if (fallbackTxt.count()) { |
| 767 this->fallbackDrawPosText(blob, 0, rt, clip, paint.getColor(), skPai
nt, viewMatrix, | 721 this->fallbackDrawPosText(blob, 0, rt, clip, paint.getColor(), skPai
nt, viewMatrix, |
| 768 fallbackTxt, fallbackPos, scalarsPerPositi
on, offset, | 722 fallbackTxt, fallbackPos, scalarsPerPositi
on, offset, |
| 769 clipRect); | 723 clipRect); |
| 770 } | 724 } |
| 771 } else { | 725 } else { |
| 772 blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); | 726 blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBatch::kGrayTextVASi
ze); |
| 773 blob->fViewMatrix = viewMatrix; | 727 blob->fViewMatrix = viewMatrix; |
| 774 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMa
trix, false); | 728 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMa
trix, false); |
| 775 this->internalDrawBMPPosText(blob, 0, cache, skPaint, paint.getColor(),
viewMatrix, text, | 729 this->internalDrawBMPPosText(blob, 0, cache, skPaint, paint.getColor(),
viewMatrix, text, |
| 776 byteLength, pos, scalarsPerPosition, offset
, clipRect); | 730 byteLength, pos, scalarsPerPosition, offset
, clipRect); |
| 777 SkGlyphCache::AttachCache(cache); | 731 SkGlyphCache::AttachCache(cache); |
| 778 } | 732 } |
| 779 return blob; | 733 return blob; |
| 780 } | 734 } |
| 781 | 735 |
| 782 void GrAtlasTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* rt, | 736 void GrAtlasTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* rt, |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1083 PerSubRunInfo* subRun = &run.fSubRunInfo.back(); | 1037 PerSubRunInfo* subRun = &run.fSubRunInfo.back(); |
| 1084 if (run.fInitialized && subRun->fMaskFormat != format) { | 1038 if (run.fInitialized && subRun->fMaskFormat != format) { |
| 1085 subRun = &run.push_back(); | 1039 subRun = &run.push_back(); |
| 1086 subRun->fStrike.reset(SkRef(fCurrStrike)); | 1040 subRun->fStrike.reset(SkRef(fCurrStrike)); |
| 1087 } else if (!run.fInitialized) { | 1041 } else if (!run.fInitialized) { |
| 1088 subRun->fStrike.reset(SkRef(fCurrStrike)); | 1042 subRun->fStrike.reset(SkRef(fCurrStrike)); |
| 1089 } | 1043 } |
| 1090 | 1044 |
| 1091 run.fInitialized = true; | 1045 run.fInitialized = true; |
| 1092 | 1046 |
| 1093 size_t vertexStride = get_vertex_stride(format); | 1047 size_t vertexStride = GrAtlasTextBatch::GetVertexStride(format); |
| 1094 | 1048 |
| 1095 SkRect r; | 1049 SkRect r; |
| 1096 r.fLeft = SkIntToScalar(x); | 1050 r.fLeft = SkIntToScalar(x); |
| 1097 r.fTop = SkIntToScalar(y); | 1051 r.fTop = SkIntToScalar(y); |
| 1098 r.fRight = r.fLeft + SkIntToScalar(width); | 1052 r.fRight = r.fLeft + SkIntToScalar(width); |
| 1099 r.fBottom = r.fTop + SkIntToScalar(height); | 1053 r.fBottom = r.fTop + SkIntToScalar(height); |
| 1100 subRun->fMaskFormat = format; | 1054 subRun->fMaskFormat = format; |
| 1101 this->appendGlyphCommon(blob, &run, subRun, r, color, vertexStride, kA8_GrMa
skFormat == format, | 1055 this->appendGlyphCommon(blob, &run, subRun, r, color, vertexStride, kA8_GrMa
skFormat == format, |
| 1102 glyph); | 1056 glyph); |
| 1103 } | 1057 } |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1161 } | 1115 } |
| 1162 | 1116 |
| 1163 PerSubRunInfo* subRun = &run.fSubRunInfo.back(); | 1117 PerSubRunInfo* subRun = &run.fSubRunInfo.back(); |
| 1164 if (!run.fInitialized) { | 1118 if (!run.fInitialized) { |
| 1165 subRun->fStrike.reset(SkRef(fCurrStrike)); | 1119 subRun->fStrike.reset(SkRef(fCurrStrike)); |
| 1166 } | 1120 } |
| 1167 run.fInitialized = true; | 1121 run.fInitialized = true; |
| 1168 SkASSERT(glyph->fMaskFormat == kA8_GrMaskFormat); | 1122 SkASSERT(glyph->fMaskFormat == kA8_GrMaskFormat); |
| 1169 subRun->fMaskFormat = kA8_GrMaskFormat; | 1123 subRun->fMaskFormat = kA8_GrMaskFormat; |
| 1170 | 1124 |
| 1171 size_t vertexStride = get_vertex_stride_df(kA8_GrMaskFormat, subRun->fUseLCD
Text); | 1125 size_t vertexStride = GrAtlasTextBatch::GetVertexStrideDf(kA8_GrMaskFormat, |
| 1126 subRun->fUseLCDTex
t); |
| 1172 | 1127 |
| 1173 bool useColorVerts = !subRun->fUseLCDText; | 1128 bool useColorVerts = !subRun->fUseLCDText; |
| 1174 this->appendGlyphCommon(blob, &run, subRun, glyphRect, color, vertexStride,
useColorVerts, | 1129 this->appendGlyphCommon(blob, &run, subRun, glyphRect, color, vertexStride,
useColorVerts, |
| 1175 glyph); | 1130 glyph); |
| 1176 return true; | 1131 return true; |
| 1177 } | 1132 } |
| 1178 | 1133 |
| 1179 inline void GrAtlasTextContext::appendGlyphPath(GrAtlasTextBlob* blob, GrGlyph*
glyph, | 1134 inline void GrAtlasTextContext::appendGlyphPath(GrAtlasTextBlob* blob, GrGlyph*
glyph, |
| 1180 GrFontScaler* scaler, const SkGl
yph& skGlyph, | 1135 GrFontScaler* scaler, const SkGl
yph& skGlyph, |
| 1181 SkScalar x, SkScalar y, SkScalar
scale, | 1136 SkScalar x, SkScalar y, SkScalar
scale, |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1244 position = reinterpret_cast<SkPoint*>(vertex); | 1199 position = reinterpret_cast<SkPoint*>(vertex); |
| 1245 position->set(positions.fRight, positions.fBottom); | 1200 position->set(positions.fRight, positions.fBottom); |
| 1246 vertex += vertexStride; | 1201 vertex += vertexStride; |
| 1247 | 1202 |
| 1248 // V3 | 1203 // V3 |
| 1249 position = reinterpret_cast<SkPoint*>(vertex); | 1204 position = reinterpret_cast<SkPoint*>(vertex); |
| 1250 position->set(positions.fRight, positions.fTop); | 1205 position->set(positions.fRight, positions.fTop); |
| 1251 } | 1206 } |
| 1252 | 1207 |
| 1253 subRun->fGlyphEndIndex++; | 1208 subRun->fGlyphEndIndex++; |
| 1254 subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph; | 1209 subRun->fVertexEndIndex += vertexStride * GrAtlasTextBatch::kVerticesPerGlyp
h; |
| 1255 } | 1210 } |
| 1256 | 1211 |
| 1257 class TextBatch : public GrVertexBatch { | |
| 1258 public: | |
| 1259 DEFINE_BATCH_CLASS_ID | |
| 1260 | |
| 1261 typedef GrAtlasTextContext::DistanceAdjustTable DistanceAdjustTable; | |
| 1262 typedef GrAtlasTextBlob Blob; | |
| 1263 typedef Blob::Run Run; | |
| 1264 typedef Run::SubRunInfo TextInfo; | |
| 1265 struct Geometry { | |
| 1266 Blob* fBlob; | |
| 1267 int fRun; | |
| 1268 int fSubRun; | |
| 1269 GrColor fColor; | |
| 1270 SkScalar fTransX; | |
| 1271 SkScalar fTransY; | |
| 1272 }; | |
| 1273 | |
| 1274 static TextBatch* CreateBitmap(GrMaskFormat maskFormat, int glyphCount, | |
| 1275 GrBatchFontCache* fontCache) { | |
| 1276 TextBatch* batch = new TextBatch; | |
| 1277 | |
| 1278 batch->fFontCache = fontCache; | |
| 1279 switch (maskFormat) { | |
| 1280 case kA8_GrMaskFormat: | |
| 1281 batch->fMaskType = kGrayscaleCoverageMask_MaskType; | |
| 1282 break; | |
| 1283 case kA565_GrMaskFormat: | |
| 1284 batch->fMaskType = kLCDCoverageMask_MaskType; | |
| 1285 break; | |
| 1286 case kARGB_GrMaskFormat: | |
| 1287 batch->fMaskType = kColorBitmapMask_MaskType; | |
| 1288 break; | |
| 1289 } | |
| 1290 batch->fBatch.fNumGlyphs = glyphCount; | |
| 1291 batch->fGeoCount = 1; | |
| 1292 batch->fFilteredColor = 0; | |
| 1293 batch->fFontCache = fontCache; | |
| 1294 batch->fUseBGR = false; | |
| 1295 return batch; | |
| 1296 } | |
| 1297 | |
| 1298 static TextBatch* CreateDistanceField(int glyphCount, GrBatchFontCache* font
Cache, | |
| 1299 const DistanceAdjustTable* distanceAdj
ustTable, | |
| 1300 SkColor filteredColor, bool isLCD, | |
| 1301 bool useBGR) { | |
| 1302 TextBatch* batch = new TextBatch; | |
| 1303 | |
| 1304 batch->fFontCache = fontCache; | |
| 1305 batch->fMaskType = isLCD ? kLCDDistanceField_MaskType : kGrayscaleDistan
ceField_MaskType; | |
| 1306 batch->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable)); | |
| 1307 batch->fFilteredColor = filteredColor; | |
| 1308 batch->fUseBGR = useBGR; | |
| 1309 batch->fBatch.fNumGlyphs = glyphCount; | |
| 1310 batch->fGeoCount = 1; | |
| 1311 return batch; | |
| 1312 } | |
| 1313 | |
| 1314 // to avoid even the initial copy of the struct, we have a getter for the fi
rst item which | |
| 1315 // is used to seed the batch with its initial geometry. After seeding, the
client should call | |
| 1316 // init() so the Batch can initialize itself | |
| 1317 Geometry& geometry() { return fGeoData[0]; } | |
| 1318 | |
| 1319 void init() { | |
| 1320 const Geometry& geo = fGeoData[0]; | |
| 1321 fBatch.fColor = geo.fColor; | |
| 1322 fBatch.fViewMatrix = geo.fBlob->fViewMatrix; | |
| 1323 | |
| 1324 // We don't yet position distance field text on the cpu, so we have to m
ap the vertex bounds | |
| 1325 // into device space | |
| 1326 const Run& run = geo.fBlob->fRuns[geo.fRun]; | |
| 1327 if (run.fSubRunInfo[geo.fSubRun].fDrawAsDistanceFields) { | |
| 1328 SkRect bounds = run.fVertexBounds; | |
| 1329 fBatch.fViewMatrix.mapRect(&bounds); | |
| 1330 this->setBounds(bounds); | |
| 1331 } else { | |
| 1332 this->setBounds(run.fVertexBounds); | |
| 1333 } | |
| 1334 } | |
| 1335 | |
| 1336 const char* name() const override { return "TextBatch"; } | |
| 1337 | |
| 1338 SkString dumpInfo() const override { | |
| 1339 SkString str; | |
| 1340 | |
| 1341 for (int i = 0; i < fGeoCount; ++i) { | |
| 1342 str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f Runs: %d\n", | |
| 1343 i, | |
| 1344 fGeoData[i].fColor, | |
| 1345 fGeoData[i].fTransX, | |
| 1346 fGeoData[i].fTransY, | |
| 1347 fGeoData[i].fBlob->fRunCount); | |
| 1348 } | |
| 1349 | |
| 1350 str.append(INHERITED::dumpInfo()); | |
| 1351 return str; | |
| 1352 } | |
| 1353 | |
| 1354 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | |
| 1355 if (kColorBitmapMask_MaskType == fMaskType) { | |
| 1356 out->setUnknownFourComponents(); | |
| 1357 } else { | |
| 1358 out->setKnownFourComponents(fBatch.fColor); | |
| 1359 } | |
| 1360 } | |
| 1361 | |
| 1362 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { | |
| 1363 switch (fMaskType) { | |
| 1364 case kGrayscaleDistanceField_MaskType: | |
| 1365 case kGrayscaleCoverageMask_MaskType: | |
| 1366 out->setUnknownSingleComponent(); | |
| 1367 break; | |
| 1368 case kLCDCoverageMask_MaskType: | |
| 1369 case kLCDDistanceField_MaskType: | |
| 1370 out->setUnknownOpaqueFourComponents(); | |
| 1371 out->setUsingLCDCoverage(); | |
| 1372 break; | |
| 1373 case kColorBitmapMask_MaskType: | |
| 1374 out->setKnownSingleComponent(0xff); | |
| 1375 } | |
| 1376 } | |
| 1377 | |
| 1378 private: | |
| 1379 void initBatchTracker(const GrPipelineOptimizations& opt) override { | |
| 1380 // Handle any color overrides | |
| 1381 if (!opt.readsColor()) { | |
| 1382 fGeoData[0].fColor = GrColor_ILLEGAL; | |
| 1383 } | |
| 1384 opt.getOverrideColorIfSet(&fGeoData[0].fColor); | |
| 1385 | |
| 1386 // setup batch properties | |
| 1387 fBatch.fColorIgnored = !opt.readsColor(); | |
| 1388 fBatch.fColor = fGeoData[0].fColor; | |
| 1389 fBatch.fUsesLocalCoords = opt.readsLocalCoords(); | |
| 1390 fBatch.fCoverageIgnored = !opt.readsCoverage(); | |
| 1391 } | |
| 1392 | |
| 1393 struct FlushInfo { | |
| 1394 SkAutoTUnref<const GrVertexBuffer> fVertexBuffer; | |
| 1395 SkAutoTUnref<const GrIndexBuffer> fIndexBuffer; | |
| 1396 int fGlyphsToFlush; | |
| 1397 int fVertexOffset; | |
| 1398 }; | |
| 1399 | |
| 1400 void onPrepareDraws(Target* target) override { | |
| 1401 // if we have RGB, then we won't have any SkShaders so no need to use a
localmatrix. | |
| 1402 // TODO actually only invert if we don't have RGBA | |
| 1403 SkMatrix localMatrix; | |
| 1404 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix))
{ | |
| 1405 SkDebugf("Cannot invert viewmatrix\n"); | |
| 1406 return; | |
| 1407 } | |
| 1408 | |
| 1409 GrTexture* texture = fFontCache->getTexture(this->maskFormat()); | |
| 1410 if (!texture) { | |
| 1411 SkDebugf("Could not allocate backing texture for atlas\n"); | |
| 1412 return; | |
| 1413 } | |
| 1414 | |
| 1415 bool usesDistanceFields = this->usesDistanceFields(); | |
| 1416 GrMaskFormat maskFormat = this->maskFormat(); | |
| 1417 bool isLCD = this->isLCD(); | |
| 1418 | |
| 1419 SkAutoTUnref<const GrGeometryProcessor> gp; | |
| 1420 if (usesDistanceFields) { | |
| 1421 gp.reset(this->setupDfProcessor(this->viewMatrix(), fFilteredColor,
this->color(), | |
| 1422 texture)); | |
| 1423 } else { | |
| 1424 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::k
None_FilterMode); | |
| 1425 gp.reset(GrBitmapTextGeoProc::Create(this->color(), | |
| 1426 texture, | |
| 1427 params, | |
| 1428 maskFormat, | |
| 1429 localMatrix, | |
| 1430 this->usesLocalCoords())); | |
| 1431 } | |
| 1432 | |
| 1433 FlushInfo flushInfo; | |
| 1434 flushInfo.fGlyphsToFlush = 0; | |
| 1435 size_t vertexStride = gp->getVertexStride(); | |
| 1436 SkASSERT(vertexStride == (usesDistanceFields ? | |
| 1437 get_vertex_stride_df(maskFormat, isLCD) : | |
| 1438 get_vertex_stride(maskFormat))); | |
| 1439 | |
| 1440 target->initDraw(gp, this->pipeline()); | |
| 1441 | |
| 1442 int glyphCount = this->numGlyphs(); | |
| 1443 const GrVertexBuffer* vertexBuffer; | |
| 1444 | |
| 1445 void* vertices = target->makeVertexSpace(vertexStride, | |
| 1446 glyphCount * kVerticesPerGlyph, | |
| 1447 &vertexBuffer, | |
| 1448 &flushInfo.fVertexOffset); | |
| 1449 flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer)); | |
| 1450 flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuf
fer()); | |
| 1451 if (!vertices || !flushInfo.fVertexBuffer) { | |
| 1452 SkDebugf("Could not allocate vertices\n"); | |
| 1453 return; | |
| 1454 } | |
| 1455 | |
| 1456 unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices); | |
| 1457 | |
| 1458 // We cache some values to avoid going to the glyphcache for the same fo
ntScaler twice | |
| 1459 // in a row | |
| 1460 const SkDescriptor* desc = nullptr; | |
| 1461 SkGlyphCache* cache = nullptr; | |
| 1462 GrFontScaler* scaler = nullptr; | |
| 1463 SkTypeface* typeface = nullptr; | |
| 1464 | |
| 1465 for (int i = 0; i < fGeoCount; i++) { | |
| 1466 Geometry& args = fGeoData[i]; | |
| 1467 Blob* blob = args.fBlob; | |
| 1468 Run& run = blob->fRuns[args.fRun]; | |
| 1469 TextInfo& info = run.fSubRunInfo[args.fSubRun]; | |
| 1470 | |
| 1471 uint64_t currentAtlasGen = fFontCache->atlasGeneration(maskFormat); | |
| 1472 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas
Gen || | |
| 1473 info.fStrike->isAbandoned(); | |
| 1474 bool regenerateColors; | |
| 1475 if (usesDistanceFields) { | |
| 1476 regenerateColors = !isLCD && run.fColor != args.fColor; | |
| 1477 } else { | |
| 1478 regenerateColors = kA8_GrMaskFormat == maskFormat && run.fColor
!= args.fColor; | |
| 1479 } | |
| 1480 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.
f; | |
| 1481 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; | |
| 1482 | |
| 1483 // We regenerate both texture coords and colors in the blob itself,
and update the | |
| 1484 // atlas generation. If we don't end up purging any unused plots, w
e can avoid | |
| 1485 // regenerating the coords. We could take a finer grained approach
to updating texture | |
| 1486 // coords but its not clear if the extra bookkeeping would offset an
y gains. | |
| 1487 // To avoid looping over the glyphs twice, we do one loop and condit
ionally update color | |
| 1488 // or coords as needed. One final note, if we have to break a run f
or an atlas eviction | |
| 1489 // then we can't really trust the atlas has all of the correct data.
Atlas evictions | |
| 1490 // should be pretty rare, so we just always regenerate in those case
s | |
| 1491 if (regenerateTextureCoords || regenerateColors || regeneratePositio
ns) { | |
| 1492 // first regenerate texture coordinates / colors if need be | |
| 1493 bool brokenRun = false; | |
| 1494 | |
| 1495 // Because the GrBatchFontCache may evict the strike a blob depe
nds on using for | |
| 1496 // generating its texture coords, we have to track whether or no
t the strike has | |
| 1497 // been abandoned. If it hasn't been abandoned, then we can use
the GrGlyph*s as is | |
| 1498 // otherwise we have to get the new strike, and use that to get
the correct glyphs. | |
| 1499 // Because we do not have the packed ids, and thus can't look up
our glyphs in the | |
| 1500 // new strike, we instead keep our ref to the old strike and use
the packed ids from | |
| 1501 // it. These ids will still be valid as long as we hold the ref
. When we are done | |
| 1502 // updating our cache of the GrGlyph*s, we drop our ref on the o
ld strike | |
| 1503 bool regenerateGlyphs = false; | |
| 1504 GrBatchTextStrike* strike = nullptr; | |
| 1505 if (regenerateTextureCoords) { | |
| 1506 info.fBulkUseToken.reset(); | |
| 1507 | |
| 1508 // We can reuse if we have a valid strike and our descriptor
s / typeface are the | |
| 1509 // same. The override descriptor is only for the non distan
ce field text within | |
| 1510 // a run | |
| 1511 const SkDescriptor* newDesc = (run.fOverrideDescriptor && !u
sesDistanceFields) ? | |
| 1512 run.fOverrideDescriptor->getDe
sc() : | |
| 1513 run.fDescriptor.getDesc(); | |
| 1514 if (!cache || !SkTypeface::Equal(typeface, run.fTypeface) || | |
| 1515 !(desc->equals(*newDesc))) { | |
| 1516 if (cache) { | |
| 1517 SkGlyphCache::AttachCache(cache); | |
| 1518 } | |
| 1519 desc = newDesc; | |
| 1520 cache = SkGlyphCache::DetachCache(run.fTypeface, desc); | |
| 1521 scaler = GrTextContext::GetGrFontScaler(cache); | |
| 1522 strike = info.fStrike; | |
| 1523 typeface = run.fTypeface; | |
| 1524 } | |
| 1525 | |
| 1526 if (info.fStrike->isAbandoned()) { | |
| 1527 regenerateGlyphs = true; | |
| 1528 strike = fFontCache->getStrike(scaler); | |
| 1529 } else { | |
| 1530 strike = info.fStrike; | |
| 1531 } | |
| 1532 } | |
| 1533 | |
| 1534 for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) { | |
| 1535 if (regenerateTextureCoords) { | |
| 1536 size_t glyphOffset = glyphIdx + info.fGlyphStartIndex; | |
| 1537 | |
| 1538 GrGlyph* glyph = blob->fGlyphs[glyphOffset]; | |
| 1539 GrGlyph::PackedID id = glyph->fPackedID; | |
| 1540 const SkGlyph& skGlyph = scaler->grToSkGlyph(id); | |
| 1541 if (regenerateGlyphs) { | |
| 1542 // Get the id from the old glyph, and use the new st
rike to lookup | |
| 1543 // the glyph. | |
| 1544 blob->fGlyphs[glyphOffset] = strike->getGlyph(skGlyp
h, id, maskFormat, | |
| 1545 scaler
); | |
| 1546 } | |
| 1547 glyph = blob->fGlyphs[glyphOffset]; | |
| 1548 SkASSERT(glyph); | |
| 1549 SkASSERT(id == glyph->fPackedID); | |
| 1550 // We want to be able to assert this but cannot for test
ing purposes. | |
| 1551 // once skbug:4143 has landed we can revist this assert | |
| 1552 //SkASSERT(glyph->fMaskFormat == this->maskFormat()); | |
| 1553 | |
| 1554 if (!fFontCache->hasGlyph(glyph) && | |
| 1555 !strike->addGlyphToAtlas(target, glyph, scaler, skGl
yph, maskFormat)) { | |
| 1556 this->flush(target, &flushInfo); | |
| 1557 target->initDraw(gp, this->pipeline()); | |
| 1558 brokenRun = glyphIdx > 0; | |
| 1559 | |
| 1560 SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(
target, | |
| 1561
glyph, | |
| 1562
scaler, | |
| 1563
skGlyph, | |
| 1564
maskFormat); | |
| 1565 SkASSERT(success); | |
| 1566 } | |
| 1567 fFontCache->addGlyphToBulkAndSetUseToken(&info.fBulkUseT
oken, glyph, | |
| 1568 target->current
Token()); | |
| 1569 | |
| 1570 // Texture coords are the last vertex attribute so we ge
t a pointer to the | |
| 1571 // first one and then map with stride in regenerateTextu
reCoords | |
| 1572 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert
ices); | |
| 1573 vertex += info.fVertexStartIndex; | |
| 1574 vertex += vertexStride * glyphIdx * kVerticesPerGlyph; | |
| 1575 vertex += vertexStride - sizeof(SkIPoint16); | |
| 1576 | |
| 1577 this->regenerateTextureCoords(glyph, vertex, vertexStrid
e); | |
| 1578 } | |
| 1579 | |
| 1580 if (regenerateColors) { | |
| 1581 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert
ices); | |
| 1582 vertex += info.fVertexStartIndex; | |
| 1583 vertex += vertexStride * glyphIdx * kVerticesPerGlyph +
sizeof(SkPoint); | |
| 1584 this->regenerateColors(vertex, vertexStride, args.fColor
); | |
| 1585 } | |
| 1586 | |
| 1587 if (regeneratePositions) { | |
| 1588 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert
ices); | |
| 1589 vertex += info.fVertexStartIndex; | |
| 1590 vertex += vertexStride * glyphIdx * kVerticesPerGlyph; | |
| 1591 SkScalar transX = args.fTransX; | |
| 1592 SkScalar transY = args.fTransY; | |
| 1593 this->regeneratePositions(vertex, vertexStride, transX,
transY); | |
| 1594 } | |
| 1595 flushInfo.fGlyphsToFlush++; | |
| 1596 } | |
| 1597 | |
| 1598 // We my have changed the color so update it here | |
| 1599 run.fColor = args.fColor; | |
| 1600 if (regenerateTextureCoords) { | |
| 1601 if (regenerateGlyphs) { | |
| 1602 info.fStrike.reset(SkRef(strike)); | |
| 1603 } | |
| 1604 info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAt
lasGeneration : | |
| 1605 fFontCache->atlasGenerat
ion(maskFormat); | |
| 1606 } | |
| 1607 } else { | |
| 1608 flushInfo.fGlyphsToFlush += glyphCount; | |
| 1609 | |
| 1610 // set use tokens for all of the glyphs in our subrun. This is
only valid if we | |
| 1611 // have a valid atlas generation | |
| 1612 fFontCache->setUseTokenBulk(info.fBulkUseToken, target->currentT
oken(), maskFormat); | |
| 1613 } | |
| 1614 | |
| 1615 // now copy all vertices | |
| 1616 size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex; | |
| 1617 memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCou
nt); | |
| 1618 | |
| 1619 currVertex += byteCount; | |
| 1620 } | |
| 1621 // Make sure to attach the last cache if applicable | |
| 1622 if (cache) { | |
| 1623 SkGlyphCache::AttachCache(cache); | |
| 1624 } | |
| 1625 this->flush(target, &flushInfo); | |
| 1626 } | |
| 1627 | |
| 1628 TextBatch() : INHERITED(ClassID()) {} // initialized in factory functions. | |
| 1629 | |
| 1630 ~TextBatch() { | |
| 1631 for (int i = 0; i < fGeoCount; i++) { | |
| 1632 fGeoData[i].fBlob->unref(); | |
| 1633 } | |
| 1634 } | |
| 1635 | |
| 1636 GrMaskFormat maskFormat() const { | |
| 1637 switch (fMaskType) { | |
| 1638 case kLCDCoverageMask_MaskType: | |
| 1639 return kA565_GrMaskFormat; | |
| 1640 case kColorBitmapMask_MaskType: | |
| 1641 return kARGB_GrMaskFormat; | |
| 1642 case kGrayscaleCoverageMask_MaskType: | |
| 1643 case kGrayscaleDistanceField_MaskType: | |
| 1644 case kLCDDistanceField_MaskType: | |
| 1645 return kA8_GrMaskFormat; | |
| 1646 } | |
| 1647 return kA8_GrMaskFormat; // suppress warning | |
| 1648 } | |
| 1649 | |
| 1650 bool usesDistanceFields() const { | |
| 1651 return kGrayscaleDistanceField_MaskType == fMaskType || | |
| 1652 kLCDDistanceField_MaskType == fMaskType; | |
| 1653 } | |
| 1654 | |
| 1655 bool isLCD() const { | |
| 1656 return kLCDCoverageMask_MaskType == fMaskType || | |
| 1657 kLCDDistanceField_MaskType == fMaskType; | |
| 1658 } | |
| 1659 | |
| 1660 void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexS
tride) { | |
| 1661 int width = glyph->fBounds.width(); | |
| 1662 int height = glyph->fBounds.height(); | |
| 1663 | |
| 1664 int u0, v0, u1, v1; | |
| 1665 if (this->usesDistanceFields()) { | |
| 1666 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset; | |
| 1667 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset; | |
| 1668 u1 = u0 + width - 2 * SK_DistanceFieldInset; | |
| 1669 v1 = v0 + height - 2 * SK_DistanceFieldInset; | |
| 1670 } else { | |
| 1671 u0 = glyph->fAtlasLocation.fX; | |
| 1672 v0 = glyph->fAtlasLocation.fY; | |
| 1673 u1 = u0 + width; | |
| 1674 v1 = v0 + height; | |
| 1675 } | |
| 1676 | |
| 1677 SkIPoint16* textureCoords; | |
| 1678 // V0 | |
| 1679 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); | |
| 1680 textureCoords->set(u0, v0); | |
| 1681 vertex += vertexStride; | |
| 1682 | |
| 1683 // V1 | |
| 1684 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); | |
| 1685 textureCoords->set(u0, v1); | |
| 1686 vertex += vertexStride; | |
| 1687 | |
| 1688 // V2 | |
| 1689 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); | |
| 1690 textureCoords->set(u1, v1); | |
| 1691 vertex += vertexStride; | |
| 1692 | |
| 1693 // V3 | |
| 1694 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); | |
| 1695 textureCoords->set(u1, v0); | |
| 1696 } | |
| 1697 | |
| 1698 void regenerateColors(intptr_t vertex, size_t vertexStride, GrColor color) { | |
| 1699 for (int i = 0; i < kVerticesPerGlyph; i++) { | |
| 1700 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex); | |
| 1701 *vcolor = color; | |
| 1702 vertex += vertexStride; | |
| 1703 } | |
| 1704 } | |
| 1705 | |
| 1706 void regeneratePositions(intptr_t vertex, size_t vertexStride, SkScalar tran
sX, | |
| 1707 SkScalar transY) { | |
| 1708 for (int i = 0; i < kVerticesPerGlyph; i++) { | |
| 1709 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
| 1710 point->fX += transX; | |
| 1711 point->fY += transY; | |
| 1712 vertex += vertexStride; | |
| 1713 } | |
| 1714 } | |
| 1715 | |
| 1716 void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) { | |
| 1717 GrVertices vertices; | |
| 1718 int maxGlyphsPerDraw = flushInfo->fIndexBuffer->maxQuads(); | |
| 1719 vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuf
fer, | |
| 1720 flushInfo->fIndexBuffer, flushInfo->fVertexOffset
, | |
| 1721 kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->f
GlyphsToFlush, | |
| 1722 maxGlyphsPerDraw); | |
| 1723 target->draw(vertices); | |
| 1724 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlus
h; | |
| 1725 flushInfo->fGlyphsToFlush = 0; | |
| 1726 } | |
| 1727 | |
| 1728 GrColor color() const { return fBatch.fColor; } | |
| 1729 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } | |
| 1730 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
| 1731 int numGlyphs() const { return fBatch.fNumGlyphs; } | |
| 1732 | |
| 1733 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { | |
| 1734 TextBatch* that = t->cast<TextBatch>(); | |
| 1735 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi
peline(), | |
| 1736 that->bounds(), caps)) { | |
| 1737 return false; | |
| 1738 } | |
| 1739 | |
| 1740 if (fMaskType != that->fMaskType) { | |
| 1741 return false; | |
| 1742 } | |
| 1743 | |
| 1744 if (!this->usesDistanceFields()) { | |
| 1745 // TODO we can often batch across LCD text if we have dual source bl
ending and don't | |
| 1746 // have to use the blend constant | |
| 1747 if (kGrayscaleCoverageMask_MaskType != fMaskType && this->color() !=
that->color()) { | |
| 1748 return false; | |
| 1749 } | |
| 1750 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that
->viewMatrix())) { | |
| 1751 return false; | |
| 1752 } | |
| 1753 } else { | |
| 1754 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { | |
| 1755 return false; | |
| 1756 } | |
| 1757 | |
| 1758 if (fFilteredColor != that->fFilteredColor) { | |
| 1759 return false; | |
| 1760 } | |
| 1761 | |
| 1762 if (fUseBGR != that->fUseBGR) { | |
| 1763 return false; | |
| 1764 } | |
| 1765 | |
| 1766 // TODO see note above | |
| 1767 if (kLCDDistanceField_MaskType == fMaskType && this->color() != that
->color()) { | |
| 1768 return false; | |
| 1769 } | |
| 1770 } | |
| 1771 | |
| 1772 fBatch.fNumGlyphs += that->numGlyphs(); | |
| 1773 | |
| 1774 // Reallocate space for geo data if necessary and then import that's geo
data. | |
| 1775 int newGeoCount = that->fGeoCount + fGeoCount; | |
| 1776 // We assume (and here enforce) that the allocation size is the smallest
power of two that | |
| 1777 // is greater than or equal to the number of geometries (and at least | |
| 1778 // kMinGeometryAllocated). | |
| 1779 int newAllocSize = GrNextPow2(newGeoCount); | |
| 1780 int currAllocSize = SkTMax<int>(kMinGeometryAllocated, GrNextPow2(fGeoCo
unt)); | |
| 1781 | |
| 1782 if (newGeoCount > currAllocSize) { | |
| 1783 fGeoData.realloc(newAllocSize); | |
| 1784 } | |
| 1785 | |
| 1786 memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * siz
eof(Geometry)); | |
| 1787 // We steal the ref on the blobs from the other TextBatch and set its co
unt to 0 so that | |
| 1788 // it doesn't try to unref them. | |
| 1789 #ifdef SK_DEBUG | |
| 1790 for (int i = 0; i < that->fGeoCount; ++i) { | |
| 1791 that->fGeoData.get()[i].fBlob = (Blob*)0x1; | |
| 1792 } | |
| 1793 #endif | |
| 1794 that->fGeoCount = 0; | |
| 1795 fGeoCount = newGeoCount; | |
| 1796 | |
| 1797 this->joinBounds(that->bounds()); | |
| 1798 return true; | |
| 1799 } | |
| 1800 | |
| 1801 // TODO just use class params | |
| 1802 // TODO trying to figure out why lcd is so whack | |
| 1803 GrGeometryProcessor* setupDfProcessor(const SkMatrix& viewMatrix, SkColor fi
lteredColor, | |
| 1804 GrColor color, GrTexture* texture) { | |
| 1805 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBile
rp_FilterMode); | |
| 1806 bool isLCD = this->isLCD(); | |
| 1807 // set up any flags | |
| 1808 uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEf
fectFlag : 0; | |
| 1809 | |
| 1810 // see if we need to create a new effect | |
| 1811 if (isLCD) { | |
| 1812 flags |= kUseLCD_DistanceFieldEffectFlag; | |
| 1813 flags |= viewMatrix.rectStaysRect() ? kRectToRect_DistanceFieldEffec
tFlag : 0; | |
| 1814 flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0; | |
| 1815 | |
| 1816 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol
or); | |
| 1817 | |
| 1818 float redCorrection = | |
| 1819 (*fDistanceAdjustTable)[GrColorUnpackR(colorNoPreMul) >> kDistan
ceAdjustLumShift]; | |
| 1820 float greenCorrection = | |
| 1821 (*fDistanceAdjustTable)[GrColorUnpackG(colorNoPreMul) >> kDistan
ceAdjustLumShift]; | |
| 1822 float blueCorrection = | |
| 1823 (*fDistanceAdjustTable)[GrColorUnpackB(colorNoPreMul) >> kDistan
ceAdjustLumShift]; | |
| 1824 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust = | |
| 1825 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrectio
n, | |
| 1826 greenCorrect
ion, | |
| 1827 blueCorrecti
on); | |
| 1828 | |
| 1829 return GrDistanceFieldLCDTextGeoProc::Create(color, | |
| 1830 viewMatrix, | |
| 1831 texture, | |
| 1832 params, | |
| 1833 widthAdjust, | |
| 1834 flags, | |
| 1835 this->usesLocalCoords()
); | |
| 1836 } else { | |
| 1837 flags |= kColorAttr_DistanceFieldEffectFlag; | |
| 1838 #ifdef SK_GAMMA_APPLY_TO_A8 | |
| 1839 U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONEN
T, filteredColor); | |
| 1840 float correction = (*fDistanceAdjustTable)[lum >> kDistanceAdjustLum
Shift]; | |
| 1841 return GrDistanceFieldA8TextGeoProc::Create(color, | |
| 1842 viewMatrix, | |
| 1843 texture, | |
| 1844 params, | |
| 1845 correction, | |
| 1846 flags, | |
| 1847 this->usesLocalCoords())
; | |
| 1848 #else | |
| 1849 return GrDistanceFieldA8TextGeoProc::Create(color, | |
| 1850 viewMatrix, | |
| 1851 texture, | |
| 1852 params, | |
| 1853 flags, | |
| 1854 this->usesLocalCoords())
; | |
| 1855 #endif | |
| 1856 } | |
| 1857 | |
| 1858 } | |
| 1859 | |
| 1860 struct BatchTracker { | |
| 1861 GrColor fColor; | |
| 1862 SkMatrix fViewMatrix; | |
| 1863 bool fUsesLocalCoords; | |
| 1864 bool fColorIgnored; | |
| 1865 bool fCoverageIgnored; | |
| 1866 int fNumGlyphs; | |
| 1867 }; | |
| 1868 | |
| 1869 BatchTracker fBatch; | |
| 1870 // The minimum number of Geometry we will try to allocate. | |
| 1871 enum { kMinGeometryAllocated = 4 }; | |
| 1872 SkAutoSTMalloc<kMinGeometryAllocated, Geometry> fGeoData; | |
| 1873 int fGeoCount; | |
| 1874 | |
| 1875 enum MaskType { | |
| 1876 kGrayscaleCoverageMask_MaskType, | |
| 1877 kLCDCoverageMask_MaskType, | |
| 1878 kColorBitmapMask_MaskType, | |
| 1879 kGrayscaleDistanceField_MaskType, | |
| 1880 kLCDDistanceField_MaskType, | |
| 1881 } fMaskType; | |
| 1882 bool fUseBGR; // fold this into the enum? | |
| 1883 | |
| 1884 GrBatchFontCache* fFontCache; | |
| 1885 | |
| 1886 // Distance field properties | |
| 1887 SkAutoTUnref<const DistanceAdjustTable> fDistanceAdjustTable; | |
| 1888 SkColor fFilteredColor; | |
| 1889 | |
| 1890 typedef GrVertexBatch INHERITED; | |
| 1891 }; | |
| 1892 | |
| 1893 void GrAtlasTextContext::flushRunAsPaths(GrDrawContext* dc, GrRenderTarget* rt, | 1212 void GrAtlasTextContext::flushRunAsPaths(GrDrawContext* dc, GrRenderTarget* rt, |
| 1894 const SkTextBlobRunIterator& it, | 1213 const SkTextBlobRunIterator& it, |
| 1895 const GrClip& clip, const SkPaint& skPa
int, | 1214 const GrClip& clip, const SkPaint& skPa
int, |
| 1896 SkDrawFilter* drawFilter, const SkMatri
x& viewMatrix, | 1215 SkDrawFilter* drawFilter, const SkMatri
x& viewMatrix, |
| 1897 const SkIRect& clipBounds, SkScalar x,
SkScalar y) { | 1216 const SkIRect& clipBounds, SkScalar x,
SkScalar y) { |
| 1898 SkPaint runPaint = skPaint; | 1217 SkPaint runPaint = skPaint; |
| 1899 | 1218 |
| 1900 size_t textLen = it.glyphCount() * sizeof(uint16_t); | 1219 size_t textLen = it.glyphCount() * sizeof(uint16_t); |
| 1901 const SkPoint& offset = it.offset(); | 1220 const SkPoint& offset = it.offset(); |
| 1902 | 1221 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1935 const SkPaint& skPaint) { | 1254 const SkPaint& skPaint) { |
| 1936 GrMaskFormat format = info.fMaskFormat; | 1255 GrMaskFormat format = info.fMaskFormat; |
| 1937 GrColor subRunColor; | 1256 GrColor subRunColor; |
| 1938 if (kARGB_GrMaskFormat == format) { | 1257 if (kARGB_GrMaskFormat == format) { |
| 1939 uint8_t paintAlpha = skPaint.getAlpha(); | 1258 uint8_t paintAlpha = skPaint.getAlpha(); |
| 1940 subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAl
pha); | 1259 subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAl
pha); |
| 1941 } else { | 1260 } else { |
| 1942 subRunColor = color; | 1261 subRunColor = color; |
| 1943 } | 1262 } |
| 1944 | 1263 |
| 1945 TextBatch* batch; | 1264 GrAtlasTextBatch* batch; |
| 1946 if (info.fDrawAsDistanceFields) { | 1265 if (info.fDrawAsDistanceFields) { |
| 1947 SkColor filteredColor; | 1266 SkColor filteredColor; |
| 1948 SkColorFilter* colorFilter = skPaint.getColorFilter(); | 1267 SkColorFilter* colorFilter = skPaint.getColorFilter(); |
| 1949 if (colorFilter) { | 1268 if (colorFilter) { |
| 1950 filteredColor = colorFilter->filterColor(skPaint.getColor()); | 1269 filteredColor = colorFilter->filterColor(skPaint.getColor()); |
| 1951 } else { | 1270 } else { |
| 1952 filteredColor = skPaint.getColor(); | 1271 filteredColor = skPaint.getColor(); |
| 1953 } | 1272 } |
| 1954 bool useBGR = SkPixelGeometryIsBGR(fSurfaceProps.pixelGeometry()); | 1273 bool useBGR = SkPixelGeometryIsBGR(fSurfaceProps.pixelGeometry()); |
| 1955 batch = TextBatch::CreateDistanceField(glyphCount, fContext->getBatchFon
tCache(), | 1274 batch = GrAtlasTextBatch::CreateDistanceField(glyphCount, fContext->getB
atchFontCache(), |
| 1956 fDistanceAdjustTable, filteredCol
or, | 1275 fDistanceAdjustTable, filt
eredColor, |
| 1957 info.fUseLCDText, useBGR); | 1276 info.fUseLCDText, useBGR); |
| 1958 } else { | 1277 } else { |
| 1959 batch = TextBatch::CreateBitmap(format, glyphCount, fContext->getBatchFo
ntCache()); | 1278 batch = GrAtlasTextBatch::CreateBitmap(format, glyphCount, fContext->get
BatchFontCache()); |
| 1960 } | 1279 } |
| 1961 TextBatch::Geometry& geometry = batch->geometry(); | 1280 GrAtlasTextBatch::Geometry& geometry = batch->geometry(); |
| 1962 geometry.fBlob = SkRef(cacheBlob); | 1281 geometry.fBlob = SkRef(cacheBlob); |
| 1963 geometry.fRun = run; | 1282 geometry.fRun = run; |
| 1964 geometry.fSubRun = subRun; | 1283 geometry.fSubRun = subRun; |
| 1965 geometry.fColor = subRunColor; | 1284 geometry.fColor = subRunColor; |
| 1966 geometry.fTransX = transX; | 1285 geometry.fTransX = transX; |
| 1967 geometry.fTransY = transY; | 1286 geometry.fTransY = transY; |
| 1968 batch->init(); | 1287 batch->init(); |
| 1969 | 1288 |
| 1970 return batch; | 1289 return batch; |
| 1971 } | 1290 } |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2123 gTextContext->createDrawTextBlob(rt, clip, grPaint, skPaint, viewMat
rix, text, | 1442 gTextContext->createDrawTextBlob(rt, clip, grPaint, skPaint, viewMat
rix, text, |
| 2124 static_cast<size_t>(textLen), 0, 0,
noClip)); | 1443 static_cast<size_t>(textLen), 0, 0,
noClip)); |
| 2125 | 1444 |
| 2126 SkScalar transX = static_cast<SkScalar>(random->nextU()); | 1445 SkScalar transX = static_cast<SkScalar>(random->nextU()); |
| 2127 SkScalar transY = static_cast<SkScalar>(random->nextU()); | 1446 SkScalar transY = static_cast<SkScalar>(random->nextU()); |
| 2128 const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]
; | 1447 const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]
; |
| 2129 return gTextContext->createBatch(blob, info, textLen, 0, 0, color, transX, t
ransY, skPaint); | 1448 return gTextContext->createBatch(blob, info, textLen, 0, 0, color, transX, t
ransY, skPaint); |
| 2130 } | 1449 } |
| 2131 | 1450 |
| 2132 #endif | 1451 #endif |
| OLD | NEW |