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 "GrBlurUtils.h" | 9 #include "GrBlurUtils.h" |
10 #include "GrDrawContext.h" | 10 #include "GrDrawContext.h" |
(...skipping 28 matching lines...) Expand all Loading... |
39 static const int kSmallDFFontSize = 32; | 39 static const int kSmallDFFontSize = 32; |
40 static const int kSmallDFFontLimit = 32; | 40 static const int kSmallDFFontLimit = 32; |
41 static const int kMediumDFFontSize = 72; | 41 static const int kMediumDFFontSize = 72; |
42 static const int kMediumDFFontLimit = 72; | 42 static const int kMediumDFFontLimit = 72; |
43 static const int kLargeDFFontSize = 162; | 43 static const int kLargeDFFontSize = 162; |
44 #ifdef SK_BUILD_FOR_ANDROID | 44 #ifdef SK_BUILD_FOR_ANDROID |
45 static const int kLargeDFFontLimit = 384; | 45 static const int kLargeDFFontLimit = 384; |
46 #else | 46 #else |
47 static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; | 47 static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; |
48 #endif | 48 #endif |
49 | |
50 SkDEBUGCODE(static const int kExpectedDistanceAdjustTableSize = 8;) | |
51 }; | 49 }; |
52 | 50 |
53 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps&
surfaceProps) | 51 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps&
surfaceProps) |
54 : INHERITED(context, surfaceProps) | 52 : INHERITED(context, surfaceProps) |
55 , fDistanceAdjustTable(new DistanceAdjustTable) { | 53 , fDistanceAdjustTable(new GrDistanceFieldAdjustTable) { |
56 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest | 54 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest |
57 // vertexStride | 55 // vertexStride |
58 static_assert(GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kColorTex
tVASize && | 56 static_assert(GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kColorTex
tVASize && |
59 GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kLCDTextV
ASize, | 57 GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kLCDTextV
ASize, |
60 "vertex_attribute_changed"); | 58 "vertex_attribute_changed"); |
61 fCurrStrike = nullptr; | 59 fCurrStrike = nullptr; |
62 fCache = context->getTextBlobCache(); | 60 fCache = context->getTextBlobCache(); |
63 } | 61 } |
64 | 62 |
65 void GrAtlasTextContext::DistanceAdjustTable::buildDistanceAdjustTable() { | |
66 | |
67 // This is used for an approximation of the mask gamma hack, used by raster
and bitmap | |
68 // text. The mask gamma hack is based off of guessing what the blend color i
s going to | |
69 // be, and adjusting the mask so that when run through the linear blend will | |
70 // produce the value closest to the desired result. However, in practice thi
s means | |
71 // that the 'adjusted' mask is just increasing or decreasing the coverage of | |
72 // the mask depending on what it is thought it will blit against. For black
(on | |
73 // assumed white) this means that coverages are decreased (on a curve). For
white (on | |
74 // assumed black) this means that coverages are increased (on a a curve). At | |
75 // middle (perceptual) gray (which could be blit against anything) the cover
ages | |
76 // remain the same. | |
77 // | |
78 // The idea here is that instead of determining the initial (real) coverage
and | |
79 // then adjusting that coverage, we determine an adjusted coverage directly
by | |
80 // essentially manipulating the geometry (in this case, the distance to the
glyph | |
81 // edge). So for black (on assumed white) this thins a bit; for white (on | |
82 // assumed black) this fake bolds the geometry a bit. | |
83 // | |
84 // The distance adjustment is calculated by determining the actual coverage
value which | |
85 // when fed into in the mask gamma table gives us an 'adjusted coverage' val
ue of 0.5. This | |
86 // actual coverage value (assuming it's between 0 and 1) corresponds to a di
stance from the | |
87 // actual edge. So by subtracting this distance adjustment and computing wit
hout the | |
88 // the coverage adjustment we should get 0.5 coverage at the same point. | |
89 // | |
90 // This has several implications: | |
91 // For non-gray lcd smoothed text, each subpixel essentially is using a | |
92 // slightly different geometry. | |
93 // | |
94 // For black (on assumed white) this may not cover some pixels which wer
e | |
95 // previously covered; however those pixels would have been only slightl
y | |
96 // covered and that slight coverage would have been decreased anyway. Al
so, some pixels | |
97 // which were previously fully covered may no longer be fully covered. | |
98 // | |
99 // For white (on assumed black) this may cover some pixels which weren't | |
100 // previously covered at all. | |
101 | |
102 int width, height; | |
103 size_t size; | |
104 | |
105 #ifdef SK_GAMMA_CONTRAST | |
106 SkScalar contrast = SK_GAMMA_CONTRAST; | |
107 #else | |
108 SkScalar contrast = 0.5f; | |
109 #endif | |
110 SkScalar paintGamma = SK_GAMMA_EXPONENT; | |
111 SkScalar deviceGamma = SK_GAMMA_EXPONENT; | |
112 | |
113 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma, | |
114 &width, &height); | |
115 | |
116 SkASSERT(kExpectedDistanceAdjustTableSize == height); | |
117 fTable = new SkScalar[height]; | |
118 | |
119 SkAutoTArray<uint8_t> data((int)size); | |
120 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get
()); | |
121 | |
122 // find the inverse points where we cross 0.5 | |
123 // binsearch might be better, but we only need to do this once on creation | |
124 for (int row = 0; row < height; ++row) { | |
125 uint8_t* rowPtr = data.get() + row*width; | |
126 for (int col = 0; col < width - 1; ++col) { | |
127 if (rowPtr[col] <= 127 && rowPtr[col + 1] >= 128) { | |
128 // compute point where a mask value will give us a result of 0.5 | |
129 float interp = (127.5f - rowPtr[col]) / (rowPtr[col + 1] - rowPt
r[col]); | |
130 float borderAlpha = (col + interp) / 255.f; | |
131 | |
132 // compute t value for that alpha | |
133 // this is an approximate inverse for smoothstep() | |
134 float t = borderAlpha*(borderAlpha*(4.0f*borderAlpha - 6.0f) + 5
.0f) / 3.0f; | |
135 | |
136 // compute distance which gives us that t value | |
137 const float kDistanceFieldAAFactor = 0.65f; // should match SK_D
istanceFieldAAFactor | |
138 float d = 2.0f*kDistanceFieldAAFactor*t - kDistanceFieldAAFactor
; | |
139 | |
140 fTable[row] = d; | |
141 break; | |
142 } | |
143 } | |
144 } | |
145 } | |
146 | 63 |
147 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, | 64 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, |
148 const SkSurfaceProps& surfaceProp
s) { | 65 const SkSurfaceProps& surfaceProp
s) { |
149 return new GrAtlasTextContext(context, surfaceProps); | 66 return new GrAtlasTextContext(context, surfaceProps); |
150 } | 67 } |
151 | 68 |
152 bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, const SkMatrix& viewMat
rix) { | 69 bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, const SkMatrix& viewMat
rix) { |
153 return this->canDrawAsDistanceFields(skPaint, viewMatrix) || | 70 return this->canDrawAsDistanceFields(skPaint, viewMatrix) || |
154 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); | 71 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); |
155 } | 72 } |
(...skipping 1004 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1160 gTextContext->createDrawTextBlob(clip, grPaint, skPaint, viewMatrix,
text, | 1077 gTextContext->createDrawTextBlob(clip, grPaint, skPaint, viewMatrix,
text, |
1161 static_cast<size_t>(textLen), 0, 0,
noClip)); | 1078 static_cast<size_t>(textLen), 0, 0,
noClip)); |
1162 | 1079 |
1163 SkScalar transX = static_cast<SkScalar>(random->nextU()); | 1080 SkScalar transX = static_cast<SkScalar>(random->nextU()); |
1164 SkScalar transY = static_cast<SkScalar>(random->nextU()); | 1081 SkScalar transY = static_cast<SkScalar>(random->nextU()); |
1165 const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]
; | 1082 const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]
; |
1166 return gTextContext->createBatch(blob, info, textLen, 0, 0, color, transX, t
ransY, skPaint); | 1083 return gTextContext->createBatch(blob, info, textLen, 0, 0, color, transX, t
ransY, skPaint); |
1167 } | 1084 } |
1168 | 1085 |
1169 #endif | 1086 #endif |
OLD | NEW |