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 |