OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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 | 7 |
8 #include "GrStencilAndCoverTextContext.h" | 8 #include "GrStencilAndCoverTextContext.h" |
9 #include "GrBitmapTextContext.h" | 9 #include "GrBitmapTextContext.h" |
10 #include "GrDrawTarget.h" | 10 #include "GrDrawTarget.h" |
11 #include "GrGpu.h" | 11 #include "GrGpu.h" |
12 #include "GrPath.h" | 12 #include "GrPath.h" |
13 #include "GrPathRange.h" | 13 #include "GrPathRange.h" |
14 #include "SkAutoKern.h" | 14 #include "SkAutoKern.h" |
15 #include "SkDraw.h" | 15 #include "SkDraw.h" |
16 #include "SkDrawProcs.h" | 16 #include "SkDrawProcs.h" |
17 #include "SkGlyphCache.h" | 17 #include "SkGlyphCache.h" |
18 #include "SkGpuDevice.h" | 18 #include "SkGpuDevice.h" |
19 #include "SkPath.h" | 19 #include "SkPath.h" |
20 #include "SkTextMapStateProc.h" | 20 #include "SkTextMapStateProc.h" |
21 #include "SkTextFormatParams.h" | 21 #include "SkTextFormatParams.h" |
22 | 22 |
23 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext( | 23 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext( |
24 GrContext* context, const SkDeviceProperties& properties) | 24 GrContext* context, const SkDeviceProperties& properties) |
25 : GrTextContext(context, properties) | 25 : GrTextContext(context, properties) |
26 , fPendingGlyphCount(0) { | 26 , fStroke(SkStrokeRec::kFill_InitStyle) |
27 , fQueuedGlyphCount(0) | |
28 , fFallbackGlyphsIdx(kGlyphBufferSize) { | |
27 } | 29 } |
28 | 30 |
29 GrStencilAndCoverTextContext* GrStencilAndCoverTextContext::Create(GrContext* co ntext, | 31 GrStencilAndCoverTextContext* GrStencilAndCoverTextContext::Create(GrContext* co ntext, |
30 const SkDeviceP roperties& props) { | 32 const SkDeviceP roperties& props) { |
31 GrStencilAndCoverTextContext* textContext = SkNEW_ARGS(GrStencilAndCoverText Context, | 33 GrStencilAndCoverTextContext* textContext = SkNEW_ARGS(GrStencilAndCoverText Context, |
32 (context, props)); | 34 (context, props)); |
33 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, pro ps); | 35 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, pro ps); |
34 | 36 |
35 return textContext; | 37 return textContext; |
36 } | 38 } |
(...skipping 19 matching lines...) Expand all Loading... | |
56 return false; | 58 return false; |
57 } | 59 } |
58 | 60 |
59 // No color bitmap fonts. | 61 // No color bitmap fonts. |
60 SkScalerContext::Rec rec; | 62 SkScalerContext::Rec rec; |
61 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec); | 63 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec); |
62 return rec.getFormat() != SkMask::kARGB32_Format; | 64 return rec.getFormat() != SkMask::kARGB32_Format; |
63 } | 65 } |
64 | 66 |
65 void GrStencilAndCoverTextContext::onDrawText(const GrPaint& paint, | 67 void GrStencilAndCoverTextContext::onDrawText(const GrPaint& paint, |
66 const SkPaint& skPaint, | 68 const SkPaint& skPaint, |
67 const char text[], | 69 const char text[], |
68 size_t byteLength, | 70 size_t byteLength, |
69 SkScalar x, SkScalar y) { | 71 SkScalar x, SkScalar y) { |
70 SkASSERT(byteLength == 0 || text != NULL); | 72 SkASSERT(byteLength == 0 || text != NULL); |
71 | 73 |
72 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) { | 74 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) { |
73 return; | 75 return; |
74 } | 76 } |
75 | 77 |
76 // This is the slow path, mainly used by Skia unit tests. The other | 78 // This is the slow path, mainly used by Skia unit tests. The other |
77 // backends (8888, gpu, ...) use device-space dependent glyph caches. In | 79 // backends (8888, gpu, ...) use device-space dependent glyph caches. In |
78 // order to match the glyph positions that the other code paths produce, we | 80 // order to match the glyph positions that the other code paths produce, we |
79 // must also use device-space dependent glyph cache. This has the | 81 // must also use device-space dependent glyph cache. This has the |
80 // side-effect that the glyph shape outline will be in device-space, | 82 // side-effect that the glyph shape outline will be in device-space, |
81 // too. This in turn has the side-effect that NVPR can not stroke the paths, | 83 // too. This in turn has the side-effect that NVPR can not stroke the paths, |
82 // as the stroke in NVPR is defined in object-space. | 84 // as the stroke in NVPR is defined in object-space. |
83 // NOTE: here we have following coincidence that works at the moment: | 85 // NOTE: here we have following coincidence that works at the moment: |
84 // - When using the device-space glyphs, the transforms we pass to NVPR | 86 // - When using the device-space glyphs, the transforms we pass to NVPR |
85 // instanced drawing are the global transforms, and the view transform is | 87 // instanced drawing are the global transforms, and the view transform is |
86 // identity. NVPR can not use non-affine transforms in the instanced | 88 // identity. NVPR can not use non-affine transforms in the instanced |
87 // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it | 89 // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it |
88 // will turn off the use of device-space glyphs when perspective transforms | 90 // will turn off the use of device-space glyphs when perspective transforms |
89 // are in use. | 91 // are in use. |
90 | 92 |
91 this->init(paint, skPaint, byteLength, kMaxAccuracy_RenderMode); | 93 this->init(paint, skPaint, byteLength, kMaxAccuracy_RenderMode); |
92 | 94 |
93 // Transform our starting point. | 95 // Transform our starting point. |
94 if (fNeedsDeviceSpaceGlyphs) { | 96 if (fUsingDeviceSpaceGlyphs) { |
95 SkPoint loc; | 97 SkPoint loc; |
96 fContextInitialMatrix.mapXY(x, y, &loc); | 98 fContextInitialMatrix.mapXY(x, y, &loc); |
97 x = loc.fX; | 99 x = loc.fX; |
98 y = loc.fY; | 100 y = loc.fY; |
99 } | 101 } |
100 | 102 |
101 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 103 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
102 | 104 |
103 const char* stop = text + byteLength; | 105 const char* stop = text + byteLength; |
104 | 106 |
(...skipping 28 matching lines...) Expand all Loading... | |
133 SkAutoKern autokern; | 135 SkAutoKern autokern; |
134 | 136 |
135 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); | 137 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); |
136 | 138 |
137 SkFixed fx = SkScalarToFixed(x); | 139 SkFixed fx = SkScalarToFixed(x); |
138 SkFixed fy = SkScalarToFixed(y); | 140 SkFixed fy = SkScalarToFixed(y); |
139 while (text < stop) { | 141 while (text < stop) { |
140 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | 142 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); |
141 fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio); | 143 fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio); |
142 if (glyph.fWidth) { | 144 if (glyph.fWidth) { |
143 this->appendGlyph(glyph.getGlyphID(), SkFixedToScalar(fx), SkFixedTo Scalar(fy)); | 145 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedT oScalar(fy))); |
144 } | 146 } |
145 | 147 |
146 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio); | 148 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio); |
147 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio); | 149 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio); |
148 } | 150 } |
149 | 151 |
150 this->finish(); | 152 this->finish(); |
151 } | 153 } |
152 | 154 |
153 void GrStencilAndCoverTextContext::onDrawPosText(const GrPaint& paint, | 155 void GrStencilAndCoverTextContext::onDrawPosText(const GrPaint& paint, |
154 const SkPaint& skPaint, | 156 const SkPaint& skPaint, |
155 const char text[], | 157 const char text[], |
156 size_t byteLength, | 158 size_t byteLength, |
157 const SkScalar pos[], | 159 const SkScalar pos[], |
158 int scalarsPerPosition, | 160 int scalarsPerPosition, |
159 const SkPoint& offset) { | 161 const SkPoint& offset) { |
160 SkASSERT(byteLength == 0 || text != NULL); | 162 SkASSERT(byteLength == 0 || text != NULL); |
161 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 163 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
162 | 164 |
163 // nothing to draw | 165 // nothing to draw |
164 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) { | 166 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) { |
165 return; | 167 return; |
166 } | 168 } |
167 | 169 |
168 // This is the fast path. Here we do not bake in the device-transform to | 170 // This is the fast path. Here we do not bake in the device-transform to |
169 // the glyph outline or the advances. This is because we do not need to | 171 // the glyph outline or the advances. This is because we do not need to |
(...skipping 12 matching lines...) Expand all Loading... | |
182 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); | 184 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); |
183 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); | 185 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); |
184 while (text < stop) { | 186 while (text < stop) { |
185 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | 187 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); |
186 if (glyph.fWidth) { | 188 if (glyph.fWidth) { |
187 SkPoint tmsLoc; | 189 SkPoint tmsLoc; |
188 tmsProc(pos, &tmsLoc); | 190 tmsProc(pos, &tmsLoc); |
189 SkPoint loc; | 191 SkPoint loc; |
190 alignProc(tmsLoc, glyph, &loc); | 192 alignProc(tmsLoc, glyph, &loc); |
191 | 193 |
192 this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y()); | 194 this->appendGlyph(glyph, loc); |
193 } | 195 } |
194 pos += scalarsPerPosition; | 196 pos += scalarsPerPosition; |
195 } | 197 } |
196 | 198 |
197 this->finish(); | 199 this->finish(); |
198 } | 200 } |
199 | 201 |
200 static GrPathRange* get_gr_glyphs(GrContext* ctx, | 202 static GrPathRange* get_gr_glyphs(GrContext* ctx, |
201 const SkTypeface* typeface, | 203 const SkTypeface* typeface, |
202 const SkDescriptor* desc, | 204 const SkDescriptor* desc, |
(...skipping 22 matching lines...) Expand all Loading... | |
225 const SkPaint& skPaint, | 227 const SkPaint& skPaint, |
226 size_t textByteLength, | 228 size_t textByteLength, |
227 RenderMode renderMode) { | 229 RenderMode renderMode) { |
228 GrTextContext::init(paint, skPaint); | 230 GrTextContext::init(paint, skPaint); |
229 | 231 |
230 fContextInitialMatrix = fContext->getMatrix(); | 232 fContextInitialMatrix = fContext->getMatrix(); |
231 | 233 |
232 const bool otherBackendsWillDrawAsPaths = | 234 const bool otherBackendsWillDrawAsPaths = |
233 SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix); | 235 SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix); |
234 | 236 |
235 fNeedsDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths && | 237 fUsingDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths && |
236 kMaxAccuracy_RenderMode == renderMode && | 238 kMaxAccuracy_RenderMode == renderMode && |
237 SkToBool(fContextInitialMatrix.getType() & | 239 SkToBool(fContextInitialMatrix.getType() & |
238 (SkMatrix::kScale_Mask | SkMatrix::kAffin e_Mask)); | 240 (SkMatrix::kScale_Mask | SkMatrix::kAffin e_Mask)); |
239 | 241 |
240 if (fNeedsDeviceSpaceGlyphs) { | 242 if (fUsingDeviceSpaceGlyphs) { |
241 // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms. | 243 // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms. |
242 SkASSERT(!fContextInitialMatrix.hasPerspective()); | 244 SkASSERT(!fContextInitialMatrix.hasPerspective()); |
243 | 245 |
246 // The whole shape (including stroke) will be baked into the glyph outli nes. Make | |
247 // NVPR just fill the baked shapes. | |
248 fStroke = SkStrokeRec(SkStrokeRec::kFill_InitStyle); | |
249 | |
244 fTextRatio = fTextInverseRatio = 1.0f; | 250 fTextRatio = fTextInverseRatio = 1.0f; |
245 | 251 |
246 // Glyphs loaded by GPU path rendering have an inverted y-direction. | 252 // Glyphs loaded by GPU path rendering have an inverted y-direction. |
247 SkMatrix m; | 253 SkMatrix m; |
248 m.setScale(1, -1); | 254 m.setScale(1, -1); |
249 fContext->setMatrix(m); | 255 fContext->setMatrix(m); |
250 | 256 |
251 // Post-flip the initial matrix so we're left with just the flip after | 257 // Post-flip the initial matrix so we're left with just the flip after |
252 // the paint preConcats the inverse. | 258 // the paint preConcats the inverse. |
253 m = fContextInitialMatrix; | 259 m = fContextInitialMatrix; |
254 m.postScale(1, -1); | 260 m.postScale(1, -1); |
255 fPaint.localCoordChangeInverse(m); | 261 fPaint.localCoordChangeInverse(m); |
256 | 262 |
257 // The whole shape (including stroke) will be baked into the glyph outli nes. Make | |
258 // NVPR just fill the baked shapes. | |
259 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, &fContextInitialM atrix, false); | 263 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, &fContextInitialM atrix, false); |
260 fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTy peface(), | 264 fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTy peface(), |
261 &fGlyphCache->getDescriptor(), | 265 &fGlyphCache->getDescriptor(), fStroke); |
262 SkStrokeRec(SkStrokeRec::kFill_InitStyle)); | |
263 } else { | 266 } else { |
264 // Don't bake strokes into the glyph outlines. We will stroke the glyphs | 267 // Don't bake strokes into the glyph outlines. We will stroke the glyphs |
265 // using the GPU instead. This is the fast path. | 268 // using the GPU instead. This is the fast path. |
266 SkStrokeRec gpuStroke = SkStrokeRec(fSkPaint); | 269 fStroke = SkStrokeRec(fSkPaint); |
267 fSkPaint.setStyle(SkPaint::kFill_Style); | 270 fSkPaint.setStyle(SkPaint::kFill_Style); |
268 | 271 |
269 if (gpuStroke.isHairlineStyle()) { | 272 if (fStroke.isHairlineStyle()) { |
270 // Approximate hairline stroke. | 273 // Approximate hairline stroke. |
271 SkScalar strokeWidth = SK_Scalar1 / | 274 SkScalar strokeWidth = SK_Scalar1 / |
272 (SkVector::Make(fContextInitialMatrix.getScaleX(), | 275 (SkVector::Make(fContextInitialMatrix.getScaleX(), |
273 fContextInitialMatrix.getSkewY()).length()); | 276 fContextInitialMatrix.getSkewY()).length()); |
274 gpuStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/); | 277 fStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/); |
275 | 278 |
276 } else if (fSkPaint.isFakeBoldText() && | 279 } else if (fSkPaint.isFakeBoldText() && |
277 #ifdef SK_USE_FREETYPE_EMBOLDEN | 280 #ifdef SK_USE_FREETYPE_EMBOLDEN |
278 kMaxPerformance_RenderMode == renderMode && | 281 kMaxPerformance_RenderMode == renderMode && |
279 #endif | 282 #endif |
280 SkStrokeRec::kStroke_Style != gpuStroke.getStyle()) { | 283 SkStrokeRec::kStroke_Style != fStroke.getStyle()) { |
281 | 284 |
282 // Instead of baking fake bold into the glyph outlines, do it with t he GPU stroke. | 285 // Instead of baking fake bold into the glyph outlines, do it with t he GPU stroke. |
283 SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(), | 286 SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(), |
284 kStdFakeBoldInterpKeys, | 287 kStdFakeBoldInterpKeys, |
285 kStdFakeBoldInterpValues , | 288 kStdFakeBoldInterpValues , |
286 kStdFakeBoldInterpLength ); | 289 kStdFakeBoldInterpLength ); |
287 SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale); | 290 SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale); |
288 gpuStroke.setStrokeStyle(gpuStroke.needToApply() ? gpuStroke.getWidt h() + extra : extra, | 291 fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra, |
289 true /*strokeAndFill*/); | 292 true /*strokeAndFill*/); |
290 | 293 |
291 fSkPaint.setFakeBoldText(false); | 294 fSkPaint.setFakeBoldText(false); |
292 } | 295 } |
293 | 296 |
294 bool canUseRawPaths; | 297 bool canUseRawPaths; |
295 | 298 |
296 if (otherBackendsWillDrawAsPaths || kMaxPerformance_RenderMode == render Mode) { | 299 if (otherBackendsWillDrawAsPaths || kMaxPerformance_RenderMode == render Mode) { |
297 // We can draw the glyphs from canonically sized paths. | 300 // We can draw the glyphs from canonically sized paths. |
298 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeFor Paths; | 301 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeFor Paths; |
299 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.g etTextSize(); | 302 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.g etTextSize(); |
300 | 303 |
301 // Compensate for the glyphs being scaled by fTextRatio. | 304 // Compensate for the glyphs being scaled by fTextRatio. |
302 if (!gpuStroke.isFillStyle()) { | 305 if (!fStroke.isFillStyle()) { |
303 gpuStroke.setStrokeStyle(gpuStroke.getWidth() / fTextRatio, | 306 fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio, |
304 SkStrokeRec::kStrokeAndFill_Style == gp uStroke.getStyle()); | 307 SkStrokeRec::kStrokeAndFill_Style == fStr oke.getStyle()); |
305 } | 308 } |
306 | 309 |
307 fSkPaint.setLinearText(true); | 310 fSkPaint.setLinearText(true); |
308 fSkPaint.setLCDRenderText(false); | 311 fSkPaint.setLCDRenderText(false); |
309 fSkPaint.setAutohinted(false); | 312 fSkPaint.setAutohinted(false); |
310 fSkPaint.setHinting(SkPaint::kNo_Hinting); | 313 fSkPaint.setHinting(SkPaint::kNo_Hinting); |
311 fSkPaint.setSubpixelText(true); | 314 fSkPaint.setSubpixelText(true); |
312 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPat hs)); | 315 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPat hs)); |
313 | 316 |
314 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() && | 317 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() && |
315 0 == fSkPaint.getTextSkewX() && | 318 0 == fSkPaint.getTextSkewX() && |
316 !fSkPaint.isFakeBoldText() && | 319 !fSkPaint.isFakeBoldText() && |
317 !fSkPaint.isVerticalText(); | 320 !fSkPaint.isVerticalText(); |
318 } else { | 321 } else { |
319 fTextRatio = fTextInverseRatio = 1.0f; | 322 fTextRatio = fTextInverseRatio = 1.0f; |
320 canUseRawPaths = false; | 323 canUseRawPaths = false; |
321 } | 324 } |
322 | 325 |
323 SkMatrix textMatrix; | 326 SkMatrix textMatrix; |
324 // Glyphs loaded by GPU path rendering have an inverted y-direction. | 327 // Glyphs loaded by GPU path rendering have an inverted y-direction. |
325 textMatrix.setScale(fTextRatio, -fTextRatio); | 328 textMatrix.setScale(fTextRatio, -fTextRatio); |
326 fPaint.localCoordChange(textMatrix); | 329 fPaint.localCoordChange(textMatrix); |
327 fContext->concatMatrix(textMatrix); | 330 fContext->concatMatrix(textMatrix); |
328 | 331 |
329 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, NULL, false); | 332 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, NULL, false); |
330 fGlyphs = canUseRawPaths ? | 333 fGlyphs = canUseRawPaths ? |
331 get_gr_glyphs(fContext, fSkPaint.getTypeface(), NULL, gpuS troke) : | 334 get_gr_glyphs(fContext, fSkPaint.getTypeface(), NULL, fStr oke) : |
332 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->g etTypeface(), | 335 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->g etTypeface(), |
333 &fGlyphCache->getDescriptor(), gpuStroke); | 336 &fGlyphCache->getDescriptor(), fStroke); |
334 } | 337 } |
335 | 338 |
336 fStateRestore.set(&fDrawState); | 339 fStateRestore.set(&fDrawState); |
337 | 340 |
338 fDrawState.setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTa rget()); | 341 fDrawState.setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTa rget()); |
339 | 342 |
340 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, | 343 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, |
341 kZero_StencilOp, | 344 kZero_StencilOp, |
342 kZero_StencilOp, | 345 kZero_StencilOp, |
343 kNotEqual_StencilFunc, | 346 kNotEqual_StencilFunc, |
344 0xffff, | 347 0xffff, |
345 0x0000, | 348 0x0000, |
346 0xffff); | 349 0xffff); |
347 | 350 |
348 *fDrawState.stencil() = kStencilPass; | 351 *fDrawState.stencil() = kStencilPass; |
349 | 352 |
350 SkASSERT(0 == fPendingGlyphCount); | 353 SkASSERT(0 == fQueuedGlyphCount); |
354 SkASSERT(kGlyphBufferSize == fFallbackGlyphsIdx); | |
351 } | 355 } |
352 | 356 |
353 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x, float y) { | 357 bool GrStencilAndCoverTextContext::mapToFallbackContext(GrContext::AutoMatrix& a utoMatrix, |
354 if (fPendingGlyphCount >= kGlyphBufferSize) { | 358 SkMatrix* inverse) { |
359 // The current view matrix is flipped because GPU path rendering glyphs have an | |
360 // inverted y-direction. Unflip the view matrix for the fallback context. If using | |
361 // device-space glyphs, we'll also need to restore the original view matrix since | |
362 // we moved that transfomation into our local glyph cache for this scenario. Also | |
363 // track the inverse operation so the caller can unmap the paint and glyph p ositions. | |
364 if (fUsingDeviceSpaceGlyphs) { | |
365 autoMatrix.set(fContext, fContextInitialMatrix); | |
366 if (!fContextInitialMatrix.invert(inverse)) { | |
367 return false; | |
368 } | |
369 inverse->preScale(1, -1); | |
370 } else { | |
371 inverse->setScale(1, -1); | |
372 const SkMatrix& unflip = *inverse; // unflip is equal to its own inverse . | |
373 autoMatrix.setPreConcat(fContext, unflip); | |
374 } | |
375 return true; | |
376 } | |
377 | |
378 inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, cons t SkPoint& pos) { | |
379 if (fQueuedGlyphCount >= fFallbackGlyphsIdx) { | |
380 SkASSERT(fQueuedGlyphCount == fFallbackGlyphsIdx); | |
355 this->flush(); | 381 this->flush(); |
356 } | 382 } |
357 | 383 |
358 fIndexBuffer[fPendingGlyphCount] = glyphID; | 384 // Stick the glyphs we can't draw at the end of the buffer, growing backward s. |
Chris Dalton
2014/11/25 23:13:54
Looking for feedback here.
Growing backwards will
jvanverth1
2014/11/26 19:41:35
On one hand, drawing them in reverse order doesn't
| |
359 fTransformBuffer[2 * fPendingGlyphCount] = fTextInverseRatio * x; | 385 int index = (SkMask::kARGB32_Format == glyph.fMaskFormat) ? |
360 fTransformBuffer[2 * fPendingGlyphCount + 1] = -fTextInverseRatio * y; | 386 --fFallbackGlyphsIdx : fQueuedGlyphCount++; |
361 | 387 |
362 ++fPendingGlyphCount; | 388 fGlyphIndices[index] = glyph.getGlyphID(); |
389 fGlyphPositions[index].set(fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y()); | |
390 } | |
391 | |
392 static const SkScalar* get_xy_scalar_array(const SkPoint* pointArray) { | |
393 GR_STATIC_ASSERT(2 * sizeof(SkScalar) == sizeof(SkPoint)); | |
394 GR_STATIC_ASSERT(0 == offsetof(SkPoint, fX)); | |
395 | |
396 return &pointArray[0].fX; | |
363 } | 397 } |
364 | 398 |
365 void GrStencilAndCoverTextContext::flush() { | 399 void GrStencilAndCoverTextContext::flush() { |
366 if (0 == fPendingGlyphCount) { | 400 if (fQueuedGlyphCount > 0) { |
367 return; | 401 fDrawTarget->drawPaths(&fDrawState, fGlyphs, |
402 fGlyphIndices, GrPathRange::kU16_PathIndexType, | |
403 get_xy_scalar_array(fGlyphPositions), | |
404 GrPathRendering::kTranslate_PathTransformType, | |
405 fQueuedGlyphCount, GrPathRendering::kWinding_Fill Type); | |
406 | |
407 fQueuedGlyphCount = 0; | |
368 } | 408 } |
369 | 409 |
370 fDrawTarget->drawPaths(&fDrawState, fGlyphs, fIndexBuffer, GrPathRange::kU16 _PathIndexType, | 410 if (fFallbackGlyphsIdx < kGlyphBufferSize) { |
371 fTransformBuffer, GrPathRendering::kTranslate_PathTra nsformType, | 411 int fallbackGlyphCount = kGlyphBufferSize - fFallbackGlyphsIdx; |
372 fPendingGlyphCount, GrPathRendering::kWinding_FillTyp e); | |
373 | 412 |
374 fPendingGlyphCount = 0; | 413 GrPaint paintFallback(fPaint); |
414 | |
415 SkPaint skPaintFallback(fSkPaint); | |
416 if (!fUsingDeviceSpaceGlyphs) { | |
417 fStroke.applyToPaint(&skPaintFallback); | |
418 } | |
419 skPaintFallback.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for. | |
420 skPaintFallback.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | |
421 | |
422 GrContext::AutoMatrix autoMatrix; | |
423 SkMatrix inverse; | |
424 if (this->mapToFallbackContext(autoMatrix, &inverse)) { | |
425 paintFallback.localCoordChangeInverse(inverse); | |
426 inverse.mapPoints(&fGlyphPositions[fFallbackGlyphsIdx], fallbackGlyp hCount); | |
427 } | |
428 | |
429 fFallbackTextContext->drawPosText(paintFallback, skPaintFallback, | |
430 (char*)&fGlyphIndices[fFallbackGlyphsI dx], | |
431 2 * fallbackGlyphCount, | |
432 get_xy_scalar_array(&fGlyphPositions[f FallbackGlyphsIdx]), | |
433 2, SkPoint::Make(0, 0)); | |
434 | |
435 fFallbackGlyphsIdx = kGlyphBufferSize; | |
436 } | |
375 } | 437 } |
376 | 438 |
377 void GrStencilAndCoverTextContext::finish() { | 439 void GrStencilAndCoverTextContext::finish() { |
378 this->flush(); | 440 this->flush(); |
379 | 441 |
380 fGlyphs->unref(); | 442 fGlyphs->unref(); |
381 fGlyphs = NULL; | 443 fGlyphs = NULL; |
382 | 444 |
383 SkGlyphCache::AttachCache(fGlyphCache); | 445 SkGlyphCache::AttachCache(fGlyphCache); |
384 fGlyphCache = NULL; | 446 fGlyphCache = NULL; |
385 | 447 |
386 fDrawState.stencil()->setDisabled(); | 448 fDrawState.stencil()->setDisabled(); |
387 fStateRestore.set(NULL); | 449 fStateRestore.set(NULL); |
388 fContext->setMatrix(fContextInitialMatrix); | 450 fContext->setMatrix(fContextInitialMatrix); |
389 GrTextContext::finish(); | 451 GrTextContext::finish(); |
390 } | 452 } |
391 | 453 |
OLD | NEW |