Chromium Code Reviews| 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 "GrDrawTarget.h" | 9 #include "GrDrawTarget.h" |
| 10 #include "GrGpu.h" | 10 #include "GrGpu.h" |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 // too. This in turn has the side-effect that NVPR can not stroke the paths, | 133 // too. This in turn has the side-effect that NVPR can not stroke the paths, |
| 134 // as the stroke in NVPR is defined in object-space. | 134 // as the stroke in NVPR is defined in object-space. |
| 135 // NOTE: here we have following coincidence that works at the moment: | 135 // NOTE: here we have following coincidence that works at the moment: |
| 136 // - When using the device-space glyphs, the transforms we pass to NVPR | 136 // - When using the device-space glyphs, the transforms we pass to NVPR |
| 137 // instanced drawing are the global transforms, and the view transform is | 137 // instanced drawing are the global transforms, and the view transform is |
| 138 // identity. NVPR can not use non-affine transforms in the instanced | 138 // identity. NVPR can not use non-affine transforms in the instanced |
| 139 // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it | 139 // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it |
| 140 // will turn off the use of device-space glyphs when perspective transforms | 140 // will turn off the use of device-space glyphs when perspective transforms |
| 141 // are in use. | 141 // are in use. |
| 142 | 142 |
| 143 fGlyphTransform = fContext->getMatrix(); | 143 this->init(paint, skPaint, byteLength, kUseIfNeeded_DeviceSpaceGlyphsBehavio r); |
| 144 | |
| 145 this->init(paint, skPaint, byteLength); | |
| 146 | 144 |
| 147 SkMatrix* glyphCacheTransform = NULL; | 145 SkMatrix* glyphCacheTransform = NULL; |
| 148 // Transform our starting point. | 146 // Transform our starting point. |
| 149 if (fNeedsDeviceSpaceGlyphs) { | 147 if (fNeedsDeviceSpaceGlyphs) { |
| 150 SkPoint loc; | 148 SkPoint loc; |
| 151 fGlyphTransform.mapXY(x, y, &loc); | 149 fContextInitialMatrix.mapXY(x, y, &loc); |
| 152 x = loc.fX; | 150 x = loc.fX; |
| 153 y = loc.fY; | 151 y = loc.fY; |
| 154 glyphCacheTransform = &fGlyphTransform; | 152 glyphCacheTransform = &fContextInitialMatrix; |
| 155 } | 153 } |
| 156 | 154 |
| 157 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 155 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
| 158 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, glyphCacheTransform ); | 156 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, glyphCacheTransform ); |
| 159 fGlyphCache = autoCache.getCache(); | 157 fGlyphCache = autoCache.getCache(); |
| 160 fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke); | 158 fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke); |
| 159 fTransformType = GrDrawTarget::kTranslate_PathTransformType; | |
| 161 | 160 |
| 162 const char* stop = text + byteLength; | 161 const char* stop = text + byteLength; |
| 163 | 162 |
| 164 // Measure first if needed. | 163 // Measure first if needed. |
| 165 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { | 164 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { |
| 166 SkFixed stopX = 0; | 165 SkFixed stopX = 0; |
| 167 SkFixed stopY = 0; | 166 SkFixed stopY = 0; |
| 168 | 167 |
| 169 const char* textPtr = text; | 168 const char* textPtr = text; |
| 170 while (textPtr < stop) { | 169 while (textPtr < stop) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 224 return; | 223 return; |
| 225 } | 224 } |
| 226 | 225 |
| 227 // This is the fast path. Here we do not bake in the device-transform to | 226 // This is the fast path. Here we do not bake in the device-transform to |
| 228 // the glyph outline or the advances. This is because we do not need to | 227 // the glyph outline or the advances. This is because we do not need to |
| 229 // position the glyphs at all, since the caller has done the positioning. | 228 // position the glyphs at all, since the caller has done the positioning. |
| 230 // The positioning is based on SkPaint::measureText of individual | 229 // The positioning is based on SkPaint::measureText of individual |
| 231 // glyphs. That already uses glyph cache without device transforms. Device | 230 // glyphs. That already uses glyph cache without device transforms. Device |
| 232 // transform is not part of SkPaint::measureText API, and thus we use the | 231 // transform is not part of SkPaint::measureText API, and thus we use the |
| 233 // same glyphs as what were measured. | 232 // same glyphs as what were measured. |
| 234 fGlyphTransform.reset(); | |
| 235 | 233 |
| 236 this->init(paint, skPaint, byteLength); | 234 const float textTranslateY = (1 == scalarsPerPosition ? constY : 0); |
| 235 this->init(paint, skPaint, byteLength, kDoNotUse_DeviceSpaceGlyphsBehavior, textTranslateY); | |
| 237 | 236 |
| 238 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 237 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
| 239 | 238 |
| 240 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, NULL); | 239 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, NULL); |
| 241 fGlyphCache = autoCache.getCache(); | 240 fGlyphCache = autoCache.getCache(); |
| 242 fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke); | 241 fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke); |
| 243 | 242 |
| 244 const char* stop = text + byteLength; | 243 const char* stop = text + byteLength; |
| 245 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); | |
| 246 SkTextMapStateProc tmsProc(SkMatrix::I(), constY, scalarsPerPosition); | |
| 247 | 244 |
| 248 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { | 245 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { |
| 249 while (text < stop) { | 246 if (1 == scalarsPerPosition) { |
| 250 SkPoint loc; | 247 fTransformType = GrDrawTarget::kTranslateX_PathTransformType; |
| 251 tmsProc(pos, &loc); | 248 while (text < stop) { |
| 252 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | 249 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); |
| 253 if (glyph.fWidth) { | 250 if (glyph.fWidth) { |
| 254 this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y()); | 251 this->appendGlyph(glyph.getGlyphID(), *pos); |
| 252 } | |
| 253 pos++; | |
| 255 } | 254 } |
| 256 pos += scalarsPerPosition; | 255 } else { |
| 256 SkASSERT(2 == scalarsPerPosition); | |
| 257 fTransformType = GrDrawTarget::kTranslate_PathTransformType; | |
| 258 while (text < stop) { | |
| 259 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | |
| 260 if (glyph.fWidth) { | |
| 261 this->appendGlyph(glyph.getGlyphID(), pos[0], pos[1]); | |
| 262 } | |
| 263 pos += 2; | |
| 264 } | |
| 257 } | 265 } |
| 258 } else { | 266 } else { |
|
Chris Dalton
2014/07/18 22:23:30
We could do a translate-x here too if we could ver
jvanverth1
2014/07/21 17:23:13
Not sure -- adding bungeman to see if he knows.
bungeman-skia
2014/07/21 17:51:27
I'm not sure I understand. You've used scalersPerP
| |
| 267 fTransformType = GrDrawTarget::kTranslate_PathTransformType; | |
| 268 SkTextMapStateProc tmsProc(SkMatrix::I(), 0, scalarsPerPosition); | |
| 269 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); | |
| 259 while (text < stop) { | 270 while (text < stop) { |
| 260 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | 271 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); |
| 261 if (glyph.fWidth) { | 272 if (glyph.fWidth) { |
| 262 SkPoint tmsLoc; | 273 SkPoint tmsLoc; |
| 263 tmsProc(pos, &tmsLoc); | 274 tmsProc(pos, &tmsLoc); |
| 264 SkPoint loc; | 275 SkPoint loc; |
| 265 alignProc(tmsLoc, glyph, &loc); | 276 alignProc(tmsLoc, glyph, &loc); |
| 266 | 277 |
| 267 this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y()); | 278 this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y()); |
| 268 } | 279 } |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 292 } | 303 } |
| 293 | 304 |
| 294 // No color bitmap fonts. | 305 // No color bitmap fonts. |
| 295 SkScalerContext::Rec rec; | 306 SkScalerContext::Rec rec; |
| 296 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec); | 307 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec); |
| 297 return rec.getFormat() != SkMask::kARGB32_Format; | 308 return rec.getFormat() != SkMask::kARGB32_Format; |
| 298 } | 309 } |
| 299 | 310 |
| 300 void GrStencilAndCoverTextContext::init(const GrPaint& paint, | 311 void GrStencilAndCoverTextContext::init(const GrPaint& paint, |
| 301 const SkPaint& skPaint, | 312 const SkPaint& skPaint, |
| 302 size_t textByteLength) { | 313 size_t textByteLength, |
| 314 DeviceSpaceGlyphsBehavior deviceSpaceGly phsBehavior, | |
| 315 SkScalar textTranslateY) { | |
| 303 GrTextContext::init(paint, skPaint); | 316 GrTextContext::init(paint, skPaint); |
| 304 | 317 |
| 318 fContextInitialMatrix = fContext->getMatrix(); | |
| 319 | |
| 305 bool otherBackendsWillDrawAsPaths = | 320 bool otherBackendsWillDrawAsPaths = |
| 306 SkDraw::ShouldDrawTextAsPaths(skPaint, fContext->getMatrix()); | 321 SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix); |
| 307 | 322 |
| 308 if (otherBackendsWillDrawAsPaths) { | 323 if (otherBackendsWillDrawAsPaths) { |
| 309 // This is to reproduce SkDraw::drawText_asPaths glyph positions. | 324 // This is to reproduce SkDraw::drawText_asPaths glyph positions. |
| 310 fSkPaint.setLinearText(true); | 325 fSkPaint.setLinearText(true); |
| 311 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPath s; | 326 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPath s; |
| 327 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTe xtSize(); | |
| 312 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths)) ; | 328 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths)) ; |
| 313 if (fSkPaint.getStyle() != SkPaint::kFill_Style) { | 329 if (fSkPaint.getStyle() != SkPaint::kFill_Style) { |
| 314 // Compensate the glyphs being scaled up by fTextRatio by scaling th e | 330 // Compensate the glyphs being scaled up by fTextRatio by scaling th e |
| 315 // stroke down. | 331 // stroke down. |
| 316 fSkPaint.setStrokeWidth(fSkPaint.getStrokeWidth() / fTextRatio); | 332 fSkPaint.setStrokeWidth(fSkPaint.getStrokeWidth() / fTextRatio); |
| 317 } | 333 } |
| 318 fNeedsDeviceSpaceGlyphs = false; | 334 fNeedsDeviceSpaceGlyphs = false; |
| 319 } else { | 335 } else { |
| 320 fTextRatio = 1.0f; | 336 fTextRatio = fTextInverseRatio = 1.0f; |
| 321 fNeedsDeviceSpaceGlyphs = (fGlyphTransform.getType() & | 337 fNeedsDeviceSpaceGlyphs = |
| 322 (SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask)) != 0; | 338 kUseIfNeeded_DeviceSpaceGlyphsBehavior == deviceSpaceGlyphsBehavior && |
| 339 (fContextInitialMatrix.getType() & | |
| 340 (SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask)) != 0; | |
| 323 // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms. | 341 // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms. |
| 324 SkASSERT(!fGlyphTransform.hasPerspective()); | 342 SkASSERT(!fContextInitialMatrix.hasPerspective()); |
| 325 if (fNeedsDeviceSpaceGlyphs) { | |
| 326 fPaint.localCoordChangeInverse(fGlyphTransform); | |
| 327 fContext->setIdentityMatrix(); | |
| 328 } | |
| 329 } | 343 } |
| 330 | 344 |
| 331 fStroke = SkStrokeRec(fSkPaint); | 345 fStroke = SkStrokeRec(fSkPaint); |
| 332 | 346 |
| 333 if (fNeedsDeviceSpaceGlyphs) { | 347 if (fNeedsDeviceSpaceGlyphs) { |
| 348 SkASSERT(1.0f == fTextRatio); | |
| 349 SkASSERT(0.0f == textTranslateY); | |
| 350 fPaint.localCoordChangeInverse(fContextInitialMatrix); | |
| 351 fContext->setIdentityMatrix(); | |
| 352 | |
| 334 // The whole shape is baked into the glyph. Make NVPR just fill the | 353 // The whole shape is baked into the glyph. Make NVPR just fill the |
| 335 // baked shape. | 354 // baked shape. |
| 336 fStroke.setStrokeStyle(-1, false); | 355 fStroke.setStrokeStyle(-1, false); |
| 337 } else { | 356 } else { |
| 357 if (1.0f != fTextRatio || 0.0f != textTranslateY) { | |
| 358 SkMatrix textMatrix; | |
| 359 textMatrix.setTranslate(0, textTranslateY); | |
| 360 textMatrix.preScale(fTextRatio, fTextRatio); | |
| 361 fPaint.localCoordChange(textMatrix); | |
| 362 fContext->concatMatrix(textMatrix); | |
| 363 } | |
| 364 | |
| 338 if (fSkPaint.getStrokeWidth() == 0.0f) { | 365 if (fSkPaint.getStrokeWidth() == 0.0f) { |
| 339 if (fSkPaint.getStyle() == SkPaint::kStrokeAndFill_Style) { | 366 if (fSkPaint.getStyle() == SkPaint::kStrokeAndFill_Style) { |
| 340 fStroke.setStrokeStyle(-1, false); | 367 fStroke.setStrokeStyle(-1, false); |
| 341 } else if (fSkPaint.getStyle() == SkPaint::kStroke_Style) { | 368 } else if (fSkPaint.getStyle() == SkPaint::kStroke_Style) { |
| 342 // Approximate hairline stroke. | 369 // Approximate hairline stroke. |
| 343 const SkMatrix& ctm = fContext->getMatrix(); | 370 const SkMatrix& ctm = fContext->getMatrix(); |
| 344 SkScalar strokeWidth = SK_Scalar1 / | 371 SkScalar strokeWidth = SK_Scalar1 / |
| 345 (fTextRatio * SkVector::Make(ctm.getScaleX(), ctm.getSkewY() ).length()); | 372 (SkVector::Make(ctm.getScaleX(), ctm.getSkewY()).length()); |
| 346 fStroke.setStrokeStyle(strokeWidth, false); | 373 fStroke.setStrokeStyle(strokeWidth, false); |
| 347 } | 374 } |
| 348 } | 375 } |
| 349 | 376 |
| 350 // Make glyph cache produce paths geometry for fill. We will stroke them | 377 // Make glyph cache produce paths geometry for fill. We will stroke them |
| 351 // by passing fStroke to drawPath. This is the fast path. | 378 // by passing fStroke to drawPath. This is the fast path. |
| 352 fSkPaint.setStyle(SkPaint::kFill_Style); | 379 fSkPaint.setStyle(SkPaint::kFill_Style); |
| 353 } | 380 } |
| 354 fStateRestore.set(fDrawTarget->drawState()); | 381 fStateRestore.set(fDrawTarget->drawState()); |
| 355 | 382 |
| 356 fDrawTarget->drawState()->setFromPaint(fPaint, fContext->getMatrix(), | 383 fDrawTarget->drawState()->setFromPaint(fPaint, fContext->getMatrix(), |
| 357 fContext->getRenderTarget()); | 384 fContext->getRenderTarget()); |
| 358 | 385 |
| 359 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, | 386 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, |
| 360 kZero_StencilOp, | 387 kZero_StencilOp, |
| 361 kZero_StencilOp, | 388 kZero_StencilOp, |
| 362 kNotEqual_StencilFunc, | 389 kNotEqual_StencilFunc, |
| 363 0xffff, | 390 0xffff, |
| 364 0x0000, | 391 0x0000, |
| 365 0xffff); | 392 0xffff); |
| 366 | 393 |
| 367 *fDrawTarget->drawState()->stencil() = kStencilPass; | 394 *fDrawTarget->drawState()->stencil() = kStencilPass; |
| 368 | 395 |
| 369 SkASSERT(0 == fPendingGlyphCount); | 396 SkASSERT(0 == fPendingGlyphCount); |
| 370 } | 397 } |
| 371 | 398 |
| 372 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x, float y) { | 399 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x) { |
| 400 SkASSERT(GrDrawTarget::kTranslateX_PathTransformType == fTransformType); | |
| 401 | |
| 373 if (fPendingGlyphCount >= kGlyphBufferSize) { | 402 if (fPendingGlyphCount >= kGlyphBufferSize) { |
| 374 this->flush(); | 403 this->flush(); |
| 375 } | 404 } |
| 405 | |
| 406 fGlyphs->preloadGlyph(glyphID, fGlyphCache); | |
| 407 | |
| 408 fIndexBuffer[fPendingGlyphCount] = glyphID; | |
| 409 fTransformBuffer[fPendingGlyphCount] = fTextInverseRatio * x; | |
| 410 | |
| 411 ++fPendingGlyphCount; | |
| 412 } | |
| 413 | |
| 414 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x, float y) { | |
| 415 SkASSERT(GrDrawTarget::kTranslate_PathTransformType == fTransformType); | |
| 416 | |
| 417 if (fPendingGlyphCount >= kGlyphBufferSize) { | |
| 418 this->flush(); | |
| 419 } | |
| 376 | 420 |
| 377 fGlyphs->preloadGlyph(glyphID, fGlyphCache); | 421 fGlyphs->preloadGlyph(glyphID, fGlyphCache); |
| 378 | 422 |
| 379 fIndexBuffer[fPendingGlyphCount] = glyphID; | 423 fIndexBuffer[fPendingGlyphCount] = glyphID; |
| 380 fTransformBuffer[6 * fPendingGlyphCount + 0] = fTextRatio; | 424 fTransformBuffer[2 * fPendingGlyphCount] = fTextInverseRatio * x; |
| 381 fTransformBuffer[6 * fPendingGlyphCount + 1] = 0; | 425 fTransformBuffer[2 * fPendingGlyphCount + 1] = fTextInverseRatio * y; |
| 382 fTransformBuffer[6 * fPendingGlyphCount + 2] = x; | |
| 383 fTransformBuffer[6 * fPendingGlyphCount + 3] = 0; | |
| 384 fTransformBuffer[6 * fPendingGlyphCount + 4] = fTextRatio; | |
| 385 fTransformBuffer[6 * fPendingGlyphCount + 5] = y; | |
| 386 | 426 |
| 387 ++fPendingGlyphCount; | 427 ++fPendingGlyphCount; |
| 388 } | 428 } |
| 389 | 429 |
| 390 void GrStencilAndCoverTextContext::flush() { | 430 void GrStencilAndCoverTextContext::flush() { |
| 391 if (0 == fPendingGlyphCount) { | 431 if (0 == fPendingGlyphCount) { |
| 392 return; | 432 return; |
| 393 } | 433 } |
| 394 | 434 |
| 395 fDrawTarget->drawPaths(fGlyphs->pathRange(), fIndexBuffer, fPendingGlyphCoun t, | 435 fDrawTarget->drawPaths(fGlyphs->pathRange(), fIndexBuffer, fPendingGlyphCoun t, |
| 396 fTransformBuffer, GrDrawTarget::kAffine_PathTransform Type, | 436 fTransformBuffer, fTransformType, SkPath::kWinding_Fi llType); |
| 397 SkPath::kWinding_FillType); | |
| 398 | 437 |
| 399 fPendingGlyphCount = 0; | 438 fPendingGlyphCount = 0; |
| 400 } | 439 } |
| 401 | 440 |
| 402 void GrStencilAndCoverTextContext::finish() { | 441 void GrStencilAndCoverTextContext::finish() { |
| 403 this->flush(); | 442 this->flush(); |
| 404 | 443 |
| 405 SkSafeUnref(fGlyphs); | 444 SkSafeUnref(fGlyphs); |
| 406 fGlyphs = NULL; | 445 fGlyphs = NULL; |
| 407 fGlyphCache = NULL; | 446 fGlyphCache = NULL; |
| 408 | 447 |
| 409 fDrawTarget->drawState()->stencil()->setDisabled(); | 448 fDrawTarget->drawState()->stencil()->setDisabled(); |
| 410 fStateRestore.set(NULL); | 449 fStateRestore.set(NULL); |
| 411 if (fNeedsDeviceSpaceGlyphs) { | 450 fContext->setMatrix(fContextInitialMatrix); |
| 412 fContext->setMatrix(fGlyphTransform); | |
| 413 } | |
| 414 GrTextContext::finish(); | 451 GrTextContext::finish(); |
| 415 } | 452 } |
| 416 | 453 |
| OLD | NEW |