blob: d33bc7a8bfd3395f565af138687e620749a90de5 [file] [log] [blame]
kkinnunenc6cb56f2014-06-24 00:12:27 -07001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrStencilAndCoverTextContext.h"
jvanverth8c27a182014-10-14 08:45:50 -07009#include "GrBitmapTextContext.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070010#include "GrDrawTarget.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070011#include "GrGpu.h"
12#include "GrPath.h"
cdaltonb85a0aa2014-07-21 15:32:44 -070013#include "GrPathRange.h"
jvanverthaab626c2014-10-16 08:04:39 -070014#include "SkAutoKern.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070015#include "SkDraw.h"
16#include "SkDrawProcs.h"
17#include "SkGlyphCache.h"
18#include "SkGpuDevice.h"
19#include "SkPath.h"
20#include "SkTextMapStateProc.h"
cdalton855d83f2014-09-18 13:51:53 -070021#include "SkTextFormatParams.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070022
23GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(
24 GrContext* context, const SkDeviceProperties& properties)
25 : GrTextContext(context, properties)
cdalton20b373c2014-12-01 08:38:55 -080026 , fStroke(SkStrokeRec::kFill_InitStyle)
27 , fQueuedGlyphCount(0)
28 , fFallbackGlyphsIdx(kGlyphBufferSize) {
kkinnunenc6cb56f2014-06-24 00:12:27 -070029}
30
jvanverth8c27a182014-10-14 08:45:50 -070031GrStencilAndCoverTextContext* GrStencilAndCoverTextContext::Create(GrContext* context,
32 const SkDeviceProperties& props) {
33 GrStencilAndCoverTextContext* textContext = SkNEW_ARGS(GrStencilAndCoverTextContext,
34 (context, props));
35 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, props);
36
37 return textContext;
38}
39
kkinnunenc6cb56f2014-06-24 00:12:27 -070040GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() {
41}
42
jvanverth0fedb192014-10-08 09:07:27 -070043bool GrStencilAndCoverTextContext::canDraw(const SkPaint& paint) {
44 if (paint.getRasterizer()) {
45 return false;
46 }
47 if (paint.getMaskFilter()) {
48 return false;
49 }
50 if (paint.getPathEffect()) {
51 return false;
52 }
53
54 // No hairlines unless we can map the 1 px width to the object space.
55 if (paint.getStyle() == SkPaint::kStroke_Style
56 && paint.getStrokeWidth() == 0
57 && fContext->getMatrix().hasPerspective()) {
58 return false;
59 }
60
61 // No color bitmap fonts.
62 SkScalerContext::Rec rec;
63 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec);
64 return rec.getFormat() != SkMask::kARGB32_Format;
65}
66
jvanverthaab626c2014-10-16 08:04:39 -070067void GrStencilAndCoverTextContext::onDrawText(const GrPaint& paint,
cdalton20b373c2014-12-01 08:38:55 -080068 const SkPaint& skPaint,
69 const char text[],
70 size_t byteLength,
71 SkScalar x, SkScalar y) {
jvanverthaab626c2014-10-16 08:04:39 -070072 SkASSERT(byteLength == 0 || text != NULL);
73
74 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
75 return;
76 }
77
78 // This is the slow path, mainly used by Skia unit tests. The other
79 // backends (8888, gpu, ...) use device-space dependent glyph caches. In
80 // order to match the glyph positions that the other code paths produce, we
81 // must also use device-space dependent glyph cache. This has the
82 // side-effect that the glyph shape outline will be in device-space,
83 // too. This in turn has the side-effect that NVPR can not stroke the paths,
84 // as the stroke in NVPR is defined in object-space.
85 // NOTE: here we have following coincidence that works at the moment:
86 // - When using the device-space glyphs, the transforms we pass to NVPR
87 // instanced drawing are the global transforms, and the view transform is
88 // identity. NVPR can not use non-affine transforms in the instanced
89 // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it
90 // will turn off the use of device-space glyphs when perspective transforms
91 // are in use.
92
cdalton38e13ad2014-11-07 06:02:15 -080093 this->init(paint, skPaint, byteLength, kMaxAccuracy_RenderMode);
jvanverthaab626c2014-10-16 08:04:39 -070094
95 // Transform our starting point.
cdalton20b373c2014-12-01 08:38:55 -080096 if (fUsingDeviceSpaceGlyphs) {
jvanverthaab626c2014-10-16 08:04:39 -070097 SkPoint loc;
98 fContextInitialMatrix.mapXY(x, y, &loc);
99 x = loc.fX;
100 y = loc.fY;
101 }
102
103 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
104
jvanverthaab626c2014-10-16 08:04:39 -0700105 const char* stop = text + byteLength;
106
107 // Measure first if needed.
108 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
109 SkFixed stopX = 0;
110 SkFixed stopY = 0;
111
112 const char* textPtr = text;
113 while (textPtr < stop) {
114 // We don't need x, y here, since all subpixel variants will have the
115 // same advance.
116 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &textPtr, 0, 0);
117
118 stopX += glyph.fAdvanceX;
119 stopY += glyph.fAdvanceY;
120 }
121 SkASSERT(textPtr == stop);
122
123 SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio;
124 SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio;
125
126 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
127 alignX = SkScalarHalf(alignX);
128 alignY = SkScalarHalf(alignY);
129 }
130
131 x -= alignX;
132 y -= alignY;
133 }
134
135 SkAutoKern autokern;
136
137 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio);
138
139 SkFixed fx = SkScalarToFixed(x);
140 SkFixed fy = SkScalarToFixed(y);
141 while (text < stop) {
142 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
143 fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio);
144 if (glyph.fWidth) {
cdalton20b373c2014-12-01 08:38:55 -0800145 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy)));
jvanverthaab626c2014-10-16 08:04:39 -0700146 }
147
148 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio);
149 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio);
150 }
151
152 this->finish();
153}
154
jvanverth8c27a182014-10-14 08:45:50 -0700155void GrStencilAndCoverTextContext::onDrawPosText(const GrPaint& paint,
cdalton20b373c2014-12-01 08:38:55 -0800156 const SkPaint& skPaint,
157 const char text[],
158 size_t byteLength,
159 const SkScalar pos[],
160 int scalarsPerPosition,
161 const SkPoint& offset) {
kkinnunenc6cb56f2014-06-24 00:12:27 -0700162 SkASSERT(byteLength == 0 || text != NULL);
163 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
164
165 // nothing to draw
166 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
167 return;
168 }
169
170 // 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
172 // position the glyphs at all, since the caller has done the positioning.
173 // The positioning is based on SkPaint::measureText of individual
174 // glyphs. That already uses glyph cache without device transforms. Device
175 // transform is not part of SkPaint::measureText API, and thus we use the
176 // same glyphs as what were measured.
kkinnunenc6cb56f2014-06-24 00:12:27 -0700177
cdalton38e13ad2014-11-07 06:02:15 -0800178 this->init(paint, skPaint, byteLength, kMaxPerformance_RenderMode);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700179
180 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
181
kkinnunenc6cb56f2014-06-24 00:12:27 -0700182 const char* stop = text + byteLength;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700183
cdalton38e13ad2014-11-07 06:02:15 -0800184 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
185 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign());
186 while (text < stop) {
187 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
188 if (glyph.fWidth) {
189 SkPoint tmsLoc;
190 tmsProc(pos, &tmsLoc);
191 SkPoint loc;
192 alignProc(tmsLoc, glyph, &loc);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700193
cdalton20b373c2014-12-01 08:38:55 -0800194 this->appendGlyph(glyph, loc);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700195 }
cdalton38e13ad2014-11-07 06:02:15 -0800196 pos += scalarsPerPosition;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700197 }
198
199 this->finish();
200}
201
cdalton855d83f2014-09-18 13:51:53 -0700202static GrPathRange* get_gr_glyphs(GrContext* ctx,
203 const SkTypeface* typeface,
204 const SkDescriptor* desc,
205 const SkStrokeRec& stroke) {
206 static const GrCacheID::Domain gGlyphsDomain = GrCacheID::GenerateDomain();
207
208 GrCacheID::Key key;
209 uint64_t* keyData = key.fData64;
210 keyData[0] = desc ? desc->getChecksum() : 0;
211 keyData[0] = (keyData[0] << 32) | (typeface ? typeface->uniqueID() : 0);
212 keyData[1] = GrPath::ComputeStrokeKey(stroke);
213 GrResourceKey resourceKey = GrResourceKey(GrCacheID(gGlyphsDomain, key),
214 GrPathRange::resourceType(), 0);
215
216 SkAutoTUnref<GrPathRange> glyphs(
217 static_cast<GrPathRange*>(ctx->findAndRefCachedResource(resourceKey)));
218 if (NULL == glyphs || (NULL != desc && !glyphs->isEqualTo(*desc))) {
219 glyphs.reset(ctx->getGpu()->pathRendering()->createGlyphs(typeface, desc, stroke));
220 ctx->addResourceToCache(resourceKey, glyphs);
221 }
222
223 return glyphs.detach();
224}
225
kkinnunenc6cb56f2014-06-24 00:12:27 -0700226void GrStencilAndCoverTextContext::init(const GrPaint& paint,
227 const SkPaint& skPaint,
cdaltonb2808cd2014-07-25 14:13:57 -0700228 size_t textByteLength,
cdalton38e13ad2014-11-07 06:02:15 -0800229 RenderMode renderMode) {
kkinnunenc6cb56f2014-06-24 00:12:27 -0700230 GrTextContext::init(paint, skPaint);
231
cdaltonb2808cd2014-07-25 14:13:57 -0700232 fContextInitialMatrix = fContext->getMatrix();
233
cdalton855d83f2014-09-18 13:51:53 -0700234 const bool otherBackendsWillDrawAsPaths =
cdaltonb2808cd2014-07-25 14:13:57 -0700235 SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700236
cdalton20b373c2014-12-01 08:38:55 -0800237 fUsingDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths &&
cdalton855d83f2014-09-18 13:51:53 -0700238 kMaxAccuracy_RenderMode == renderMode &&
239 SkToBool(fContextInitialMatrix.getType() &
240 (SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask));
kkinnunenc6cb56f2014-06-24 00:12:27 -0700241
cdalton20b373c2014-12-01 08:38:55 -0800242 if (fUsingDeviceSpaceGlyphs) {
cdalton855d83f2014-09-18 13:51:53 -0700243 // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms.
244 SkASSERT(!fContextInitialMatrix.hasPerspective());
cdaltonb2808cd2014-07-25 14:13:57 -0700245
cdalton20b373c2014-12-01 08:38:55 -0800246 // The whole shape (including stroke) will be baked into the glyph outlines. Make
247 // NVPR just fill the baked shapes.
248 fStroke = SkStrokeRec(SkStrokeRec::kFill_InitStyle);
249
cdalton855d83f2014-09-18 13:51:53 -0700250 fTextRatio = fTextInverseRatio = 1.0f;
251
252 // Glyphs loaded by GPU path rendering have an inverted y-direction.
253 SkMatrix m;
254 m.setScale(1, -1);
255 fContext->setMatrix(m);
256
257 // Post-flip the initial matrix so we're left with just the flip after
258 // the paint preConcats the inverse.
259 m = fContextInitialMatrix;
260 m.postScale(1, -1);
261 fPaint.localCoordChangeInverse(m);
262
cdalton855d83f2014-09-18 13:51:53 -0700263 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, &fContextInitialMatrix, false);
264 fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
cdalton20b373c2014-12-01 08:38:55 -0800265 &fGlyphCache->getDescriptor(), fStroke);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700266 } else {
cdalton855d83f2014-09-18 13:51:53 -0700267 // Don't bake strokes into the glyph outlines. We will stroke the glyphs
268 // using the GPU instead. This is the fast path.
cdalton20b373c2014-12-01 08:38:55 -0800269 fStroke = SkStrokeRec(fSkPaint);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700270 fSkPaint.setStyle(SkPaint::kFill_Style);
cdalton855d83f2014-09-18 13:51:53 -0700271
cdalton20b373c2014-12-01 08:38:55 -0800272 if (fStroke.isHairlineStyle()) {
cdalton855d83f2014-09-18 13:51:53 -0700273 // Approximate hairline stroke.
274 SkScalar strokeWidth = SK_Scalar1 /
275 (SkVector::Make(fContextInitialMatrix.getScaleX(),
276 fContextInitialMatrix.getSkewY()).length());
cdalton20b373c2014-12-01 08:38:55 -0800277 fStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/);
cdalton855d83f2014-09-18 13:51:53 -0700278
279 } else if (fSkPaint.isFakeBoldText() &&
280#ifdef SK_USE_FREETYPE_EMBOLDEN
281 kMaxPerformance_RenderMode == renderMode &&
282#endif
cdalton20b373c2014-12-01 08:38:55 -0800283 SkStrokeRec::kStroke_Style != fStroke.getStyle()) {
cdalton855d83f2014-09-18 13:51:53 -0700284
285 // Instead of baking fake bold into the glyph outlines, do it with the GPU stroke.
286 SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(),
287 kStdFakeBoldInterpKeys,
288 kStdFakeBoldInterpValues,
289 kStdFakeBoldInterpLength);
290 SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale);
cdalton20b373c2014-12-01 08:38:55 -0800291 fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
292 true /*strokeAndFill*/);
cdalton855d83f2014-09-18 13:51:53 -0700293
294 fSkPaint.setFakeBoldText(false);
295 }
296
297 bool canUseRawPaths;
298
299 if (otherBackendsWillDrawAsPaths || kMaxPerformance_RenderMode == renderMode) {
300 // We can draw the glyphs from canonically sized paths.
301 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
302 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();
303
304 // Compensate for the glyphs being scaled by fTextRatio.
cdalton20b373c2014-12-01 08:38:55 -0800305 if (!fStroke.isFillStyle()) {
306 fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
307 SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
cdalton855d83f2014-09-18 13:51:53 -0700308 }
309
310 fSkPaint.setLinearText(true);
311 fSkPaint.setLCDRenderText(false);
312 fSkPaint.setAutohinted(false);
313 fSkPaint.setHinting(SkPaint::kNo_Hinting);
314 fSkPaint.setSubpixelText(true);
315 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
316
317 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() &&
318 0 == fSkPaint.getTextSkewX() &&
319 !fSkPaint.isFakeBoldText() &&
320 !fSkPaint.isVerticalText();
321 } else {
322 fTextRatio = fTextInverseRatio = 1.0f;
323 canUseRawPaths = false;
324 }
325
326 SkMatrix textMatrix;
cdalton855d83f2014-09-18 13:51:53 -0700327 // Glyphs loaded by GPU path rendering have an inverted y-direction.
cdalton38e13ad2014-11-07 06:02:15 -0800328 textMatrix.setScale(fTextRatio, -fTextRatio);
cdalton855d83f2014-09-18 13:51:53 -0700329 fPaint.localCoordChange(textMatrix);
330 fContext->concatMatrix(textMatrix);
331
332 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, NULL, false);
333 fGlyphs = canUseRawPaths ?
cdalton20b373c2014-12-01 08:38:55 -0800334 get_gr_glyphs(fContext, fSkPaint.getTypeface(), NULL, fStroke) :
cdalton855d83f2014-09-18 13:51:53 -0700335 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
cdalton20b373c2014-12-01 08:38:55 -0800336 &fGlyphCache->getDescriptor(), fStroke);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700337 }
cdalton855d83f2014-09-18 13:51:53 -0700338
joshualitt9853cce2014-11-17 14:22:48 -0800339 fStateRestore.set(&fDrawState);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700340
joshualitt9853cce2014-11-17 14:22:48 -0800341 fDrawState.setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
kkinnunenc6cb56f2014-06-24 00:12:27 -0700342
343 GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
344 kZero_StencilOp,
345 kZero_StencilOp,
346 kNotEqual_StencilFunc,
347 0xffff,
348 0x0000,
349 0xffff);
350
joshualitt9853cce2014-11-17 14:22:48 -0800351 *fDrawState.stencil() = kStencilPass;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700352
cdalton20b373c2014-12-01 08:38:55 -0800353 SkASSERT(0 == fQueuedGlyphCount);
354 SkASSERT(kGlyphBufferSize == fFallbackGlyphsIdx);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700355}
356
cdalton20b373c2014-12-01 08:38:55 -0800357bool GrStencilAndCoverTextContext::mapToFallbackContext(GrContext::AutoMatrix& autoMatrix,
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 positions.
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
378inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) {
379 if (fQueuedGlyphCount >= fFallbackGlyphsIdx) {
380 SkASSERT(fQueuedGlyphCount == fFallbackGlyphsIdx);
cdaltonb2808cd2014-07-25 14:13:57 -0700381 this->flush();
382 }
383
cdalton20b373c2014-12-01 08:38:55 -0800384 // Stick the glyphs we can't draw at the end of the buffer, growing backwards.
385 int index = (SkMask::kARGB32_Format == glyph.fMaskFormat) ?
386 --fFallbackGlyphsIdx : fQueuedGlyphCount++;
cdaltonb85a0aa2014-07-21 15:32:44 -0700387
cdalton20b373c2014-12-01 08:38:55 -0800388 fGlyphIndices[index] = glyph.getGlyphID();
389 fGlyphPositions[index].set(fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y());
390}
391
392static 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;
cdaltonb85a0aa2014-07-21 15:32:44 -0700397}
398
399void GrStencilAndCoverTextContext::flush() {
cdalton20b373c2014-12-01 08:38:55 -0800400 if (fQueuedGlyphCount > 0) {
401 fDrawTarget->drawPaths(&fDrawState, fGlyphs,
402 fGlyphIndices, GrPathRange::kU16_PathIndexType,
403 get_xy_scalar_array(fGlyphPositions),
404 GrPathRendering::kTranslate_PathTransformType,
405 fQueuedGlyphCount, GrPathRendering::kWinding_FillType);
406
407 fQueuedGlyphCount = 0;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700408 }
409
cdalton20b373c2014-12-01 08:38:55 -0800410 if (fFallbackGlyphsIdx < kGlyphBufferSize) {
411 int fallbackGlyphCount = kGlyphBufferSize - fFallbackGlyphsIdx;
cdaltonb85a0aa2014-07-21 15:32:44 -0700412
cdalton20b373c2014-12-01 08:38:55 -0800413 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], fallbackGlyphCount);
427 }
428
429 fFallbackTextContext->drawPosText(paintFallback, skPaintFallback,
430 (char*)&fGlyphIndices[fFallbackGlyphsIdx],
431 2 * fallbackGlyphCount,
432 get_xy_scalar_array(&fGlyphPositions[fFallbackGlyphsIdx]),
433 2, SkPoint::Make(0, 0));
434
435 fFallbackGlyphsIdx = kGlyphBufferSize;
436 }
kkinnunenc6cb56f2014-06-24 00:12:27 -0700437}
438
439void GrStencilAndCoverTextContext::finish() {
cdaltonb85a0aa2014-07-21 15:32:44 -0700440 this->flush();
kkinnunenc6cb56f2014-06-24 00:12:27 -0700441
cdalton855d83f2014-09-18 13:51:53 -0700442 fGlyphs->unref();
cdaltonb85a0aa2014-07-21 15:32:44 -0700443 fGlyphs = NULL;
cdalton855d83f2014-09-18 13:51:53 -0700444
445 SkGlyphCache::AttachCache(fGlyphCache);
cdaltonb85a0aa2014-07-21 15:32:44 -0700446 fGlyphCache = NULL;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700447
joshualitt9853cce2014-11-17 14:22:48 -0800448 fDrawState.stencil()->setDisabled();
kkinnunenc6cb56f2014-06-24 00:12:27 -0700449 fStateRestore.set(NULL);
cdaltonb2808cd2014-07-25 14:13:57 -0700450 fContext->setMatrix(fContextInitialMatrix);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700451 GrTextContext::finish();
452}
453