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" |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 // too. This in turn has the side-effect that NVPR can not stroke the paths, | 81 // 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. | 82 // as the stroke in NVPR is defined in object-space. |
83 // NOTE: here we have following coincidence that works at the moment: | 83 // NOTE: here we have following coincidence that works at the moment: |
84 // - When using the device-space glyphs, the transforms we pass to NVPR | 84 // - When using the device-space glyphs, the transforms we pass to NVPR |
85 // instanced drawing are the global transforms, and the view transform is | 85 // instanced drawing are the global transforms, and the view transform is |
86 // identity. NVPR can not use non-affine transforms in the instanced | 86 // identity. NVPR can not use non-affine transforms in the instanced |
87 // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it | 87 // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it |
88 // will turn off the use of device-space glyphs when perspective transforms | 88 // will turn off the use of device-space glyphs when perspective transforms |
89 // are in use. | 89 // are in use. |
90 | 90 |
91 this->init(paint, skPaint, byteLength, kMaxAccuracy_RenderMode, SkPoint::Mak
e(0, 0)); | 91 this->init(paint, skPaint, byteLength, kMaxAccuracy_RenderMode); |
92 | 92 |
93 // Transform our starting point. | 93 // Transform our starting point. |
94 if (fNeedsDeviceSpaceGlyphs) { | 94 if (fNeedsDeviceSpaceGlyphs) { |
95 SkPoint loc; | 95 SkPoint loc; |
96 fContextInitialMatrix.mapXY(x, y, &loc); | 96 fContextInitialMatrix.mapXY(x, y, &loc); |
97 x = loc.fX; | 97 x = loc.fX; |
98 y = loc.fY; | 98 y = loc.fY; |
99 } | 99 } |
100 | 100 |
101 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 101 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
102 | 102 |
103 fTransformType = GrPathRendering::kTranslate_PathTransformType; | |
104 | |
105 const char* stop = text + byteLength; | 103 const char* stop = text + byteLength; |
106 | 104 |
107 // Measure first if needed. | 105 // Measure first if needed. |
108 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { | 106 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { |
109 SkFixed stopX = 0; | 107 SkFixed stopX = 0; |
110 SkFixed stopY = 0; | 108 SkFixed stopY = 0; |
111 | 109 |
112 const char* textPtr = text; | 110 const char* textPtr = text; |
113 while (textPtr < stop) { | 111 while (textPtr < stop) { |
114 // We don't need x, y here, since all subpixel variants will have th
e | 112 // We don't need x, y here, since all subpixel variants will have th
e |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 } | 166 } |
169 | 167 |
170 // This is the fast path. Here we do not bake in the device-transform to | 168 // This is the fast path. Here we do not bake in the device-transform to |
171 // the glyph outline or the advances. This is because we do not need to | 169 // the glyph outline or the advances. This is because we do not need to |
172 // position the glyphs at all, since the caller has done the positioning. | 170 // position the glyphs at all, since the caller has done the positioning. |
173 // The positioning is based on SkPaint::measureText of individual | 171 // The positioning is based on SkPaint::measureText of individual |
174 // glyphs. That already uses glyph cache without device transforms. Device | 172 // glyphs. That already uses glyph cache without device transforms. Device |
175 // transform is not part of SkPaint::measureText API, and thus we use the | 173 // transform is not part of SkPaint::measureText API, and thus we use the |
176 // same glyphs as what were measured. | 174 // same glyphs as what were measured. |
177 | 175 |
178 this->init(paint, skPaint, byteLength, kMaxPerformance_RenderMode, offset); | 176 this->init(paint, skPaint, byteLength, kMaxPerformance_RenderMode); |
179 | 177 |
180 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 178 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
181 | 179 |
182 const char* stop = text + byteLength; | 180 const char* stop = text + byteLength; |
183 | 181 |
184 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { | 182 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); |
185 if (1 == scalarsPerPosition) { | 183 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); |
186 fTransformType = GrPathRendering::kTranslateX_PathTransformType; | 184 while (text < stop) { |
187 while (text < stop) { | 185 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); |
188 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | 186 if (glyph.fWidth) { |
189 if (glyph.fWidth) { | 187 SkPoint tmsLoc; |
190 this->appendGlyph(glyph.getGlyphID(), *pos); | 188 tmsProc(pos, &tmsLoc); |
191 } | 189 SkPoint loc; |
192 pos++; | 190 alignProc(tmsLoc, glyph, &loc); |
193 } | 191 |
194 } else { | 192 this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y()); |
195 SkASSERT(2 == scalarsPerPosition); | |
196 fTransformType = GrPathRendering::kTranslate_PathTransformType; | |
197 while (text < stop) { | |
198 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | |
199 if (glyph.fWidth) { | |
200 this->appendGlyph(glyph.getGlyphID(), pos[0], pos[1]); | |
201 } | |
202 pos += 2; | |
203 } | |
204 } | 193 } |
205 } else { | 194 pos += scalarsPerPosition; |
206 fTransformType = GrPathRendering::kTranslate_PathTransformType; | |
207 SkTextMapStateProc tmsProc(SkMatrix::I(), SkPoint::Make(0, 0), scalarsPe
rPosition); | |
208 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); | |
209 while (text < stop) { | |
210 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | |
211 if (glyph.fWidth) { | |
212 SkPoint tmsLoc; | |
213 tmsProc(pos, &tmsLoc); | |
214 SkPoint loc; | |
215 alignProc(tmsLoc, glyph, &loc); | |
216 | |
217 this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y()); | |
218 } | |
219 pos += scalarsPerPosition; | |
220 } | |
221 } | 195 } |
222 | 196 |
223 this->finish(); | 197 this->finish(); |
224 } | 198 } |
225 | 199 |
226 static GrPathRange* get_gr_glyphs(GrContext* ctx, | 200 static GrPathRange* get_gr_glyphs(GrContext* ctx, |
227 const SkTypeface* typeface, | 201 const SkTypeface* typeface, |
228 const SkDescriptor* desc, | 202 const SkDescriptor* desc, |
229 const SkStrokeRec& stroke) { | 203 const SkStrokeRec& stroke) { |
230 static const GrCacheID::Domain gGlyphsDomain = GrCacheID::GenerateDomain(); | 204 static const GrCacheID::Domain gGlyphsDomain = GrCacheID::GenerateDomain(); |
(...skipping 12 matching lines...) Expand all Loading... |
243 glyphs.reset(ctx->getGpu()->pathRendering()->createGlyphs(typeface, desc
, stroke)); | 217 glyphs.reset(ctx->getGpu()->pathRendering()->createGlyphs(typeface, desc
, stroke)); |
244 ctx->addResourceToCache(resourceKey, glyphs); | 218 ctx->addResourceToCache(resourceKey, glyphs); |
245 } | 219 } |
246 | 220 |
247 return glyphs.detach(); | 221 return glyphs.detach(); |
248 } | 222 } |
249 | 223 |
250 void GrStencilAndCoverTextContext::init(const GrPaint& paint, | 224 void GrStencilAndCoverTextContext::init(const GrPaint& paint, |
251 const SkPaint& skPaint, | 225 const SkPaint& skPaint, |
252 size_t textByteLength, | 226 size_t textByteLength, |
253 RenderMode renderMode, | 227 RenderMode renderMode) { |
254 const SkPoint& textTranslate) { | |
255 GrTextContext::init(paint, skPaint); | 228 GrTextContext::init(paint, skPaint); |
256 | 229 |
257 fContextInitialMatrix = fContext->getMatrix(); | 230 fContextInitialMatrix = fContext->getMatrix(); |
258 | 231 |
259 const bool otherBackendsWillDrawAsPaths = | 232 const bool otherBackendsWillDrawAsPaths = |
260 SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix); | 233 SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix); |
261 | 234 |
262 fNeedsDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths && | 235 fNeedsDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths && |
263 kMaxAccuracy_RenderMode == renderMode && | 236 kMaxAccuracy_RenderMode == renderMode && |
264 SkToBool(fContextInitialMatrix.getType() & | 237 SkToBool(fContextInitialMatrix.getType() & |
265 (SkMatrix::kScale_Mask | SkMatrix::kAffin
e_Mask)); | 238 (SkMatrix::kScale_Mask | SkMatrix::kAffin
e_Mask)); |
266 | 239 |
267 if (fNeedsDeviceSpaceGlyphs) { | 240 if (fNeedsDeviceSpaceGlyphs) { |
268 // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms. | 241 // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms. |
269 SkASSERT(!fContextInitialMatrix.hasPerspective()); | 242 SkASSERT(!fContextInitialMatrix.hasPerspective()); |
270 SkASSERT(textTranslate.isZero()); // TODO: Handle textTranslate in devic
e-space usecase. | |
271 | 243 |
272 fTextRatio = fTextInverseRatio = 1.0f; | 244 fTextRatio = fTextInverseRatio = 1.0f; |
273 | 245 |
274 // Glyphs loaded by GPU path rendering have an inverted y-direction. | 246 // Glyphs loaded by GPU path rendering have an inverted y-direction. |
275 SkMatrix m; | 247 SkMatrix m; |
276 m.setScale(1, -1); | 248 m.setScale(1, -1); |
277 fContext->setMatrix(m); | 249 fContext->setMatrix(m); |
278 | 250 |
279 // Post-flip the initial matrix so we're left with just the flip after | 251 // Post-flip the initial matrix so we're left with just the flip after |
280 // the paint preConcats the inverse. | 252 // the paint preConcats the inverse. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() && | 314 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() && |
343 0 == fSkPaint.getTextSkewX() && | 315 0 == fSkPaint.getTextSkewX() && |
344 !fSkPaint.isFakeBoldText() && | 316 !fSkPaint.isFakeBoldText() && |
345 !fSkPaint.isVerticalText(); | 317 !fSkPaint.isVerticalText(); |
346 } else { | 318 } else { |
347 fTextRatio = fTextInverseRatio = 1.0f; | 319 fTextRatio = fTextInverseRatio = 1.0f; |
348 canUseRawPaths = false; | 320 canUseRawPaths = false; |
349 } | 321 } |
350 | 322 |
351 SkMatrix textMatrix; | 323 SkMatrix textMatrix; |
352 textMatrix.setTranslate(textTranslate.x(), textTranslate.y()); | |
353 // Glyphs loaded by GPU path rendering have an inverted y-direction. | 324 // Glyphs loaded by GPU path rendering have an inverted y-direction. |
354 textMatrix.preScale(fTextRatio, -fTextRatio); | 325 textMatrix.setScale(fTextRatio, -fTextRatio); |
355 fPaint.localCoordChange(textMatrix); | 326 fPaint.localCoordChange(textMatrix); |
356 fContext->concatMatrix(textMatrix); | 327 fContext->concatMatrix(textMatrix); |
357 | 328 |
358 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, NULL, false); | 329 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, NULL, false); |
359 fGlyphs = canUseRawPaths ? | 330 fGlyphs = canUseRawPaths ? |
360 get_gr_glyphs(fContext, fSkPaint.getTypeface(), NULL, gpuS
troke) : | 331 get_gr_glyphs(fContext, fSkPaint.getTypeface(), NULL, gpuS
troke) : |
361 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->g
etTypeface(), | 332 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->g
etTypeface(), |
362 &fGlyphCache->getDescriptor(), gpuStroke); | 333 &fGlyphCache->getDescriptor(), gpuStroke); |
363 } | 334 } |
364 | 335 |
365 fStateRestore.set(fDrawTarget->drawState()); | 336 fStateRestore.set(fDrawTarget->drawState()); |
366 | 337 |
367 fDrawTarget->drawState()->setFromPaint(fPaint, fContext->getMatrix(), | 338 fDrawTarget->drawState()->setFromPaint(fPaint, fContext->getMatrix(), |
368 fContext->getRenderTarget()); | 339 fContext->getRenderTarget()); |
369 | 340 |
370 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, | 341 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, |
371 kZero_StencilOp, | 342 kZero_StencilOp, |
372 kZero_StencilOp, | 343 kZero_StencilOp, |
373 kNotEqual_StencilFunc, | 344 kNotEqual_StencilFunc, |
374 0xffff, | 345 0xffff, |
375 0x0000, | 346 0x0000, |
376 0xffff); | 347 0xffff); |
377 | 348 |
378 *fDrawTarget->drawState()->stencil() = kStencilPass; | 349 *fDrawTarget->drawState()->stencil() = kStencilPass; |
379 | 350 |
380 SkASSERT(0 == fPendingGlyphCount); | 351 SkASSERT(0 == fPendingGlyphCount); |
381 } | 352 } |
382 | 353 |
383 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x)
{ | 354 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x,
float y) { |
384 SkASSERT(GrPathRendering::kTranslateX_PathTransformType == fTransformType); | |
385 | |
386 if (fPendingGlyphCount >= kGlyphBufferSize) { | 355 if (fPendingGlyphCount >= kGlyphBufferSize) { |
387 this->flush(); | 356 this->flush(); |
388 } | 357 } |
389 | |
390 fIndexBuffer[fPendingGlyphCount] = glyphID; | |
391 fTransformBuffer[fPendingGlyphCount] = fTextInverseRatio * x; | |
392 | |
393 ++fPendingGlyphCount; | |
394 } | |
395 | |
396 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x,
float y) { | |
397 SkASSERT(GrPathRendering::kTranslate_PathTransformType == fTransformType); | |
398 | |
399 if (fPendingGlyphCount >= kGlyphBufferSize) { | |
400 this->flush(); | |
401 } | |
402 | 358 |
403 fIndexBuffer[fPendingGlyphCount] = glyphID; | 359 fIndexBuffer[fPendingGlyphCount] = glyphID; |
404 fTransformBuffer[2 * fPendingGlyphCount] = fTextInverseRatio * x; | 360 fTransformBuffer[2 * fPendingGlyphCount] = fTextInverseRatio * x; |
405 fTransformBuffer[2 * fPendingGlyphCount + 1] = -fTextInverseRatio * y; | 361 fTransformBuffer[2 * fPendingGlyphCount + 1] = -fTextInverseRatio * y; |
406 | 362 |
407 ++fPendingGlyphCount; | 363 ++fPendingGlyphCount; |
408 } | 364 } |
409 | 365 |
410 void GrStencilAndCoverTextContext::flush() { | 366 void GrStencilAndCoverTextContext::flush() { |
411 if (0 == fPendingGlyphCount) { | 367 if (0 == fPendingGlyphCount) { |
412 return; | 368 return; |
413 } | 369 } |
414 | 370 |
415 fDrawTarget->drawPaths(fGlyphs, fIndexBuffer, fPendingGlyphCount, | 371 fDrawTarget->drawPaths(fGlyphs, fIndexBuffer, fPendingGlyphCount, fTransform
Buffer, |
416 fTransformBuffer, fTransformType, GrPathRendering::kW
inding_FillType); | 372 GrPathRendering::kTranslate_PathTransformType, |
| 373 GrPathRendering::kWinding_FillType); |
417 | 374 |
418 fPendingGlyphCount = 0; | 375 fPendingGlyphCount = 0; |
419 } | 376 } |
420 | 377 |
421 void GrStencilAndCoverTextContext::finish() { | 378 void GrStencilAndCoverTextContext::finish() { |
422 this->flush(); | 379 this->flush(); |
423 | 380 |
424 fGlyphs->unref(); | 381 fGlyphs->unref(); |
425 fGlyphs = NULL; | 382 fGlyphs = NULL; |
426 | 383 |
427 SkGlyphCache::AttachCache(fGlyphCache); | 384 SkGlyphCache::AttachCache(fGlyphCache); |
428 fGlyphCache = NULL; | 385 fGlyphCache = NULL; |
429 | 386 |
430 fDrawTarget->drawState()->stencil()->setDisabled(); | 387 fDrawTarget->drawState()->stencil()->setDisabled(); |
431 fStateRestore.set(NULL); | 388 fStateRestore.set(NULL); |
432 fContext->setMatrix(fContextInitialMatrix); | 389 fContext->setMatrix(fContextInitialMatrix); |
433 GrTextContext::finish(); | 390 GrTextContext::finish(); |
434 } | 391 } |
435 | 392 |
OLD | NEW |