| 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 |