blob: bf1e58dae85779c292393e0967a226c6aa3e052e [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
cdaltone05162d2014-12-01 08:57:33 -0800263 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, &fContextInitialMatrix,
264 true /*ignoreGamma*/);
cdalton855d83f2014-09-18 13:51:53 -0700265 fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
cdalton20b373c2014-12-01 08:38:55 -0800266 &fGlyphCache->getDescriptor(), fStroke);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700267 } else {
cdalton855d83f2014-09-18 13:51:53 -0700268 // Don't bake strokes into the glyph outlines. We will stroke the glyphs
269 // using the GPU instead. This is the fast path.
cdalton20b373c2014-12-01 08:38:55 -0800270 fStroke = SkStrokeRec(fSkPaint);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700271 fSkPaint.setStyle(SkPaint::kFill_Style);
cdalton855d83f2014-09-18 13:51:53 -0700272
cdalton20b373c2014-12-01 08:38:55 -0800273 if (fStroke.isHairlineStyle()) {
cdalton855d83f2014-09-18 13:51:53 -0700274 // Approximate hairline stroke.
275 SkScalar strokeWidth = SK_Scalar1 /
276 (SkVector::Make(fContextInitialMatrix.getScaleX(),
277 fContextInitialMatrix.getSkewY()).length());
cdalton20b373c2014-12-01 08:38:55 -0800278 fStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/);
cdalton855d83f2014-09-18 13:51:53 -0700279
280 } else if (fSkPaint.isFakeBoldText() &&
281#ifdef SK_USE_FREETYPE_EMBOLDEN
282 kMaxPerformance_RenderMode == renderMode &&
283#endif
cdalton20b373c2014-12-01 08:38:55 -0800284 SkStrokeRec::kStroke_Style != fStroke.getStyle()) {
cdalton855d83f2014-09-18 13:51:53 -0700285
286 // Instead of baking fake bold into the glyph outlines, do it with the GPU stroke.
287 SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(),
288 kStdFakeBoldInterpKeys,
289 kStdFakeBoldInterpValues,
290 kStdFakeBoldInterpLength);
291 SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale);
cdalton20b373c2014-12-01 08:38:55 -0800292 fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
293 true /*strokeAndFill*/);
cdalton855d83f2014-09-18 13:51:53 -0700294
295 fSkPaint.setFakeBoldText(false);
296 }
297
298 bool canUseRawPaths;
299
300 if (otherBackendsWillDrawAsPaths || kMaxPerformance_RenderMode == renderMode) {
301 // We can draw the glyphs from canonically sized paths.
302 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
303 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();
304
305 // Compensate for the glyphs being scaled by fTextRatio.
cdalton20b373c2014-12-01 08:38:55 -0800306 if (!fStroke.isFillStyle()) {
307 fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
308 SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
cdalton855d83f2014-09-18 13:51:53 -0700309 }
310
311 fSkPaint.setLinearText(true);
312 fSkPaint.setLCDRenderText(false);
313 fSkPaint.setAutohinted(false);
314 fSkPaint.setHinting(SkPaint::kNo_Hinting);
315 fSkPaint.setSubpixelText(true);
316 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
317
318 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() &&
319 0 == fSkPaint.getTextSkewX() &&
320 !fSkPaint.isFakeBoldText() &&
321 !fSkPaint.isVerticalText();
322 } else {
323 fTextRatio = fTextInverseRatio = 1.0f;
324 canUseRawPaths = false;
325 }
326
327 SkMatrix textMatrix;
cdalton855d83f2014-09-18 13:51:53 -0700328 // Glyphs loaded by GPU path rendering have an inverted y-direction.
cdalton38e13ad2014-11-07 06:02:15 -0800329 textMatrix.setScale(fTextRatio, -fTextRatio);
cdalton855d83f2014-09-18 13:51:53 -0700330 fPaint.localCoordChange(textMatrix);
331 fContext->concatMatrix(textMatrix);
332
cdaltone05162d2014-12-01 08:57:33 -0800333 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, NULL, true /*ignoreGamma*/);
cdalton855d83f2014-09-18 13:51:53 -0700334 fGlyphs = canUseRawPaths ?
cdalton20b373c2014-12-01 08:38:55 -0800335 get_gr_glyphs(fContext, fSkPaint.getTypeface(), NULL, fStroke) :
cdalton855d83f2014-09-18 13:51:53 -0700336 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
cdalton20b373c2014-12-01 08:38:55 -0800337 &fGlyphCache->getDescriptor(), fStroke);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700338 }
cdalton855d83f2014-09-18 13:51:53 -0700339
joshualitt9853cce2014-11-17 14:22:48 -0800340 fStateRestore.set(&fDrawState);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700341
joshualitt9853cce2014-11-17 14:22:48 -0800342 fDrawState.setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
kkinnunenc6cb56f2014-06-24 00:12:27 -0700343
344 GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
345 kZero_StencilOp,
346 kZero_StencilOp,
347 kNotEqual_StencilFunc,
348 0xffff,
349 0x0000,
350 0xffff);
351
joshualitt9853cce2014-11-17 14:22:48 -0800352 *fDrawState.stencil() = kStencilPass;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700353
cdalton20b373c2014-12-01 08:38:55 -0800354 SkASSERT(0 == fQueuedGlyphCount);
355 SkASSERT(kGlyphBufferSize == fFallbackGlyphsIdx);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700356}
357
cdalton20b373c2014-12-01 08:38:55 -0800358bool GrStencilAndCoverTextContext::mapToFallbackContext(GrContext::AutoMatrix& autoMatrix,
359 SkMatrix* inverse) {
360 // The current view matrix is flipped because GPU path rendering glyphs have an
361 // inverted y-direction. Unflip the view matrix for the fallback context. If using
362 // device-space glyphs, we'll also need to restore the original view matrix since
363 // we moved that transfomation into our local glyph cache for this scenario. Also
364 // track the inverse operation so the caller can unmap the paint and glyph positions.
365 if (fUsingDeviceSpaceGlyphs) {
366 autoMatrix.set(fContext, fContextInitialMatrix);
367 if (!fContextInitialMatrix.invert(inverse)) {
368 return false;
369 }
370 inverse->preScale(1, -1);
371 } else {
372 inverse->setScale(1, -1);
373 const SkMatrix& unflip = *inverse; // unflip is equal to its own inverse.
374 autoMatrix.setPreConcat(fContext, unflip);
375 }
376 return true;
377}
378
379inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) {
380 if (fQueuedGlyphCount >= fFallbackGlyphsIdx) {
381 SkASSERT(fQueuedGlyphCount == fFallbackGlyphsIdx);
cdaltonb2808cd2014-07-25 14:13:57 -0700382 this->flush();
383 }
384
cdalton20b373c2014-12-01 08:38:55 -0800385 // Stick the glyphs we can't draw at the end of the buffer, growing backwards.
386 int index = (SkMask::kARGB32_Format == glyph.fMaskFormat) ?
387 --fFallbackGlyphsIdx : fQueuedGlyphCount++;
cdaltonb85a0aa2014-07-21 15:32:44 -0700388
cdalton20b373c2014-12-01 08:38:55 -0800389 fGlyphIndices[index] = glyph.getGlyphID();
390 fGlyphPositions[index].set(fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y());
391}
392
393static const SkScalar* get_xy_scalar_array(const SkPoint* pointArray) {
394 GR_STATIC_ASSERT(2 * sizeof(SkScalar) == sizeof(SkPoint));
395 GR_STATIC_ASSERT(0 == offsetof(SkPoint, fX));
396
397 return &pointArray[0].fX;
cdaltonb85a0aa2014-07-21 15:32:44 -0700398}
399
400void GrStencilAndCoverTextContext::flush() {
cdalton20b373c2014-12-01 08:38:55 -0800401 if (fQueuedGlyphCount > 0) {
joshualitt8c0f6152014-12-10 14:12:22 -0800402 fDrawTarget->drawPaths(&fDrawState, fPaint.getColor(), fGlyphs,
cdalton20b373c2014-12-01 08:38:55 -0800403 fGlyphIndices, GrPathRange::kU16_PathIndexType,
404 get_xy_scalar_array(fGlyphPositions),
405 GrPathRendering::kTranslate_PathTransformType,
406 fQueuedGlyphCount, GrPathRendering::kWinding_FillType);
407
408 fQueuedGlyphCount = 0;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700409 }
410
cdalton20b373c2014-12-01 08:38:55 -0800411 if (fFallbackGlyphsIdx < kGlyphBufferSize) {
412 int fallbackGlyphCount = kGlyphBufferSize - fFallbackGlyphsIdx;
cdaltonb85a0aa2014-07-21 15:32:44 -0700413
cdalton20b373c2014-12-01 08:38:55 -0800414 GrPaint paintFallback(fPaint);
415
416 SkPaint skPaintFallback(fSkPaint);
417 if (!fUsingDeviceSpaceGlyphs) {
418 fStroke.applyToPaint(&skPaintFallback);
419 }
420 skPaintFallback.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for.
421 skPaintFallback.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
422
423 GrContext::AutoMatrix autoMatrix;
424 SkMatrix inverse;
425 if (this->mapToFallbackContext(autoMatrix, &inverse)) {
426 paintFallback.localCoordChangeInverse(inverse);
427 inverse.mapPoints(&fGlyphPositions[fFallbackGlyphsIdx], fallbackGlyphCount);
428 }
429
430 fFallbackTextContext->drawPosText(paintFallback, skPaintFallback,
431 (char*)&fGlyphIndices[fFallbackGlyphsIdx],
432 2 * fallbackGlyphCount,
433 get_xy_scalar_array(&fGlyphPositions[fFallbackGlyphsIdx]),
434 2, SkPoint::Make(0, 0));
435
436 fFallbackGlyphsIdx = kGlyphBufferSize;
437 }
kkinnunenc6cb56f2014-06-24 00:12:27 -0700438}
439
440void GrStencilAndCoverTextContext::finish() {
cdaltonb85a0aa2014-07-21 15:32:44 -0700441 this->flush();
kkinnunenc6cb56f2014-06-24 00:12:27 -0700442
cdalton855d83f2014-09-18 13:51:53 -0700443 fGlyphs->unref();
cdaltonb85a0aa2014-07-21 15:32:44 -0700444 fGlyphs = NULL;
cdalton855d83f2014-09-18 13:51:53 -0700445
446 SkGlyphCache::AttachCache(fGlyphCache);
cdaltonb85a0aa2014-07-21 15:32:44 -0700447 fGlyphCache = NULL;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700448
joshualitt9853cce2014-11-17 14:22:48 -0800449 fDrawState.stencil()->setDisabled();
kkinnunenc6cb56f2014-06-24 00:12:27 -0700450 fStateRestore.set(NULL);
cdaltonb2808cd2014-07-25 14:13:57 -0700451 fContext->setMatrix(fContextInitialMatrix);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700452 GrTextContext::finish();
453}
454