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 "GrBitmapTextContext.h" | 9 #include "GrBitmapTextContext.h" |
| 10 #include "GrDrawTarget.h" | 10 #include "GrDrawTarget.h" |
| 11 #include "GrGpu.h" | 11 #include "GrGpu.h" |
| 12 #include "GrPath.h" | 12 #include "GrPath.h" |
| 13 #include "GrPathRange.h" | 13 #include "GrPathRange.h" |
| 14 #include "SkAutoKern.h" | 14 #include "SkAutoKern.h" |
| 15 #include "SkDraw.h" | 15 #include "SkDraw.h" |
| 16 #include "SkDrawProcs.h" | 16 #include "SkDrawProcs.h" |
| 17 #include "SkGlyphCache.h" | 17 #include "SkGlyphCache.h" |
| 18 #include "SkGpuDevice.h" | 18 #include "SkGpuDevice.h" |
| 19 #include "SkPath.h" | 19 #include "SkPath.h" |
| 20 #include "SkTextMapStateProc.h" | 20 #include "SkTextMapStateProc.h" |
| 21 #include "SkTextFormatParams.h" | 21 #include "SkTextFormatParams.h" |
| 22 | 22 |
| 23 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext( | 23 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext( |
| 24 GrContext* context, const SkDeviceProperties& properties) | 24 GrContext* context, const SkDeviceProperties& properties) |
| 25 : GrTextContext(context, properties) | 25 : GrTextContext(context, properties) |
| 26 , fPendingGlyphCount(0) { | 26 , fStroke(SkStrokeRec::kFill_InitStyle) |
| 27 , fQueuedGlyphCount(0) | |
| 28 , fFallbackGlyphsIdx(kGlyphBufferSize) { | |
| 27 } | 29 } |
| 28 | 30 |
| 29 GrStencilAndCoverTextContext* GrStencilAndCoverTextContext::Create(GrContext* co ntext, | 31 GrStencilAndCoverTextContext* GrStencilAndCoverTextContext::Create(GrContext* co ntext, |
| 30 const SkDeviceP roperties& props) { | 32 const SkDeviceP roperties& props) { |
| 31 GrStencilAndCoverTextContext* textContext = SkNEW_ARGS(GrStencilAndCoverText Context, | 33 GrStencilAndCoverTextContext* textContext = SkNEW_ARGS(GrStencilAndCoverText Context, |
| 32 (context, props)); | 34 (context, props)); |
| 33 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, pro ps); | 35 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, pro ps); |
| 34 | 36 |
| 35 return textContext; | 37 return textContext; |
| 36 } | 38 } |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 56 return false; | 58 return false; |
| 57 } | 59 } |
| 58 | 60 |
| 59 // No color bitmap fonts. | 61 // No color bitmap fonts. |
| 60 SkScalerContext::Rec rec; | 62 SkScalerContext::Rec rec; |
| 61 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec); | 63 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec); |
| 62 return rec.getFormat() != SkMask::kARGB32_Format; | 64 return rec.getFormat() != SkMask::kARGB32_Format; |
| 63 } | 65 } |
| 64 | 66 |
| 65 void GrStencilAndCoverTextContext::onDrawText(const GrPaint& paint, | 67 void GrStencilAndCoverTextContext::onDrawText(const GrPaint& paint, |
| 66 const SkPaint& skPaint, | 68 const SkPaint& skPaint, |
| 67 const char text[], | 69 const char text[], |
| 68 size_t byteLength, | 70 size_t byteLength, |
| 69 SkScalar x, SkScalar y) { | 71 SkScalar x, SkScalar y) { |
| 70 SkASSERT(byteLength == 0 || text != NULL); | 72 SkASSERT(byteLength == 0 || text != NULL); |
| 71 | 73 |
| 72 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) { | 74 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) { |
| 73 return; | 75 return; |
| 74 } | 76 } |
| 75 | 77 |
| 76 // This is the slow path, mainly used by Skia unit tests. The other | 78 // This is the slow path, mainly used by Skia unit tests. The other |
| 77 // backends (8888, gpu, ...) use device-space dependent glyph caches. In | 79 // backends (8888, gpu, ...) use device-space dependent glyph caches. In |
| 78 // order to match the glyph positions that the other code paths produce, we | 80 // order to match the glyph positions that the other code paths produce, we |
| 79 // must also use device-space dependent glyph cache. This has the | 81 // must also use device-space dependent glyph cache. This has the |
| 80 // side-effect that the glyph shape outline will be in device-space, | 82 // side-effect that the glyph shape outline will be in device-space, |
| 81 // too. This in turn has the side-effect that NVPR can not stroke the paths, | 83 // 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. | 84 // as the stroke in NVPR is defined in object-space. |
| 83 // NOTE: here we have following coincidence that works at the moment: | 85 // NOTE: here we have following coincidence that works at the moment: |
| 84 // - When using the device-space glyphs, the transforms we pass to NVPR | 86 // - When using the device-space glyphs, the transforms we pass to NVPR |
| 85 // instanced drawing are the global transforms, and the view transform is | 87 // instanced drawing are the global transforms, and the view transform is |
| 86 // identity. NVPR can not use non-affine transforms in the instanced | 88 // identity. NVPR can not use non-affine transforms in the instanced |
| 87 // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it | 89 // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it |
| 88 // will turn off the use of device-space glyphs when perspective transforms | 90 // will turn off the use of device-space glyphs when perspective transforms |
| 89 // are in use. | 91 // are in use. |
| 90 | 92 |
| 91 this->init(paint, skPaint, byteLength, kMaxAccuracy_RenderMode); | 93 this->init(paint, skPaint, byteLength, kMaxAccuracy_RenderMode); |
| 92 | 94 |
| 93 // Transform our starting point. | 95 // Transform our starting point. |
| 94 if (fNeedsDeviceSpaceGlyphs) { | 96 if (fUsingDeviceSpaceGlyphs) { |
| 95 SkPoint loc; | 97 SkPoint loc; |
| 96 fContextInitialMatrix.mapXY(x, y, &loc); | 98 fContextInitialMatrix.mapXY(x, y, &loc); |
| 97 x = loc.fX; | 99 x = loc.fX; |
| 98 y = loc.fY; | 100 y = loc.fY; |
| 99 } | 101 } |
| 100 | 102 |
| 101 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 103 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
| 102 | 104 |
| 103 const char* stop = text + byteLength; | 105 const char* stop = text + byteLength; |
| 104 | 106 |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 133 SkAutoKern autokern; | 135 SkAutoKern autokern; |
| 134 | 136 |
| 135 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); | 137 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); |
| 136 | 138 |
| 137 SkFixed fx = SkScalarToFixed(x); | 139 SkFixed fx = SkScalarToFixed(x); |
| 138 SkFixed fy = SkScalarToFixed(y); | 140 SkFixed fy = SkScalarToFixed(y); |
| 139 while (text < stop) { | 141 while (text < stop) { |
| 140 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | 142 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); |
| 141 fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio); | 143 fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio); |
| 142 if (glyph.fWidth) { | 144 if (glyph.fWidth) { |
| 143 this->appendGlyph(glyph.getGlyphID(), SkFixedToScalar(fx), SkFixedTo Scalar(fy)); | 145 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedT oScalar(fy))); |
| 144 } | 146 } |
| 145 | 147 |
| 146 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio); | 148 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio); |
| 147 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio); | 149 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio); |
| 148 } | 150 } |
| 149 | 151 |
| 150 this->finish(); | 152 this->finish(); |
| 151 } | 153 } |
| 152 | 154 |
| 153 void GrStencilAndCoverTextContext::onDrawPosText(const GrPaint& paint, | 155 void GrStencilAndCoverTextContext::onDrawPosText(const GrPaint& paint, |
| 154 const SkPaint& skPaint, | 156 const SkPaint& skPaint, |
| 155 const char text[], | 157 const char text[], |
| 156 size_t byteLength, | 158 size_t byteLength, |
| 157 const SkScalar pos[], | 159 const SkScalar pos[], |
| 158 int scalarsPerPosition, | 160 int scalarsPerPosition, |
| 159 const SkPoint& offset) { | 161 const SkPoint& offset) { |
| 160 SkASSERT(byteLength == 0 || text != NULL); | 162 SkASSERT(byteLength == 0 || text != NULL); |
| 161 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 163 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
| 162 | 164 |
| 163 // nothing to draw | 165 // nothing to draw |
| 164 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) { | 166 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) { |
| 165 return; | 167 return; |
| 166 } | 168 } |
| 167 | 169 |
| 168 // This is the fast path. Here we do not bake in the device-transform to | 170 // This is the fast path. Here we do not bake in the device-transform to |
| 169 // the glyph outline or the advances. This is because we do not need to | 171 // the glyph outline or the advances. This is because we do not need to |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 182 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); | 184 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); |
| 183 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); | 185 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); |
| 184 while (text < stop) { | 186 while (text < stop) { |
| 185 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | 187 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); |
| 186 if (glyph.fWidth) { | 188 if (glyph.fWidth) { |
| 187 SkPoint tmsLoc; | 189 SkPoint tmsLoc; |
| 188 tmsProc(pos, &tmsLoc); | 190 tmsProc(pos, &tmsLoc); |
| 189 SkPoint loc; | 191 SkPoint loc; |
| 190 alignProc(tmsLoc, glyph, &loc); | 192 alignProc(tmsLoc, glyph, &loc); |
| 191 | 193 |
| 192 this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y()); | 194 this->appendGlyph(glyph, loc); |
| 193 } | 195 } |
| 194 pos += scalarsPerPosition; | 196 pos += scalarsPerPosition; |
| 195 } | 197 } |
| 196 | 198 |
| 197 this->finish(); | 199 this->finish(); |
| 198 } | 200 } |
| 199 | 201 |
| 200 static GrPathRange* get_gr_glyphs(GrContext* ctx, | 202 static GrPathRange* get_gr_glyphs(GrContext* ctx, |
| 201 const SkTypeface* typeface, | 203 const SkTypeface* typeface, |
| 202 const SkDescriptor* desc, | 204 const SkDescriptor* desc, |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 225 const SkPaint& skPaint, | 227 const SkPaint& skPaint, |
| 226 size_t textByteLength, | 228 size_t textByteLength, |
| 227 RenderMode renderMode) { | 229 RenderMode renderMode) { |
| 228 GrTextContext::init(paint, skPaint); | 230 GrTextContext::init(paint, skPaint); |
| 229 | 231 |
| 230 fContextInitialMatrix = fContext->getMatrix(); | 232 fContextInitialMatrix = fContext->getMatrix(); |
| 231 | 233 |
| 232 const bool otherBackendsWillDrawAsPaths = | 234 const bool otherBackendsWillDrawAsPaths = |
| 233 SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix); | 235 SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix); |
| 234 | 236 |
| 235 fNeedsDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths && | 237 fUsingDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths && |
| 236 kMaxAccuracy_RenderMode == renderMode && | 238 kMaxAccuracy_RenderMode == renderMode && |
| 237 SkToBool(fContextInitialMatrix.getType() & | 239 SkToBool(fContextInitialMatrix.getType() & |
| 238 (SkMatrix::kScale_Mask | SkMatrix::kAffin e_Mask)); | 240 (SkMatrix::kScale_Mask | SkMatrix::kAffin e_Mask)); |
| 239 | 241 |
| 240 if (fNeedsDeviceSpaceGlyphs) { | 242 if (fUsingDeviceSpaceGlyphs) { |
| 241 // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms. | 243 // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms. |
| 242 SkASSERT(!fContextInitialMatrix.hasPerspective()); | 244 SkASSERT(!fContextInitialMatrix.hasPerspective()); |
| 243 | 245 |
| 246 // The whole shape (including stroke) will be baked into the glyph outli nes. Make | |
| 247 // NVPR just fill the baked shapes. | |
| 248 fStroke = SkStrokeRec(SkStrokeRec::kFill_InitStyle); | |
| 249 | |
| 244 fTextRatio = fTextInverseRatio = 1.0f; | 250 fTextRatio = fTextInverseRatio = 1.0f; |
| 245 | 251 |
| 246 // Glyphs loaded by GPU path rendering have an inverted y-direction. | 252 // Glyphs loaded by GPU path rendering have an inverted y-direction. |
| 247 SkMatrix m; | 253 SkMatrix m; |
| 248 m.setScale(1, -1); | 254 m.setScale(1, -1); |
| 249 fContext->setMatrix(m); | 255 fContext->setMatrix(m); |
| 250 | 256 |
| 251 // Post-flip the initial matrix so we're left with just the flip after | 257 // Post-flip the initial matrix so we're left with just the flip after |
| 252 // the paint preConcats the inverse. | 258 // the paint preConcats the inverse. |
| 253 m = fContextInitialMatrix; | 259 m = fContextInitialMatrix; |
| 254 m.postScale(1, -1); | 260 m.postScale(1, -1); |
| 255 fPaint.localCoordChangeInverse(m); | 261 fPaint.localCoordChangeInverse(m); |
| 256 | 262 |
| 257 // The whole shape (including stroke) will be baked into the glyph outli nes. Make | |
| 258 // NVPR just fill the baked shapes. | |
| 259 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, &fContextInitialM atrix, false); | 263 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, &fContextInitialM atrix, false); |
| 260 fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTy peface(), | 264 fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTy peface(), |
| 261 &fGlyphCache->getDescriptor(), | 265 &fGlyphCache->getDescriptor(), fStroke); |
| 262 SkStrokeRec(SkStrokeRec::kFill_InitStyle)); | |
| 263 } else { | 266 } else { |
| 264 // Don't bake strokes into the glyph outlines. We will stroke the glyphs | 267 // Don't bake strokes into the glyph outlines. We will stroke the glyphs |
| 265 // using the GPU instead. This is the fast path. | 268 // using the GPU instead. This is the fast path. |
| 266 SkStrokeRec gpuStroke = SkStrokeRec(fSkPaint); | 269 fStroke = SkStrokeRec(fSkPaint); |
| 267 fSkPaint.setStyle(SkPaint::kFill_Style); | 270 fSkPaint.setStyle(SkPaint::kFill_Style); |
| 268 | 271 |
| 269 if (gpuStroke.isHairlineStyle()) { | 272 if (fStroke.isHairlineStyle()) { |
| 270 // Approximate hairline stroke. | 273 // Approximate hairline stroke. |
| 271 SkScalar strokeWidth = SK_Scalar1 / | 274 SkScalar strokeWidth = SK_Scalar1 / |
| 272 (SkVector::Make(fContextInitialMatrix.getScaleX(), | 275 (SkVector::Make(fContextInitialMatrix.getScaleX(), |
| 273 fContextInitialMatrix.getSkewY()).length()); | 276 fContextInitialMatrix.getSkewY()).length()); |
| 274 gpuStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/); | 277 fStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/); |
| 275 | 278 |
| 276 } else if (fSkPaint.isFakeBoldText() && | 279 } else if (fSkPaint.isFakeBoldText() && |
| 277 #ifdef SK_USE_FREETYPE_EMBOLDEN | 280 #ifdef SK_USE_FREETYPE_EMBOLDEN |
| 278 kMaxPerformance_RenderMode == renderMode && | 281 kMaxPerformance_RenderMode == renderMode && |
| 279 #endif | 282 #endif |
| 280 SkStrokeRec::kStroke_Style != gpuStroke.getStyle()) { | 283 SkStrokeRec::kStroke_Style != fStroke.getStyle()) { |
| 281 | 284 |
| 282 // Instead of baking fake bold into the glyph outlines, do it with t he GPU stroke. | 285 // Instead of baking fake bold into the glyph outlines, do it with t he GPU stroke. |
| 283 SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(), | 286 SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(), |
| 284 kStdFakeBoldInterpKeys, | 287 kStdFakeBoldInterpKeys, |
| 285 kStdFakeBoldInterpValues , | 288 kStdFakeBoldInterpValues , |
| 286 kStdFakeBoldInterpLength ); | 289 kStdFakeBoldInterpLength ); |
| 287 SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale); | 290 SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale); |
| 288 gpuStroke.setStrokeStyle(gpuStroke.needToApply() ? gpuStroke.getWidt h() + extra : extra, | 291 fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra, |
| 289 true /*strokeAndFill*/); | 292 true /*strokeAndFill*/); |
| 290 | 293 |
| 291 fSkPaint.setFakeBoldText(false); | 294 fSkPaint.setFakeBoldText(false); |
| 292 } | 295 } |
| 293 | 296 |
| 294 bool canUseRawPaths; | 297 bool canUseRawPaths; |
| 295 | 298 |
| 296 if (otherBackendsWillDrawAsPaths || kMaxPerformance_RenderMode == render Mode) { | 299 if (otherBackendsWillDrawAsPaths || kMaxPerformance_RenderMode == render Mode) { |
| 297 // We can draw the glyphs from canonically sized paths. | 300 // We can draw the glyphs from canonically sized paths. |
| 298 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeFor Paths; | 301 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeFor Paths; |
| 299 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.g etTextSize(); | 302 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.g etTextSize(); |
| 300 | 303 |
| 301 // Compensate for the glyphs being scaled by fTextRatio. | 304 // Compensate for the glyphs being scaled by fTextRatio. |
| 302 if (!gpuStroke.isFillStyle()) { | 305 if (!fStroke.isFillStyle()) { |
| 303 gpuStroke.setStrokeStyle(gpuStroke.getWidth() / fTextRatio, | 306 fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio, |
| 304 SkStrokeRec::kStrokeAndFill_Style == gp uStroke.getStyle()); | 307 SkStrokeRec::kStrokeAndFill_Style == fStr oke.getStyle()); |
| 305 } | 308 } |
| 306 | 309 |
| 307 fSkPaint.setLinearText(true); | 310 fSkPaint.setLinearText(true); |
| 308 fSkPaint.setLCDRenderText(false); | 311 fSkPaint.setLCDRenderText(false); |
| 309 fSkPaint.setAutohinted(false); | 312 fSkPaint.setAutohinted(false); |
| 310 fSkPaint.setHinting(SkPaint::kNo_Hinting); | 313 fSkPaint.setHinting(SkPaint::kNo_Hinting); |
| 311 fSkPaint.setSubpixelText(true); | 314 fSkPaint.setSubpixelText(true); |
| 312 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPat hs)); | 315 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPat hs)); |
| 313 | 316 |
| 314 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() && | 317 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() && |
| 315 0 == fSkPaint.getTextSkewX() && | 318 0 == fSkPaint.getTextSkewX() && |
| 316 !fSkPaint.isFakeBoldText() && | 319 !fSkPaint.isFakeBoldText() && |
| 317 !fSkPaint.isVerticalText(); | 320 !fSkPaint.isVerticalText(); |
| 318 } else { | 321 } else { |
| 319 fTextRatio = fTextInverseRatio = 1.0f; | 322 fTextRatio = fTextInverseRatio = 1.0f; |
| 320 canUseRawPaths = false; | 323 canUseRawPaths = false; |
| 321 } | 324 } |
| 322 | 325 |
| 323 SkMatrix textMatrix; | 326 SkMatrix textMatrix; |
| 324 // Glyphs loaded by GPU path rendering have an inverted y-direction. | 327 // Glyphs loaded by GPU path rendering have an inverted y-direction. |
| 325 textMatrix.setScale(fTextRatio, -fTextRatio); | 328 textMatrix.setScale(fTextRatio, -fTextRatio); |
| 326 fPaint.localCoordChange(textMatrix); | 329 fPaint.localCoordChange(textMatrix); |
| 327 fContext->concatMatrix(textMatrix); | 330 fContext->concatMatrix(textMatrix); |
| 328 | 331 |
| 329 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, NULL, false); | 332 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, NULL, false); |
| 330 fGlyphs = canUseRawPaths ? | 333 fGlyphs = canUseRawPaths ? |
| 331 get_gr_glyphs(fContext, fSkPaint.getTypeface(), NULL, gpuS troke) : | 334 get_gr_glyphs(fContext, fSkPaint.getTypeface(), NULL, fStr oke) : |
| 332 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->g etTypeface(), | 335 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->g etTypeface(), |
| 333 &fGlyphCache->getDescriptor(), gpuStroke); | 336 &fGlyphCache->getDescriptor(), fStroke); |
| 334 } | 337 } |
| 335 | 338 |
| 336 fStateRestore.set(&fDrawState); | 339 fStateRestore.set(&fDrawState); |
| 337 | 340 |
| 338 fDrawState.setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTa rget()); | 341 fDrawState.setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTa rget()); |
| 339 | 342 |
| 340 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, | 343 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, |
| 341 kZero_StencilOp, | 344 kZero_StencilOp, |
| 342 kZero_StencilOp, | 345 kZero_StencilOp, |
| 343 kNotEqual_StencilFunc, | 346 kNotEqual_StencilFunc, |
| 344 0xffff, | 347 0xffff, |
| 345 0x0000, | 348 0x0000, |
| 346 0xffff); | 349 0xffff); |
| 347 | 350 |
| 348 *fDrawState.stencil() = kStencilPass; | 351 *fDrawState.stencil() = kStencilPass; |
| 349 | 352 |
| 350 SkASSERT(0 == fPendingGlyphCount); | 353 SkASSERT(0 == fQueuedGlyphCount); |
| 354 SkASSERT(kGlyphBufferSize == fFallbackGlyphsIdx); | |
| 351 } | 355 } |
| 352 | 356 |
| 353 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x, float y) { | 357 bool GrStencilAndCoverTextContext::mapToFallbackContext(GrContext::AutoMatrix& a utoMatrix, |
| 354 if (fPendingGlyphCount >= kGlyphBufferSize) { | 358 SkMatrix* inverse) { |
| 359 // The current view matrix is flipped because GPU path rendering glyphs have an | |
| 360 // inverted y-direction. Unflip the view matrix for the fallback context. If using | |
| 361 // device-space glyphs, we'll also need to restore the original view matrix since | |
| 362 // we moved that transfomation into our local glyph cache for this scenario. Also | |
| 363 // track the inverse operation so the caller can unmap the paint and glyph p ositions. | |
| 364 if (fUsingDeviceSpaceGlyphs) { | |
| 365 autoMatrix.set(fContext, fContextInitialMatrix); | |
| 366 if (!fContextInitialMatrix.invert(inverse)) { | |
| 367 return false; | |
| 368 } | |
| 369 inverse->preScale(1, -1); | |
| 370 } else { | |
| 371 inverse->setScale(1, -1); | |
| 372 const SkMatrix& unflip = *inverse; // unflip is equal to its own inverse . | |
| 373 autoMatrix.setPreConcat(fContext, unflip); | |
| 374 } | |
| 375 return true; | |
| 376 } | |
| 377 | |
| 378 inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, cons t SkPoint& pos) { | |
| 379 if (fQueuedGlyphCount >= fFallbackGlyphsIdx) { | |
| 380 SkASSERT(fQueuedGlyphCount == fFallbackGlyphsIdx); | |
| 355 this->flush(); | 381 this->flush(); |
| 356 } | 382 } |
| 357 | 383 |
| 358 fIndexBuffer[fPendingGlyphCount] = glyphID; | 384 // Stick the glyphs we can't draw at the end of the buffer, growing backward s. |
|
Chris Dalton
2014/11/25 23:13:54
Looking for feedback here.
Growing backwards will
jvanverth1
2014/11/26 19:41:35
On one hand, drawing them in reverse order doesn't
| |
| 359 fTransformBuffer[2 * fPendingGlyphCount] = fTextInverseRatio * x; | 385 int index = (SkMask::kARGB32_Format == glyph.fMaskFormat) ? |
| 360 fTransformBuffer[2 * fPendingGlyphCount + 1] = -fTextInverseRatio * y; | 386 --fFallbackGlyphsIdx : fQueuedGlyphCount++; |
| 361 | 387 |
| 362 ++fPendingGlyphCount; | 388 fGlyphIndices[index] = glyph.getGlyphID(); |
| 389 fGlyphPositions[index].set(fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y()); | |
| 390 } | |
| 391 | |
| 392 static const SkScalar* get_xy_scalar_array(const SkPoint* pointArray) { | |
| 393 GR_STATIC_ASSERT(2 * sizeof(SkScalar) == sizeof(SkPoint)); | |
| 394 GR_STATIC_ASSERT(0 == offsetof(SkPoint, fX)); | |
| 395 | |
| 396 return &pointArray[0].fX; | |
| 363 } | 397 } |
| 364 | 398 |
| 365 void GrStencilAndCoverTextContext::flush() { | 399 void GrStencilAndCoverTextContext::flush() { |
| 366 if (0 == fPendingGlyphCount) { | 400 if (fQueuedGlyphCount > 0) { |
| 367 return; | 401 fDrawTarget->drawPaths(&fDrawState, fGlyphs, |
| 402 fGlyphIndices, GrPathRange::kU16_PathIndexType, | |
| 403 get_xy_scalar_array(fGlyphPositions), | |
| 404 GrPathRendering::kTranslate_PathTransformType, | |
| 405 fQueuedGlyphCount, GrPathRendering::kWinding_Fill Type); | |
| 406 | |
| 407 fQueuedGlyphCount = 0; | |
| 368 } | 408 } |
| 369 | 409 |
| 370 fDrawTarget->drawPaths(&fDrawState, fGlyphs, fIndexBuffer, GrPathRange::kU16 _PathIndexType, | 410 if (fFallbackGlyphsIdx < kGlyphBufferSize) { |
| 371 fTransformBuffer, GrPathRendering::kTranslate_PathTra nsformType, | 411 int fallbackGlyphCount = kGlyphBufferSize - fFallbackGlyphsIdx; |
| 372 fPendingGlyphCount, GrPathRendering::kWinding_FillTyp e); | |
| 373 | 412 |
| 374 fPendingGlyphCount = 0; | 413 GrPaint paintFallback(fPaint); |
| 414 | |
| 415 SkPaint skPaintFallback(fSkPaint); | |
| 416 if (!fUsingDeviceSpaceGlyphs) { | |
| 417 fStroke.applyToPaint(&skPaintFallback); | |
| 418 } | |
| 419 skPaintFallback.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for. | |
| 420 skPaintFallback.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | |
| 421 | |
| 422 GrContext::AutoMatrix autoMatrix; | |
| 423 SkMatrix inverse; | |
| 424 if (this->mapToFallbackContext(autoMatrix, &inverse)) { | |
| 425 paintFallback.localCoordChangeInverse(inverse); | |
| 426 inverse.mapPoints(&fGlyphPositions[fFallbackGlyphsIdx], fallbackGlyp hCount); | |
| 427 } | |
| 428 | |
| 429 fFallbackTextContext->drawPosText(paintFallback, skPaintFallback, | |
| 430 (char*)&fGlyphIndices[fFallbackGlyphsI dx], | |
| 431 2 * fallbackGlyphCount, | |
| 432 get_xy_scalar_array(&fGlyphPositions[f FallbackGlyphsIdx]), | |
| 433 2, SkPoint::Make(0, 0)); | |
| 434 | |
| 435 fFallbackGlyphsIdx = kGlyphBufferSize; | |
| 436 } | |
| 375 } | 437 } |
| 376 | 438 |
| 377 void GrStencilAndCoverTextContext::finish() { | 439 void GrStencilAndCoverTextContext::finish() { |
| 378 this->flush(); | 440 this->flush(); |
| 379 | 441 |
| 380 fGlyphs->unref(); | 442 fGlyphs->unref(); |
| 381 fGlyphs = NULL; | 443 fGlyphs = NULL; |
| 382 | 444 |
| 383 SkGlyphCache::AttachCache(fGlyphCache); | 445 SkGlyphCache::AttachCache(fGlyphCache); |
| 384 fGlyphCache = NULL; | 446 fGlyphCache = NULL; |
| 385 | 447 |
| 386 fDrawState.stencil()->setDisabled(); | 448 fDrawState.stencil()->setDisabled(); |
| 387 fStateRestore.set(NULL); | 449 fStateRestore.set(NULL); |
| 388 fContext->setMatrix(fContextInitialMatrix); | 450 fContext->setMatrix(fContextInitialMatrix); |
| 389 GrTextContext::finish(); | 451 GrTextContext::finish(); |
| 390 } | 452 } |
| 391 | 453 |
| OLD | NEW |