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