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 "GrAtlasTextContext.h" | 9 #include "GrAtlasTextContext.h" |
10 #include "GrDrawContext.h" | 10 #include "GrDrawContext.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 return false; | 51 return false; |
52 } | 52 } |
53 if (skPaint.getMaskFilter()) { | 53 if (skPaint.getMaskFilter()) { |
54 return false; | 54 return false; |
55 } | 55 } |
56 if (SkPathEffect* pe = skPaint.getPathEffect()) { | 56 if (SkPathEffect* pe = skPaint.getPathEffect()) { |
57 if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) { | 57 if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) { |
58 return false; | 58 return false; |
59 } | 59 } |
60 } | 60 } |
61 | 61 // No hairlines. They would require new paths with customized strokes for ev
ery new draw matrix. |
62 // No hairlines unless we can map the 1 px width to the object space. | 62 return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrok
eWidth(); |
63 if (skPaint.getStyle() == SkPaint::kStroke_Style | |
64 && skPaint.getStrokeWidth() == 0 | |
65 && viewMatrix.hasPerspective()) { | |
66 return false; | |
67 } | |
68 | |
69 // No color bitmap fonts. | |
70 SkScalerContext::Rec rec; | |
71 SkScalerContext::MakeRec(skPaint, &fSurfaceProps, nullptr, &rec); | |
72 return rec.getFormat() != SkMask::kARGB32_Format; | |
73 } | 63 } |
74 | 64 |
75 void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget*
rt, | 65 void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget*
rt, |
76 const GrClip& clip, | 66 const GrClip& clip, |
77 const GrPaint& paint, | 67 const GrPaint& paint, |
78 const SkPaint& skPaint, | 68 const SkPaint& skPaint, |
79 const SkMatrix& viewMatrix, | 69 const SkMatrix& viewMatrix, |
80 const char text[], | 70 const char text[], |
81 size_t byteLength, | 71 size_t byteLength, |
82 SkScalar x, SkScalar y, | 72 SkScalar x, SkScalar y, |
83 const SkIRect& regionClipBounds) { | 73 const SkIRect& regionClipBounds) { |
84 SkASSERT(byteLength == 0 || text != nullptr); | 74 SkASSERT(byteLength == 0 || text != nullptr); |
85 | 75 |
86 if (text == nullptr || byteLength == 0 /*|| fRC->isEmpty()*/) { | 76 if (text == nullptr || byteLength == 0 /*|| fRC->isEmpty()*/) { |
87 return; | 77 return; |
88 } | 78 } |
89 | 79 |
90 // This is the slow path, mainly used by Skia unit tests. The other | 80 this->init(rt, clip, paint, skPaint, byteLength, viewMatrix, regionClipBound
s); |
91 // backends (8888, gpu, ...) use device-space dependent glyph caches. In | |
92 // order to match the glyph positions that the other code paths produce, we | |
93 // must also use device-space dependent glyph cache. This has the | |
94 // side-effect that the glyph shape outline will be in device-space, | |
95 // too. This in turn has the side-effect that NVPR can not stroke the paths, | |
96 // as the stroke in NVPR is defined in object-space. | |
97 // NOTE: here we have following coincidence that works at the moment: | |
98 // - When using the device-space glyphs, the transforms we pass to NVPR | |
99 // instanced drawing are the global transforms, and the view transform is | |
100 // identity. NVPR can not use non-affine transforms in the instanced | |
101 // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it | |
102 // will turn off the use of device-space glyphs when perspective transforms | |
103 // are in use. | |
104 | |
105 this->init(rt, clip, paint, skPaint, byteLength, kMaxAccuracy_RenderMode, vi
ewMatrix, | |
106 regionClipBounds); | |
107 | |
108 // Transform our starting point. | |
109 if (fUsingDeviceSpaceGlyphs) { | |
110 SkPoint loc; | |
111 fContextInitialMatrix.mapXY(x, y, &loc); | |
112 x = loc.fX; | |
113 y = loc.fY; | |
114 } | |
115 | 81 |
116 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 82 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
117 | 83 |
118 const char* stop = text + byteLength; | 84 const char* stop = text + byteLength; |
119 | 85 |
120 // Measure first if needed. | 86 // Measure first if needed. |
121 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { | 87 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { |
122 SkFixed stopX = 0; | 88 SkFixed stopX = 0; |
123 SkFixed stopY = 0; | 89 SkFixed stopY = 0; |
124 | 90 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 const SkPoint& offset, | 143 const SkPoint& offset, |
178 const SkIRect& regionClipBounds
) { | 144 const SkIRect& regionClipBounds
) { |
179 SkASSERT(byteLength == 0 || text != nullptr); | 145 SkASSERT(byteLength == 0 || text != nullptr); |
180 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 146 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
181 | 147 |
182 // nothing to draw | 148 // nothing to draw |
183 if (text == nullptr || byteLength == 0/* || fRC->isEmpty()*/) { | 149 if (text == nullptr || byteLength == 0/* || fRC->isEmpty()*/) { |
184 return; | 150 return; |
185 } | 151 } |
186 | 152 |
187 // This is the fast path. Here we do not bake in the device-transform to | 153 this->init(rt, clip, paint, skPaint, byteLength, viewMatrix, regionClipBound
s); |
188 // the glyph outline or the advances. This is because we do not need to | |
189 // position the glyphs at all, since the caller has done the positioning. | |
190 // The positioning is based on SkPaint::measureText of individual | |
191 // glyphs. That already uses glyph cache without device transforms. Device | |
192 // transform is not part of SkPaint::measureText API, and thus we use the | |
193 // same glyphs as what were measured. | |
194 | |
195 this->init(rt, clip, paint, skPaint, byteLength, kMaxPerformance_RenderMode,
viewMatrix, | |
196 regionClipBounds); | |
197 | 154 |
198 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 155 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
199 | 156 |
200 const char* stop = text + byteLength; | 157 const char* stop = text + byteLength; |
201 | 158 |
202 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); | 159 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); |
203 SkTextAlignProc alignProc(fSkPaint.getTextAlign()); | 160 SkTextAlignProc alignProc(fSkPaint.getTextAlign()); |
204 while (text < stop) { | 161 while (text < stop) { |
205 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | 162 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); |
206 if (glyph.fWidth) { | 163 if (glyph.fWidth) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 } | 201 } |
245 | 202 |
246 return glyphs.detach(); | 203 return glyphs.detach(); |
247 } | 204 } |
248 | 205 |
249 void GrStencilAndCoverTextContext::init(GrRenderTarget* rt, | 206 void GrStencilAndCoverTextContext::init(GrRenderTarget* rt, |
250 const GrClip& clip, | 207 const GrClip& clip, |
251 const GrPaint& paint, | 208 const GrPaint& paint, |
252 const SkPaint& skPaint, | 209 const SkPaint& skPaint, |
253 size_t textByteLength, | 210 size_t textByteLength, |
254 RenderMode renderMode, | |
255 const SkMatrix& viewMatrix, | 211 const SkMatrix& viewMatrix, |
256 const SkIRect& regionClipBounds) { | 212 const SkIRect& regionClipBounds) { |
257 fClip = clip; | 213 fClip = clip; |
258 | 214 |
259 fRenderTarget.reset(SkRef(rt)); | 215 fRenderTarget.reset(SkRef(rt)); |
260 | 216 |
261 fRegionClipBounds = regionClipBounds; | 217 fRegionClipBounds = regionClipBounds; |
262 fClip.getConservativeBounds(fRenderTarget->width(), fRenderTarget->height(),
&fClipRect); | 218 fClip.getConservativeBounds(fRenderTarget->width(), fRenderTarget->height(),
&fClipRect); |
263 | 219 |
264 fPaint = paint; | 220 fPaint = paint; |
265 fSkPaint = skPaint; | 221 fSkPaint = skPaint; |
266 | 222 |
267 fContextInitialMatrix = viewMatrix; | 223 // Don't bake strokes into the glyph outlines. We will stroke the glyphs usi
ng the GPU instead. |
268 fViewMatrix = viewMatrix; | 224 fStroke = GrStrokeInfo(fSkPaint); |
269 fLocalMatrix = SkMatrix::I(); | 225 fSkPaint.setStyle(SkPaint::kFill_Style); |
270 | 226 |
271 const bool otherBackendsWillDrawAsPaths = | 227 SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. |
272 SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix); | |
273 | 228 |
274 fUsingDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths && | 229 if (fSkPaint.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getSt
yle()) { |
275 kMaxAccuracy_RenderMode == renderMode && | 230 // Instead of baking fake bold into the glyph outlines, do it with the G
PU stroke. |
276 SkToBool(fContextInitialMatrix.getType() & | 231 SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(), |
277 (SkMatrix::kScale_Mask | SkMatrix::kAffin
e_Mask)); | 232 kStdFakeBoldInterpKeys, |
| 233 kStdFakeBoldInterpValues, |
| 234 kStdFakeBoldInterpLength); |
| 235 SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale); |
| 236 fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extr
a : extra, |
| 237 true /*strokeAndFill*/); |
278 | 238 |
279 if (fUsingDeviceSpaceGlyphs) { | 239 fSkPaint.setFakeBoldText(false); |
280 // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms. | 240 } |
281 SkASSERT(!fContextInitialMatrix.hasPerspective()); | |
282 | 241 |
283 // The whole shape (including stroke) will be baked into the glyph outli
nes. Make | 242 bool canUseRawPaths; |
284 // NVPR just fill the baked shapes. | 243 if (!fStroke.isDashed()) { |
285 fStroke = GrStrokeInfo(SkStrokeRec::kFill_InitStyle); | 244 // We can draw the glyphs from canonically sized paths. |
| 245 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPath
s; |
| 246 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTe
xtSize(); |
286 | 247 |
287 fTextRatio = fTextInverseRatio = 1.0f; | 248 // Compensate for the glyphs being scaled by fTextRatio. |
288 | 249 if (!fStroke.isFillStyle()) { |
289 // Glyphs loaded by GPU path rendering have an inverted y-direction. | 250 fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio, |
290 SkMatrix m; | 251 SkStrokeRec::kStrokeAndFill_Style == fStroke.
getStyle()); |
291 m.setScale(1, -1); | |
292 fViewMatrix = m; | |
293 | |
294 // Post-flip the initial matrix so we're left with just the flip after | |
295 // the paint preConcats the inverse. | |
296 m = fContextInitialMatrix; | |
297 m.postScale(1, -1); | |
298 if (!m.invert(&fLocalMatrix)) { | |
299 SkDebugf("Not invertible!\n"); | |
300 return; | |
301 } | 252 } |
302 | 253 |
303 fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, &fContextInitialMatri
x, | 254 fSkPaint.setLinearText(true); |
304 true /*ignoreGamma*/); | 255 fSkPaint.setLCDRenderText(false); |
305 fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTy
peface(), | 256 fSkPaint.setAutohinted(false); |
306 &fGlyphCache->getDescriptor(), fStroke); | 257 fSkPaint.setHinting(SkPaint::kNo_Hinting); |
| 258 fSkPaint.setSubpixelText(true); |
| 259 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths))
; |
| 260 |
| 261 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() && |
| 262 0 == fSkPaint.getTextSkewX() && |
| 263 !fSkPaint.isFakeBoldText() && |
| 264 !fSkPaint.isVerticalText(); |
307 } else { | 265 } else { |
308 // Don't bake strokes into the glyph outlines. We will stroke the glyphs | 266 fTextRatio = fTextInverseRatio = 1.0f; |
309 // using the GPU instead. This is the fast path. | 267 canUseRawPaths = false; |
310 fStroke = GrStrokeInfo(fSkPaint); | |
311 fSkPaint.setStyle(SkPaint::kFill_Style); | |
312 | |
313 if (fStroke.isHairlineStyle()) { | |
314 // Approximate hairline stroke. | |
315 SkScalar strokeWidth = SK_Scalar1 / | |
316 (SkVector::Make(fContextInitialMatrix.getScaleX(), | |
317 fContextInitialMatrix.getSkewY()).length()); | |
318 fStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/); | |
319 | |
320 } else if (fSkPaint.isFakeBoldText() && | |
321 #ifdef SK_USE_FREETYPE_EMBOLDEN | |
322 kMaxPerformance_RenderMode == renderMode && | |
323 #endif | |
324 SkStrokeRec::kStroke_Style != fStroke.getStyle()) { | |
325 | |
326 // Instead of baking fake bold into the glyph outlines, do it with t
he GPU stroke. | |
327 SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(), | |
328 kStdFakeBoldInterpKeys, | |
329 kStdFakeBoldInterpValues
, | |
330 kStdFakeBoldInterpLength
); | |
331 SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale); | |
332 fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() +
extra : extra, | |
333 true /*strokeAndFill*/); | |
334 | |
335 fSkPaint.setFakeBoldText(false); | |
336 } | |
337 | |
338 bool canUseRawPaths; | |
339 if (!fStroke.isDashed() && (otherBackendsWillDrawAsPaths || | |
340 kMaxPerformance_RenderMode == renderMode)) { | |
341 // We can draw the glyphs from canonically sized paths. | |
342 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeFor
Paths; | |
343 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.g
etTextSize(); | |
344 | |
345 // Compensate for the glyphs being scaled by fTextRatio. | |
346 if (!fStroke.isFillStyle()) { | |
347 fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio, | |
348 SkStrokeRec::kStrokeAndFill_Style == fStr
oke.getStyle()); | |
349 } | |
350 | |
351 fSkPaint.setLinearText(true); | |
352 fSkPaint.setLCDRenderText(false); | |
353 fSkPaint.setAutohinted(false); | |
354 fSkPaint.setHinting(SkPaint::kNo_Hinting); | |
355 fSkPaint.setSubpixelText(true); | |
356 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPat
hs)); | |
357 | |
358 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() && | |
359 0 == fSkPaint.getTextSkewX() && | |
360 !fSkPaint.isFakeBoldText() && | |
361 !fSkPaint.isVerticalText(); | |
362 } else { | |
363 fTextRatio = fTextInverseRatio = 1.0f; | |
364 canUseRawPaths = false; | |
365 } | |
366 | |
367 SkMatrix textMatrix; | |
368 // Glyphs loaded by GPU path rendering have an inverted y-direction. | |
369 textMatrix.setScale(fTextRatio, -fTextRatio); | |
370 fViewMatrix.preConcat(textMatrix); | |
371 fLocalMatrix = textMatrix; | |
372 | |
373 fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, nullptr, true /*ignor
eGamma*/); | |
374 fGlyphs = canUseRawPaths ? | |
375 get_gr_glyphs(fContext, fSkPaint.getTypeface(), nullptr, f
Stroke) : | |
376 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->g
etTypeface(), | |
377 &fGlyphCache->getDescriptor(), fStroke); | |
378 } | 268 } |
379 | 269 |
380 } | 270 fViewMatrix = viewMatrix; |
| 271 fViewMatrix.preScale(fTextRatio, fTextRatio); |
| 272 fLocalMatrix.setScale(fTextRatio, fTextRatio); |
381 | 273 |
382 bool GrStencilAndCoverTextContext::mapToFallbackContext(SkMatrix* inverse) { | 274 fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, nullptr, true /*ignoreGam
ma*/); |
383 // The current view matrix is flipped because GPU path rendering glyphs have
an | 275 fGlyphs = canUseRawPaths ? |
384 // inverted y-direction. Unflip the view matrix for the fallback context. If
using | 276 get_gr_glyphs(fContext, fSkPaint.getTypeface(), nullptr, fStro
ke) : |
385 // device-space glyphs, we'll also need to restore the original view matrix
since | 277 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTy
peface(), |
386 // we moved that transfomation into our local glyph cache for this scenario.
Also | 278 &fGlyphCache->getDescriptor(), fStroke); |
387 // track the inverse operation so the caller can unmap the paint and glyph p
ositions. | |
388 if (fUsingDeviceSpaceGlyphs) { | |
389 fViewMatrix = fContextInitialMatrix; | |
390 if (!fContextInitialMatrix.invert(inverse)) { | |
391 return false; | |
392 } | |
393 inverse->preScale(1, -1); | |
394 } else { | |
395 inverse->setScale(1, -1); | |
396 const SkMatrix& unflip = *inverse; // unflip is equal to its own inverse
. | |
397 fViewMatrix.preConcat(unflip); | |
398 } | |
399 return true; | |
400 } | 279 } |
401 | 280 |
402 inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, cons
t SkPoint& pos) { | 281 inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, cons
t SkPoint& pos) { |
403 // Stick the glyphs we can't draw into the fallback arrays. | 282 // Stick the glyphs we can't draw into the fallback arrays. |
404 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { | 283 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { |
405 fFallbackIndices.push_back(glyph.getGlyphID()); | 284 fFallbackIndices.push_back(glyph.getGlyphID()); |
406 fFallbackPositions.push_back().set(fTextInverseRatio * pos.x(), | 285 fFallbackPositions.push_back(pos); |
407 -fTextInverseRatio * pos.y()); | |
408 } else { | 286 } else { |
409 // TODO: infer the reserve count from the text length. | 287 // TODO: infer the reserve count from the text length. |
410 if (!fDraw) { | 288 if (!fDraw) { |
411 fDraw = GrPathRangeDraw::Create(fGlyphs, | 289 fDraw = GrPathRangeDraw::Create(fGlyphs, |
412 GrPathRendering::kTranslate_PathTran
sformType, | 290 GrPathRendering::kTranslate_PathTran
sformType, |
413 64); | 291 64); |
414 } | 292 } |
415 float translate[] = { fTextInverseRatio * pos.x(), -fTextInverseRatio *
pos.y() }; | 293 float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * p
os.y() }; |
416 fDraw->append(glyph.getGlyphID(), translate); | 294 fDraw->append(glyph.getGlyphID(), translate); |
417 } | 295 } |
418 } | 296 } |
419 | 297 |
420 static const SkScalar* get_xy_scalar_array(const SkPoint* pointArray) { | |
421 GR_STATIC_ASSERT(2 * sizeof(SkScalar) == sizeof(SkPoint)); | |
422 GR_STATIC_ASSERT(0 == offsetof(SkPoint, fX)); | |
423 | |
424 return &pointArray[0].fX; | |
425 } | |
426 | |
427 void GrStencilAndCoverTextContext::flush(GrDrawContext* dc) { | 298 void GrStencilAndCoverTextContext::flush(GrDrawContext* dc) { |
428 if (fDraw) { | 299 if (fDraw) { |
429 SkASSERT(fDraw->count()); | 300 SkASSERT(fDraw->count()); |
430 | 301 |
431 // We should only be flushing about once every run. However, if this im
pacts performance | 302 // We should only be flushing about once every run. However, if this im
pacts performance |
432 // we could move the creation of the GrPipelineBuilder earlier. | 303 // we could move the creation of the GrPipelineBuilder earlier. |
433 GrPipelineBuilder pipelineBuilder(fPaint, fRenderTarget, fClip); | 304 GrPipelineBuilder pipelineBuilder(fPaint, fRenderTarget, fClip); |
434 SkASSERT(fRenderTarget->isStencilBufferMultisampled() || !fPaint.isAntiA
lias()); | 305 SkASSERT(fRenderTarget->isStencilBufferMultisampled() || !fPaint.isAntiA
lias()); |
435 pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, fPaint.is
AntiAlias()); | 306 pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, fPaint.is
AntiAlias()); |
436 | 307 |
437 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, | 308 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, |
438 kZero_StencilOp, | 309 kZero_StencilOp, |
439 kKeep_StencilOp, | 310 kKeep_StencilOp, |
440 kNotEqual_StencilFunc, | 311 kNotEqual_StencilFunc, |
441 0xffff, | 312 0xffff, |
442 0x0000, | 313 0x0000, |
443 0xffff); | 314 0xffff); |
444 | 315 |
445 *pipelineBuilder.stencil() = kStencilPass; | 316 *pipelineBuilder.stencil() = kStencilPass; |
446 | 317 |
447 dc->drawPathsFromRange(&pipelineBuilder, fViewMatrix, fLocalMatrix, fPai
nt.getColor(), | 318 dc->drawPathsFromRange(&pipelineBuilder, fViewMatrix, fLocalMatrix, fPai
nt.getColor(), |
448 fDraw, GrPathRendering::kWinding_FillType); | 319 fDraw, GrPathRendering::kWinding_FillType); |
449 fDraw->unref(); | 320 fDraw->unref(); |
450 fDraw = nullptr; | 321 fDraw = nullptr; |
451 } | 322 } |
452 | 323 |
453 if (fFallbackIndices.count()) { | 324 if (fFallbackIndices.count()) { |
454 SkASSERT(fFallbackPositions.count() == fFallbackIndices.count()); | 325 SkASSERT(fFallbackPositions.count() == fFallbackIndices.count()); |
455 GrPaint paintFallback(fPaint); | |
456 | 326 |
457 SkPaint skPaintFallback(fSkPaint); | 327 SkPaint fallbackSkPaint(fSkPaint); |
458 if (!fUsingDeviceSpaceGlyphs) { | 328 fStroke.applyToPaint(&fallbackSkPaint); |
459 fStroke.applyToPaint(&skPaintFallback); | 329 if (!fStroke.isFillStyle()) { |
| 330 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); |
460 } | 331 } |
461 skPaintFallback.setTextAlign(SkPaint::kLeft_Align); // Align has already
been accounted for. | 332 fallbackSkPaint.setTextAlign(SkPaint::kLeft_Align); // Align has already
been accounted for. |
462 skPaintFallback.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 333 fallbackSkPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| 334 // No need for subpixel positioning with bitmap glyphs. TODO: revisit if
non-bitmap color |
| 335 // glyphs show up and https://code.google.com/p/skia/issues/detail?id=44
08 gets resolved. |
| 336 fallbackSkPaint.setSubpixelText(false); |
| 337 fallbackSkPaint.setTextSize(fSkPaint.getTextSize() * fTextRatio); |
463 | 338 |
464 SkMatrix inverse; | 339 SkMatrix fallbackMatrix(fViewMatrix); |
465 if (this->mapToFallbackContext(&inverse)) { | 340 fallbackMatrix.preScale(fTextInverseRatio, fTextInverseRatio); |
466 inverse.mapPoints(fFallbackPositions.begin(), fFallbackPositions.cou
nt()); | |
467 } | |
468 | 341 |
469 fFallbackTextContext->drawPosText(dc, fRenderTarget, fClip, paintFallbac
k, skPaintFallback, | 342 fFallbackTextContext->drawPosText(dc, fRenderTarget, fClip, fPaint, fall
backSkPaint, |
470 fViewMatrix, (char*)fFallbackIndices.b
egin(), | 343 fallbackMatrix, (char*)fFallbackIndice
s.begin(), |
471 sizeof(uint16_t) * fFallbackIndices.co
unt(), | 344 sizeof(uint16_t) * fFallbackIndices.co
unt(), |
472 get_xy_scalar_array(fFallbackPositions
.begin()), | 345 fFallbackPositions[0].asScalars(), 2,
SkPoint::Make(0, 0), |
473 2, SkPoint::Make(0, 0), fRegionClipBou
nds); | 346 fRegionClipBounds); |
474 fFallbackIndices.reset(); | 347 fFallbackIndices.reset(); |
475 fFallbackPositions.reset(); | 348 fFallbackPositions.reset(); |
476 } | 349 } |
477 } | 350 } |
478 | 351 |
479 void GrStencilAndCoverTextContext::finish(GrDrawContext* dc) { | 352 void GrStencilAndCoverTextContext::finish(GrDrawContext* dc) { |
480 this->flush(dc); | 353 this->flush(dc); |
481 | 354 |
482 SkASSERT(!fDraw); | 355 SkASSERT(!fDraw); |
483 SkASSERT(!fFallbackIndices.count()); | 356 SkASSERT(!fFallbackIndices.count()); |
484 SkASSERT(!fFallbackPositions.count()); | 357 SkASSERT(!fFallbackPositions.count()); |
485 | 358 |
486 fGlyphs->unref(); | 359 fGlyphs->unref(); |
487 fGlyphs = nullptr; | 360 fGlyphs = nullptr; |
488 | 361 |
489 SkGlyphCache::AttachCache(fGlyphCache); | 362 SkGlyphCache::AttachCache(fGlyphCache); |
490 fGlyphCache = nullptr; | 363 fGlyphCache = nullptr; |
491 | |
492 fViewMatrix = fContextInitialMatrix; | |
493 } | 364 } |
OLD | NEW |