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 "GrDrawContext.h" | 9 #include "GrDrawContext.h" |
10 #include "GrDrawTarget.h" | 10 #include "GrDrawTarget.h" |
11 #include "GrFontScaler.h" | |
12 #include "GrStrokeInfo.h" | |
13 #include "GrTextBlobCache.h" | 11 #include "GrTextBlobCache.h" |
14 #include "GrTexturePriv.h" | |
15 #include "GrTextUtils.h" | 12 #include "GrTextUtils.h" |
16 #include "GrVertexBuffer.h" | |
17 | 13 |
18 #include "SkAutoKern.h" | |
19 #include "SkColorPriv.h" | |
20 #include "SkColorFilter.h" | |
21 #include "SkDistanceFieldGen.h" | |
22 #include "SkDraw.h" | 14 #include "SkDraw.h" |
23 #include "SkDrawFilter.h" | 15 #include "SkDrawFilter.h" |
24 #include "SkDrawProcs.h" | |
25 #include "SkFindAndPlaceGlyph.h" | |
26 #include "SkGlyphCache.h" | |
27 #include "SkGpuDevice.h" | |
28 #include "SkGrPriv.h" | 16 #include "SkGrPriv.h" |
29 #include "SkPath.h" | |
30 #include "SkRTConf.h" | |
31 #include "SkStrokeRec.h" | |
32 #include "SkTextBlob.h" | |
33 #include "SkTextMapStateProc.h" | |
34 | 17 |
35 #include "batches/GrAtlasTextBatch.h" | 18 GrAtlasTextContext::GrAtlasTextContext() |
36 | 19 : fDistanceAdjustTable(new GrDistanceFieldAdjustTable) { |
37 GrAtlasTextContext::GrAtlasTextContext(GrContext* context) | |
38 : INHERITED(context) | |
39 , fDistanceAdjustTable(new GrDistanceFieldAdjustTable) { | |
40 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest | |
41 // vertexStride | |
42 static_assert(GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kColorTex
tVASize && | |
43 GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kLCDTextV
ASize, | |
44 "vertex_attribute_changed"); | |
45 fCache = context->getTextBlobCache(); | |
46 } | 20 } |
47 | 21 |
48 | 22 |
49 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context) { | 23 GrAtlasTextContext* GrAtlasTextContext::Create() { |
50 return new GrAtlasTextContext(context); | 24 return new GrAtlasTextContext(); |
51 } | 25 } |
52 | 26 |
53 bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, | 27 bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, |
54 const SkMatrix& viewMatrix, | 28 const SkMatrix& viewMatrix, |
55 const SkSurfaceProps& props) { | 29 const SkSurfaceProps& props, |
56 return GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, props, | 30 const GrShaderCaps& shaderCaps) { |
57 *fContext->caps()->shaderCaps())
|| | 31 return GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, props, shad
erCaps) || |
58 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); | 32 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); |
59 } | 33 } |
60 | 34 |
61 GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd
) { | 35 GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd
) { |
62 GrColor canonicalColor = paint.computeLuminanceColor(); | 36 GrColor canonicalColor = paint.computeLuminanceColor(); |
63 if (lcd) { | 37 if (lcd) { |
64 // This is the correct computation, but there are tons of cases where LC
D can be overridden. | 38 // This is the correct computation, but there are tons of cases where LC
D can be overridden. |
65 // For now we just regenerate if any run in a textblob has LCD. | 39 // For now we just regenerate if any run in a textblob has LCD. |
66 // TODO figure out where all of these overrides are and see if we can in
corporate that logic | 40 // TODO figure out where all of these overrides are and see if we can in
corporate that logic |
67 // at a higher level *OR* use sRGB | 41 // at a higher level *OR* use sRGB |
(...skipping 17 matching lines...) Expand all Loading... |
85 bool GrAtlasTextContext::HasLCD(const SkTextBlob* blob) { | 59 bool GrAtlasTextContext::HasLCD(const SkTextBlob* blob) { |
86 SkTextBlobRunIterator it(blob); | 60 SkTextBlobRunIterator it(blob); |
87 for (; !it.done(); it.next()) { | 61 for (; !it.done(); it.next()) { |
88 if (it.isLCD()) { | 62 if (it.isLCD()) { |
89 return true; | 63 return true; |
90 } | 64 } |
91 } | 65 } |
92 return false; | 66 return false; |
93 } | 67 } |
94 | 68 |
95 void GrAtlasTextContext::drawTextBlob(GrDrawContext* dc, | 69 void GrAtlasTextContext::drawTextBlob(GrContext* context, GrDrawContext* dc, |
96 const GrClip& clip, const SkPaint& skPaint
, | 70 const GrClip& clip, const SkPaint& skPaint
, |
97 const SkMatrix& viewMatrix, | 71 const SkMatrix& viewMatrix, |
98 const SkSurfaceProps& props, const SkTextB
lob* blob, | 72 const SkSurfaceProps& props, const SkTextB
lob* blob, |
99 SkScalar x, SkScalar y, | 73 SkScalar x, SkScalar y, |
100 SkDrawFilter* drawFilter, const SkIRect& c
lipBounds) { | 74 SkDrawFilter* drawFilter, const SkIRect& c
lipBounds) { |
101 // If we have been abandoned, then don't draw | 75 // If we have been abandoned, then don't draw |
102 if (fContext->abandoned()) { | 76 if (context->abandoned()) { |
103 return; | 77 return; |
104 } | 78 } |
105 | 79 |
106 SkAutoTUnref<GrAtlasTextBlob> cacheBlob; | 80 SkAutoTUnref<GrAtlasTextBlob> cacheBlob; |
107 SkMaskFilter::BlurRec blurRec; | 81 SkMaskFilter::BlurRec blurRec; |
108 GrAtlasTextBlob::Key key; | 82 GrAtlasTextBlob::Key key; |
109 // It might be worth caching these things, but its not clear at this time | 83 // It might be worth caching these things, but its not clear at this time |
110 // TODO for animated mask filters, this will fill up our cache. We need a s
afeguard here | 84 // TODO for animated mask filters, this will fill up our cache. We need a s
afeguard here |
111 const SkMaskFilter* mf = skPaint.getMaskFilter(); | 85 const SkMaskFilter* mf = skPaint.getMaskFilter(); |
112 bool canCache = !(skPaint.getPathEffect() || | 86 bool canCache = !(skPaint.getPathEffect() || |
113 (mf && !mf->asABlur(&blurRec)) || | 87 (mf && !mf->asABlur(&blurRec)) || |
114 drawFilter); | 88 drawFilter); |
115 | 89 |
| 90 GrTextBlobCache* cache = context->getTextBlobCache(); |
116 if (canCache) { | 91 if (canCache) { |
117 bool hasLCD = HasLCD(blob); | 92 bool hasLCD = HasLCD(blob); |
118 | 93 |
119 // We canonicalize all non-lcd draws to use kUnknown_SkPixelGeometry | 94 // We canonicalize all non-lcd draws to use kUnknown_SkPixelGeometry |
120 SkPixelGeometry pixelGeometry = hasLCD ? props.pixelGeometry() : | 95 SkPixelGeometry pixelGeometry = hasLCD ? props.pixelGeometry() : |
121 kUnknown_SkPixelGeometry; | 96 kUnknown_SkPixelGeometry; |
122 | 97 |
123 // TODO we want to figure out a way to be able to use the canonical colo
r on LCD text, | 98 // TODO we want to figure out a way to be able to use the canonical colo
r on LCD text, |
124 // see the note on ComputeCanonicalColor above. We pick a dummy value f
or LCD text to | 99 // see the note on ComputeCanonicalColor above. We pick a dummy value f
or LCD text to |
125 // ensure we always match the same key | 100 // ensure we always match the same key |
126 GrColor canonicalColor = hasLCD ? SK_ColorTRANSPARENT : | 101 GrColor canonicalColor = hasLCD ? SK_ColorTRANSPARENT : |
127 ComputeCanonicalColor(skPaint, hasLCD)
; | 102 ComputeCanonicalColor(skPaint, hasLCD)
; |
128 | 103 |
129 key.fPixelGeometry = pixelGeometry; | 104 key.fPixelGeometry = pixelGeometry; |
130 key.fUniqueID = blob->uniqueID(); | 105 key.fUniqueID = blob->uniqueID(); |
131 key.fStyle = skPaint.getStyle(); | 106 key.fStyle = skPaint.getStyle(); |
132 key.fHasBlur = SkToBool(mf); | 107 key.fHasBlur = SkToBool(mf); |
133 key.fCanonicalColor = canonicalColor; | 108 key.fCanonicalColor = canonicalColor; |
134 cacheBlob.reset(SkSafeRef(fCache->find(key))); | 109 cacheBlob.reset(SkSafeRef(cache->find(key))); |
135 } | 110 } |
136 | 111 |
137 SkScalar transX = 0.f; | 112 SkScalar transX = 0.f; |
138 SkScalar transY = 0.f; | 113 SkScalar transY = 0.f; |
139 | 114 |
140 // Though for the time being runs in the textblob can override the paint, th
ey only touch font | 115 // Though for the time being runs in the textblob can override the paint, th
ey only touch font |
141 // info. | 116 // info. |
142 GrPaint grPaint; | 117 GrPaint grPaint; |
143 if (!SkPaintToGrPaint(fContext, skPaint, viewMatrix, &grPaint)) { | 118 if (!SkPaintToGrPaint(context, skPaint, viewMatrix, &grPaint)) { |
144 return; | 119 return; |
145 } | 120 } |
146 | 121 |
147 if (cacheBlob) { | 122 if (cacheBlob) { |
148 if (cacheBlob->mustRegenerate(&transX, &transY, skPaint, grPaint.getColo
r(), blurRec, | 123 if (cacheBlob->mustRegenerate(&transX, &transY, skPaint, grPaint.getColo
r(), blurRec, |
149 viewMatrix, x, y)) { | 124 viewMatrix, x, y)) { |
150 // We have to remake the blob because changes may invalidate our mas
ks. | 125 // We have to remake the blob because changes may invalidate our mas
ks. |
151 // TODO we could probably get away reuse most of the time if the poi
nter is unique, | 126 // TODO we could probably get away reuse most of the time if the poi
nter is unique, |
152 // but we'd have to clear the subrun information | 127 // but we'd have to clear the subrun information |
153 fCache->remove(cacheBlob); | 128 cache->remove(cacheBlob); |
154 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, s
kPaint))); | 129 cacheBlob.reset(SkRef(cache->createCachedBlob(blob, key, blurRec, sk
Paint))); |
155 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), vie
wMatrix, props, | 130 RegenerateTextBlob(cacheBlob, context->getBatchFontCache(), |
156 blob, x, y, drawFilter); | 131 *context->caps()->shaderCaps(), skPaint, grPaint.
getColor(), |
| 132 viewMatrix, props, |
| 133 blob, x, y, drawFilter); |
157 } else { | 134 } else { |
158 fCache->makeMRU(cacheBlob); | 135 cache->makeMRU(cacheBlob); |
159 | 136 |
160 if (CACHE_SANITY_CHECK) { | 137 if (CACHE_SANITY_CHECK) { |
161 int glyphCount = 0; | 138 int glyphCount = 0; |
162 int runCount = 0; | 139 int runCount = 0; |
163 GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob); | 140 GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob); |
164 SkAutoTUnref<GrAtlasTextBlob> sanityBlob(fCache->createBlob(glyp
hCount, runCount)); | 141 SkAutoTUnref<GrAtlasTextBlob> sanityBlob(cache->createBlob(glyph
Count, runCount)); |
165 sanityBlob->setupKey(key, blurRec, skPaint); | 142 sanityBlob->setupKey(key, blurRec, skPaint); |
166 this->regenerateTextBlob(sanityBlob, skPaint, grPaint.getColor()
, viewMatrix, props, | 143 RegenerateTextBlob(sanityBlob, context->getBatchFontCache(), |
167 blob, x, y, drawFilter); | 144 *context->caps()->shaderCaps(), skPaint, |
| 145 grPaint.getColor(), viewMatrix, props, |
| 146 blob, x, y, drawFilter); |
168 GrAtlasTextBlob::AssertEqual(*sanityBlob, *cacheBlob); | 147 GrAtlasTextBlob::AssertEqual(*sanityBlob, *cacheBlob); |
169 } | 148 } |
170 } | 149 } |
171 } else { | 150 } else { |
172 if (canCache) { | 151 if (canCache) { |
173 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, s
kPaint))); | 152 cacheBlob.reset(SkRef(cache->createCachedBlob(blob, key, blurRec, sk
Paint))); |
174 } else { | 153 } else { |
175 cacheBlob.reset(fCache->createBlob(blob)); | 154 cacheBlob.reset(cache->createBlob(blob)); |
176 } | 155 } |
177 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat
rix, props, | 156 RegenerateTextBlob(cacheBlob, context->getBatchFontCache(), |
178 blob, x, y, drawFilter); | 157 *context->caps()->shaderCaps(), skPaint, grPaint.getC
olor(), |
| 158 viewMatrix, props, |
| 159 blob, x, y, drawFilter); |
179 } | 160 } |
180 | 161 |
181 cacheBlob->flushCached(fContext, dc, blob, props, fDistanceAdjustTable, skPa
int, | 162 cacheBlob->flushCached(context, dc, blob, props, fDistanceAdjustTable, skPai
nt, |
182 grPaint, drawFilter, clip, viewMatrix, clipBounds, x,
y, transX, transY); | 163 grPaint, drawFilter, clip, viewMatrix, clipBounds, x,
y, transX, transY); |
183 } | 164 } |
184 | 165 |
185 void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, | 166 void GrAtlasTextContext::RegenerateTextBlob(GrAtlasTextBlob* cacheBlob, |
| 167 GrBatchFontCache* fontCache, |
| 168 const GrShaderCaps& shaderCaps, |
186 const SkPaint& skPaint, GrColor colo
r, | 169 const SkPaint& skPaint, GrColor colo
r, |
187 const SkMatrix& viewMatrix, | 170 const SkMatrix& viewMatrix, |
188 const SkSurfaceProps& props, | 171 const SkSurfaceProps& props, |
189 const SkTextBlob* blob, SkScalar x,
SkScalar y, | 172 const SkTextBlob* blob, SkScalar x,
SkScalar y, |
190 SkDrawFilter* drawFilter) { | 173 SkDrawFilter* drawFilter) { |
191 cacheBlob->initReusableBlob(color, viewMatrix, x, y); | 174 cacheBlob->initReusableBlob(color, viewMatrix, x, y); |
192 | 175 |
193 // Regenerate textblob | 176 // Regenerate textblob |
194 SkPaint runPaint = skPaint; | 177 SkPaint runPaint = skPaint; |
195 SkTextBlobRunIterator it(blob); | 178 SkTextBlobRunIterator it(blob); |
196 for (int run = 0; !it.done(); it.next(), run++) { | 179 for (int run = 0; !it.done(); it.next(), run++) { |
197 int glyphCount = it.glyphCount(); | 180 int glyphCount = it.glyphCount(); |
198 size_t textLen = glyphCount * sizeof(uint16_t); | 181 size_t textLen = glyphCount * sizeof(uint16_t); |
199 const SkPoint& offset = it.offset(); | 182 const SkPoint& offset = it.offset(); |
200 // applyFontToPaint() always overwrites the exact same attributes, | 183 // applyFontToPaint() always overwrites the exact same attributes, |
201 // so it is safe to not re-seed the paint for this reason. | 184 // so it is safe to not re-seed the paint for this reason. |
202 it.applyFontToPaint(&runPaint); | 185 it.applyFontToPaint(&runPaint); |
203 | 186 |
204 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ
e)) { | 187 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ
e)) { |
205 // A false return from filter() means we should abort the current dr
aw. | 188 // A false return from filter() means we should abort the current dr
aw. |
206 runPaint = skPaint; | 189 runPaint = skPaint; |
207 continue; | 190 continue; |
208 } | 191 } |
209 | 192 |
210 runPaint.setFlags(FilterTextFlags(props, runPaint)); | 193 runPaint.setFlags(FilterTextFlags(props, runPaint)); |
211 | 194 |
212 cacheBlob->push_back_run(run); | 195 cacheBlob->push_back_run(run); |
213 | 196 |
214 if (GrTextUtils::CanDrawAsDistanceFields(runPaint, viewMatrix, props, | 197 if (GrTextUtils::CanDrawAsDistanceFields(runPaint, viewMatrix, props, sh
aderCaps)) { |
215 *fContext->caps()->shaderCaps()
)) { | |
216 switch (it.positioning()) { | 198 switch (it.positioning()) { |
217 case SkTextBlob::kDefault_Positioning: { | 199 case SkTextBlob::kDefault_Positioning: { |
218 GrTextUtils::DrawDFText(cacheBlob, run, fContext->getBatchFo
ntCache(), | 200 GrTextUtils::DrawDFText(cacheBlob, run, fontCache, |
219 props, runPaint, color, viewMatrix, | 201 props, runPaint, color, viewMatrix, |
220 (const char *)it.glyphs(), textLen, | 202 (const char *)it.glyphs(), textLen, |
221 x + offset.x(), y + offset.y()); | 203 x + offset.x(), y + offset.y()); |
222 break; | 204 break; |
223 } | 205 } |
224 case SkTextBlob::kHorizontal_Positioning: { | 206 case SkTextBlob::kHorizontal_Positioning: { |
225 SkPoint dfOffset = SkPoint::Make(x, y + offset.y()); | 207 SkPoint dfOffset = SkPoint::Make(x, y + offset.y()); |
226 GrTextUtils::DrawDFPosText(cacheBlob, run, fContext->getBatc
hFontCache(), | 208 GrTextUtils::DrawDFPosText(cacheBlob, run, fontCache, |
227 props, runPaint, color, viewMatri
x, | 209 props, runPaint, color, viewMatri
x, |
228 (const char*)it.glyphs(), textLen
, it.pos(), | 210 (const char*)it.glyphs(), textLen
, it.pos(), |
229 1, dfOffset); | 211 1, dfOffset); |
230 break; | 212 break; |
231 } | 213 } |
232 case SkTextBlob::kFull_Positioning: { | 214 case SkTextBlob::kFull_Positioning: { |
233 SkPoint dfOffset = SkPoint::Make(x, y); | 215 SkPoint dfOffset = SkPoint::Make(x, y); |
234 GrTextUtils::DrawDFPosText(cacheBlob, run, fContext->getBat
chFontCache(), | 216 GrTextUtils::DrawDFPosText(cacheBlob, run, fontCache, |
235 props, runPaint, color, viewMatri
x, | 217 props, runPaint, color, viewMatri
x, |
236 (const char*)it.glyphs(), textLen
, it.pos(), | 218 (const char*)it.glyphs(), textLen
, it.pos(), |
237 2, dfOffset); | 219 2, dfOffset); |
238 break; | 220 break; |
239 } | 221 } |
240 } | 222 } |
241 } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { | 223 } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { |
242 cacheBlob->setRunDrawAsPaths(run); | 224 cacheBlob->setRunDrawAsPaths(run); |
243 } else { | 225 } else { |
244 switch (it.positioning()) { | 226 switch (it.positioning()) { |
245 case SkTextBlob::kDefault_Positioning: | 227 case SkTextBlob::kDefault_Positioning: |
246 GrTextUtils::DrawBmpText(cacheBlob, run, fContext->getBatchF
ontCache(), | 228 GrTextUtils::DrawBmpText(cacheBlob, run, fontCache, |
247 props, runPaint, color, viewMatrix, | 229 props, runPaint, color, viewMatrix, |
248 (const char *)it.glyphs(), textLen, | 230 (const char *)it.glyphs(), textLen, |
249 x + offset.x(), y + offset.y()); | 231 x + offset.x(), y + offset.y()); |
250 break; | 232 break; |
251 case SkTextBlob::kHorizontal_Positioning: | 233 case SkTextBlob::kHorizontal_Positioning: |
252 GrTextUtils::DrawBmpPosText(cacheBlob, run, fContext->getBat
chFontCache(), | 234 GrTextUtils::DrawBmpPosText(cacheBlob, run, fontCache, |
253 props, runPaint, color, viewMatr
ix, | 235 props, runPaint, color, viewMatr
ix, |
254 (const char*)it.glyphs(), textLe
n, it.pos(), 1, | 236 (const char*)it.glyphs(), textLe
n, it.pos(), 1, |
255 SkPoint::Make(x, y + offset.y())
); | 237 SkPoint::Make(x, y + offset.y())
); |
256 break; | 238 break; |
257 case SkTextBlob::kFull_Positioning: | 239 case SkTextBlob::kFull_Positioning: |
258 GrTextUtils::DrawBmpPosText(cacheBlob, run, fContext->getBat
chFontCache(), | 240 GrTextUtils::DrawBmpPosText(cacheBlob, run, fontCache, |
259 props, runPaint, color, viewMatr
ix, | 241 props, runPaint, color, viewMatr
ix, |
260 (const char*)it.glyphs(), textLe
n, it.pos(), 2, | 242 (const char*)it.glyphs(), textLe
n, it.pos(), 2, |
261 SkPoint::Make(x, y)); | 243 SkPoint::Make(x, y)); |
262 break; | 244 break; |
263 } | 245 } |
264 } | 246 } |
265 | 247 |
266 if (drawFilter) { | 248 if (drawFilter) { |
267 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. | 249 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. |
268 runPaint = skPaint; | 250 runPaint = skPaint; |
269 } | 251 } |
270 } | 252 } |
271 } | 253 } |
272 | 254 |
273 inline GrAtlasTextBlob* | 255 inline GrAtlasTextBlob* |
274 GrAtlasTextContext::createDrawTextBlob(const GrPaint& paint, | 256 GrAtlasTextContext::CreateDrawTextBlob(GrTextBlobCache* blobCache, |
| 257 GrBatchFontCache* fontCache, |
| 258 const GrShaderCaps& shaderCaps, |
| 259 const GrPaint& paint, |
275 const SkPaint& skPaint, | 260 const SkPaint& skPaint, |
276 const SkMatrix& viewMatrix, | 261 const SkMatrix& viewMatrix, |
277 const SkSurfaceProps& props, | 262 const SkSurfaceProps& props, |
278 const char text[], size_t byteLength, | 263 const char text[], size_t byteLength, |
279 SkScalar x, SkScalar y) { | 264 SkScalar x, SkScalar y) { |
280 int glyphCount = skPaint.countText(text, byteLength); | 265 int glyphCount = skPaint.countText(text, byteLength); |
281 | 266 |
282 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1); | 267 GrAtlasTextBlob* blob = blobCache->createBlob(glyphCount, 1); |
283 blob->initThrowawayBlob(viewMatrix, x, y); | 268 blob->initThrowawayBlob(viewMatrix, x, y); |
284 | 269 |
285 if (GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, props, | 270 if (GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, props, shaderC
aps)) { |
286 *fContext->caps()->shaderCaps())) { | 271 GrTextUtils::DrawDFText(blob, 0, fontCache, props, |
287 GrTextUtils::DrawDFText(blob, 0, fContext->getBatchFontCache(), props, | |
288 skPaint, paint.getColor(), viewMatrix, text, | 272 skPaint, paint.getColor(), viewMatrix, text, |
289 byteLength, x, y); | 273 byteLength, x, y); |
290 } else { | 274 } else { |
291 GrTextUtils::DrawBmpText(blob, 0, fContext->getBatchFontCache(), props,
skPaint, | 275 GrTextUtils::DrawBmpText(blob, 0, fontCache, props, skPaint, |
292 paint.getColor(), viewMatrix, text, byteLength,
x, y); | 276 paint.getColor(), viewMatrix, text, byteLength,
x, y); |
293 } | 277 } |
294 return blob; | 278 return blob; |
295 } | 279 } |
296 | 280 |
297 inline GrAtlasTextBlob* | 281 inline GrAtlasTextBlob* |
298 GrAtlasTextContext::createDrawPosTextBlob(const GrPaint& paint, const SkPaint& s
kPaint, | 282 GrAtlasTextContext::CreateDrawPosTextBlob(GrTextBlobCache* blobCache, GrBatchFon
tCache* fontCache, |
| 283 const GrShaderCaps& shaderCaps, const
GrPaint& paint, |
| 284 const SkPaint& skPaint, |
299 const SkMatrix& viewMatrix, const SkSu
rfaceProps& props, | 285 const SkMatrix& viewMatrix, const SkSu
rfaceProps& props, |
300 const char text[], size_t byteLength, | 286 const char text[], size_t byteLength, |
301 const SkScalar pos[], int scalarsPerPo
sition, | 287 const SkScalar pos[], int scalarsPerPo
sition, |
302 const SkPoint& offset) { | 288 const SkPoint& offset) { |
303 int glyphCount = skPaint.countText(text, byteLength); | 289 int glyphCount = skPaint.countText(text, byteLength); |
304 | 290 |
305 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1); | 291 GrAtlasTextBlob* blob = blobCache->createBlob(glyphCount, 1); |
306 blob->initThrowawayBlob(viewMatrix, offset.x(), offset.y()); | 292 blob->initThrowawayBlob(viewMatrix, offset.x(), offset.y()); |
307 | 293 |
308 if (GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, props, | 294 if (GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, props, shaderC
aps)) { |
309 *fContext->caps()->shaderCaps())) { | 295 GrTextUtils::DrawDFPosText(blob, 0, fontCache, props, |
310 GrTextUtils::DrawDFPosText(blob, 0, fContext->getBatchFontCache(), props
, | |
311 skPaint, paint.getColor(), viewMatrix, text, | 296 skPaint, paint.getColor(), viewMatrix, text, |
312 byteLength, pos, scalarsPerPosition, offset); | 297 byteLength, pos, scalarsPerPosition, offset); |
313 } else { | 298 } else { |
314 GrTextUtils::DrawBmpPosText(blob, 0, fContext->getBatchFontCache(), prop
s, skPaint, | 299 GrTextUtils::DrawBmpPosText(blob, 0, fontCache, props, skPaint, |
315 paint.getColor(), viewMatrix, text, | 300 paint.getColor(), viewMatrix, text, |
316 byteLength, pos, scalarsPerPosition, offset)
; | 301 byteLength, pos, scalarsPerPosition, offset)
; |
317 } | 302 } |
318 return blob; | 303 return blob; |
319 } | 304 } |
320 | 305 |
321 void GrAtlasTextContext::drawText(GrDrawContext* dc, | 306 void GrAtlasTextContext::drawText(GrContext* context, |
| 307 GrDrawContext* dc, |
322 const GrClip& clip, | 308 const GrClip& clip, |
323 const GrPaint& paint, const SkPaint& skPaint, | 309 const GrPaint& paint, const SkPaint& skPaint, |
324 const SkMatrix& viewMatrix, | 310 const SkMatrix& viewMatrix, |
325 const SkSurfaceProps& props, | 311 const SkSurfaceProps& props, |
326 const char text[], size_t byteLength, | 312 const char text[], size_t byteLength, |
327 SkScalar x, SkScalar y, const SkIRect& regionC
lipBounds) { | 313 SkScalar x, SkScalar y, const SkIRect& regionC
lipBounds) { |
328 if (fContext->abandoned()) { | 314 if (context->abandoned()) { |
329 return; | 315 return; |
330 } else if (this->canDraw(skPaint, viewMatrix, props)) { | 316 } else if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shade
rCaps())) { |
331 SkAutoTUnref<GrAtlasTextBlob> blob( | 317 SkAutoTUnref<GrAtlasTextBlob> blob( |
332 this->createDrawTextBlob(paint, skPaint, viewMatrix, props, text, by
teLength, x, y)); | 318 CreateDrawTextBlob(context->getTextBlobCache(), context->getBatchFon
tCache(), |
333 blob->flushThrowaway(fContext, dc, props, fDistanceAdjustTable, skPaint,
paint, | 319 *context->caps()->shaderCaps(), |
| 320 paint, skPaint, |
| 321 viewMatrix, props, |
| 322 text, byteLength, x, y)); |
| 323 blob->flushThrowaway(context, dc, props, fDistanceAdjustTable, skPaint,
paint, |
334 clip, regionClipBounds); | 324 clip, regionClipBounds); |
335 return; | 325 return; |
336 } | 326 } |
337 | 327 |
338 // fall back to drawing as a path | 328 // fall back to drawing as a path |
339 GrTextUtils::DrawTextAsPath(fContext, dc, clip, skPaint, viewMatrix, text, b
yteLength, x, y, | 329 GrTextUtils::DrawTextAsPath(context, dc, clip, skPaint, viewMatrix, text, by
teLength, x, y, |
340 regionClipBounds); | 330 regionClipBounds); |
341 } | 331 } |
342 | 332 |
343 void GrAtlasTextContext::drawPosText(GrDrawContext* dc, | 333 void GrAtlasTextContext::drawPosText(GrContext* context, |
| 334 GrDrawContext* dc, |
344 const GrClip& clip, | 335 const GrClip& clip, |
345 const GrPaint& paint, const SkPaint& skPain
t, | 336 const GrPaint& paint, const SkPaint& skPain
t, |
346 const SkMatrix& viewMatrix, | 337 const SkMatrix& viewMatrix, |
347 const SkSurfaceProps& props, | 338 const SkSurfaceProps& props, |
348 const char text[], size_t byteLength, | 339 const char text[], size_t byteLength, |
349 const SkScalar pos[], int scalarsPerPositio
n, | 340 const SkScalar pos[], int scalarsPerPositio
n, |
350 const SkPoint& offset, const SkIRect& regio
nClipBounds) { | 341 const SkPoint& offset, const SkIRect& regio
nClipBounds) { |
351 if (fContext->abandoned()) { | 342 if (context->abandoned()) { |
352 return; | 343 return; |
353 } else if (this->canDraw(skPaint, viewMatrix, props)) { | 344 } else if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shade
rCaps())) { |
354 SkAutoTUnref<GrAtlasTextBlob> blob( | 345 SkAutoTUnref<GrAtlasTextBlob> blob( |
355 this->createDrawPosTextBlob(paint, skPaint, viewMatrix, props, | 346 CreateDrawPosTextBlob(context->getTextBlobCache(), |
356 text, byteLength, | 347 context->getBatchFontCache(), |
357 pos, scalarsPerPosition, | 348 *context->caps()->shaderCaps(), |
358 offset)); | 349 paint, skPaint, viewMatrix, props, |
359 blob->flushThrowaway(fContext, dc, props, fDistanceAdjustTable, skPaint,
paint, | 350 text, byteLength, |
| 351 pos, scalarsPerPosition, |
| 352 offset)); |
| 353 blob->flushThrowaway(context, dc, props, fDistanceAdjustTable, skPaint,
paint, |
360 clip, regionClipBounds); | 354 clip, regionClipBounds); |
361 return; | 355 return; |
362 } | 356 } |
363 | 357 |
364 // fall back to drawing as a path | 358 // fall back to drawing as a path |
365 GrTextUtils::DrawPosTextAsPath(fContext, dc, props, clip, skPaint, viewMatri
x, text, | 359 GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, skPaint, viewMatrix
, text, |
366 byteLength, pos, scalarsPerPosition, offset,
regionClipBounds); | 360 byteLength, pos, scalarsPerPosition, offset,
regionClipBounds); |
367 } | 361 } |
368 | 362 |
369 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 363 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
370 | 364 |
371 #ifdef GR_TEST_UTILS | 365 #ifdef GR_TEST_UTILS |
372 | 366 |
373 DRAW_BATCH_TEST_DEFINE(TextBlobBatch) { | 367 DRAW_BATCH_TEST_DEFINE(TextBlobBatch) { |
374 static uint32_t gContextID = SK_InvalidGenID; | 368 static uint32_t gContextID = SK_InvalidGenID; |
375 static GrAtlasTextContext* gTextContext = nullptr; | 369 static GrAtlasTextContext* gTextContext = nullptr; |
376 static SkSurfaceProps gSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType
); | 370 static SkSurfaceProps gSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType
); |
377 | 371 |
378 if (context->uniqueID() != gContextID) { | 372 if (context->uniqueID() != gContextID) { |
379 gContextID = context->uniqueID(); | 373 gContextID = context->uniqueID(); |
380 delete gTextContext; | 374 delete gTextContext; |
381 | 375 |
382 // We don't yet test the fall back to paths in the GrTextContext base cl
ass. This is mostly | 376 // We don't yet test the fall back to paths in the GrTextContext base cl
ass. This is mostly |
383 // because we don't really want to have a gpu device here. | 377 // because we don't really want to have a gpu device here. |
384 // We enable distance fields by twiddling a knob on the paint | 378 // We enable distance fields by twiddling a knob on the paint |
385 gTextContext = GrAtlasTextContext::Create(context); | 379 gTextContext = GrAtlasTextContext::Create(); |
386 } | 380 } |
387 | 381 |
388 // Setup dummy SkPaint / GrPaint | 382 // Setup dummy SkPaint / GrPaint |
389 GrColor color = GrRandomColor(random); | 383 GrColor color = GrRandomColor(random); |
390 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); | 384 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); |
391 SkPaint skPaint; | 385 SkPaint skPaint; |
392 skPaint.setColor(color); | 386 skPaint.setColor(color); |
393 skPaint.setLCDRenderText(random->nextBool()); | 387 skPaint.setLCDRenderText(random->nextBool()); |
394 skPaint.setAntiAlias(skPaint.isLCDRenderText() ? true : random->nextBool()); | 388 skPaint.setAntiAlias(skPaint.isLCDRenderText() ? true : random->nextBool()); |
395 skPaint.setSubpixelText(random->nextBool()); | 389 skPaint.setSubpixelText(random->nextBool()); |
396 | 390 |
397 GrPaint grPaint; | 391 GrPaint grPaint; |
398 if (!SkPaintToGrPaint(context, skPaint, viewMatrix, &grPaint)) { | 392 if (!SkPaintToGrPaint(context, skPaint, viewMatrix, &grPaint)) { |
399 SkFAIL("couldn't convert paint\n"); | 393 SkFAIL("couldn't convert paint\n"); |
400 } | 394 } |
401 | 395 |
402 const char* text = "The quick brown fox jumps over the lazy dog."; | 396 const char* text = "The quick brown fox jumps over the lazy dog."; |
403 int textLen = (int)strlen(text); | 397 int textLen = (int)strlen(text); |
404 | 398 |
405 // Setup clip | 399 // Setup clip |
406 GrClip clip; | 400 GrClip clip; |
407 | 401 |
408 // right now we don't handle textblobs, nor do we handle drawPosText. Since
we only | 402 // right now we don't handle textblobs, nor do we handle drawPosText. Since
we only |
409 // intend to test the batch with this unit test, that is okay. | 403 // intend to test the batch with this unit test, that is okay. |
410 SkAutoTUnref<GrAtlasTextBlob> blob( | 404 SkAutoTUnref<GrAtlasTextBlob> blob( |
411 gTextContext->createDrawTextBlob(grPaint, skPaint, viewMatrix, gSurf
aceProps, text, | 405 GrAtlasTextContext::CreateDrawTextBlob(context->getTextBlobCache(), |
412 static_cast<size_t>(textLen), 0, 0)
); | 406 context->getBatchFontCache(), |
| 407 *context->caps()->shaderCaps(), g
rPaint, skPaint, |
| 408 viewMatrix, |
| 409 gSurfaceProps, text, |
| 410 static_cast<size_t>(textLen), 0,
0)); |
413 | 411 |
414 // We'd like to be able to test this with random translations, but currently
the vertex | 412 // We'd like to be able to test this with random translations, but currently
the vertex |
415 // bounds and vertices will get out of sync | 413 // bounds and vertices will get out of sync |
416 SkScalar transX = 0.f;//SkIntToScalar(random->nextU()); | 414 SkScalar transX = 0.f;//SkIntToScalar(random->nextU()); |
417 SkScalar transY = 0.f;//SkIntToScalar(random->nextU()); | 415 SkScalar transY = 0.f;//SkIntToScalar(random->nextU()); |
418 return blob->test_createBatch(textLen, 0, 0, color, transX, transY, skPaint, | 416 return blob->test_createBatch(textLen, 0, 0, color, transX, transY, skPaint, |
419 gSurfaceProps, gTextContext->dfAdjustTable(), | 417 gSurfaceProps, gTextContext->dfAdjustTable(), |
420 context->getBatchFontCache()); | 418 context->getBatchFontCache()); |
421 } | 419 } |
422 | 420 |
423 #endif | 421 #endif |
OLD | NEW |