blob: 6447ca523a049efb55b689e74337fd93b183fb50 [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
joshualitt5531d512014-12-17 15:50:11 -080043bool GrStencilAndCoverTextContext::canDraw(const SkPaint& paint, const SkMatrix& viewMatrix) {
jvanverth0fedb192014-10-08 09:07:27 -070044 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
joshualitt5531d512014-12-17 15:50:11 -080057 && viewMatrix.hasPerspective()) {
jvanverth0fedb192014-10-08 09:07:27 -070058 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,
joshualitt5531d512014-12-17 15:50:11 -080069 const SkMatrix& viewMatrix,
cdalton20b373c2014-12-01 08:38:55 -080070 const char text[],
71 size_t byteLength,
72 SkScalar x, SkScalar y) {
jvanverthaab626c2014-10-16 08:04:39 -070073 SkASSERT(byteLength == 0 || text != NULL);
74
75 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
76 return;
77 }
78
79 // This is the slow path, mainly used by Skia unit tests. The other
80 // backends (8888, gpu, ...) use device-space dependent glyph caches. In
81 // order to match the glyph positions that the other code paths produce, we
82 // must also use device-space dependent glyph cache. This has the
83 // side-effect that the glyph shape outline will be in device-space,
84 // too. This in turn has the side-effect that NVPR can not stroke the paths,
85 // as the stroke in NVPR is defined in object-space.
86 // NOTE: here we have following coincidence that works at the moment:
87 // - When using the device-space glyphs, the transforms we pass to NVPR
88 // instanced drawing are the global transforms, and the view transform is
89 // identity. NVPR can not use non-affine transforms in the instanced
90 // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it
91 // will turn off the use of device-space glyphs when perspective transforms
92 // are in use.
93
joshualitt5531d512014-12-17 15:50:11 -080094 this->init(paint, skPaint, byteLength, kMaxAccuracy_RenderMode, viewMatrix);
jvanverthaab626c2014-10-16 08:04:39 -070095
96 // Transform our starting point.
cdalton20b373c2014-12-01 08:38:55 -080097 if (fUsingDeviceSpaceGlyphs) {
jvanverthaab626c2014-10-16 08:04:39 -070098 SkPoint loc;
99 fContextInitialMatrix.mapXY(x, y, &loc);
100 x = loc.fX;
101 y = loc.fY;
102 }
103
104 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
105
jvanverthaab626c2014-10-16 08:04:39 -0700106 const char* stop = text + byteLength;
107
108 // Measure first if needed.
109 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
110 SkFixed stopX = 0;
111 SkFixed stopY = 0;
112
113 const char* textPtr = text;
114 while (textPtr < stop) {
115 // We don't need x, y here, since all subpixel variants will have the
116 // same advance.
117 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &textPtr, 0, 0);
118
119 stopX += glyph.fAdvanceX;
120 stopY += glyph.fAdvanceY;
121 }
122 SkASSERT(textPtr == stop);
123
124 SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio;
125 SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio;
126
127 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
128 alignX = SkScalarHalf(alignX);
129 alignY = SkScalarHalf(alignY);
130 }
131
132 x -= alignX;
133 y -= alignY;
134 }
135
136 SkAutoKern autokern;
137
138 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio);
139
140 SkFixed fx = SkScalarToFixed(x);
141 SkFixed fy = SkScalarToFixed(y);
142 while (text < stop) {
143 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
144 fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio);
145 if (glyph.fWidth) {
cdalton20b373c2014-12-01 08:38:55 -0800146 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy)));
jvanverthaab626c2014-10-16 08:04:39 -0700147 }
148
149 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio);
150 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio);
151 }
152
153 this->finish();
154}
155
jvanverth8c27a182014-10-14 08:45:50 -0700156void GrStencilAndCoverTextContext::onDrawPosText(const GrPaint& paint,
cdalton20b373c2014-12-01 08:38:55 -0800157 const SkPaint& skPaint,
joshualitt5531d512014-12-17 15:50:11 -0800158 const SkMatrix& viewMatrix,
cdalton20b373c2014-12-01 08:38:55 -0800159 const char text[],
160 size_t byteLength,
161 const SkScalar pos[],
162 int scalarsPerPosition,
163 const SkPoint& offset) {
kkinnunenc6cb56f2014-06-24 00:12:27 -0700164 SkASSERT(byteLength == 0 || text != NULL);
165 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
166
167 // nothing to draw
168 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
169 return;
170 }
171
172 // This is the fast path. Here we do not bake in the device-transform to
173 // the glyph outline or the advances. This is because we do not need to
174 // position the glyphs at all, since the caller has done the positioning.
175 // The positioning is based on SkPaint::measureText of individual
176 // glyphs. That already uses glyph cache without device transforms. Device
177 // transform is not part of SkPaint::measureText API, and thus we use the
178 // same glyphs as what were measured.
kkinnunenc6cb56f2014-06-24 00:12:27 -0700179
joshualitt5531d512014-12-17 15:50:11 -0800180 this->init(paint, skPaint, byteLength, kMaxPerformance_RenderMode, viewMatrix);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700181
182 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
183
kkinnunenc6cb56f2014-06-24 00:12:27 -0700184 const char* stop = text + byteLength;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700185
cdalton38e13ad2014-11-07 06:02:15 -0800186 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
187 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign());
188 while (text < stop) {
189 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
190 if (glyph.fWidth) {
191 SkPoint tmsLoc;
192 tmsProc(pos, &tmsLoc);
193 SkPoint loc;
194 alignProc(tmsLoc, glyph, &loc);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700195
cdalton20b373c2014-12-01 08:38:55 -0800196 this->appendGlyph(glyph, loc);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700197 }
cdalton38e13ad2014-11-07 06:02:15 -0800198 pos += scalarsPerPosition;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700199 }
200
201 this->finish();
202}
203
cdalton855d83f2014-09-18 13:51:53 -0700204static GrPathRange* get_gr_glyphs(GrContext* ctx,
205 const SkTypeface* typeface,
206 const SkDescriptor* desc,
207 const SkStrokeRec& stroke) {
208 static const GrCacheID::Domain gGlyphsDomain = GrCacheID::GenerateDomain();
209
210 GrCacheID::Key key;
211 uint64_t* keyData = key.fData64;
212 keyData[0] = desc ? desc->getChecksum() : 0;
213 keyData[0] = (keyData[0] << 32) | (typeface ? typeface->uniqueID() : 0);
214 keyData[1] = GrPath::ComputeStrokeKey(stroke);
bsalomon7775c852014-12-30 12:50:52 -0800215 GrResourceKey resourceKey = GrResourceKey(GrCacheID(gGlyphsDomain, key), 0);
cdalton855d83f2014-09-18 13:51:53 -0700216
217 SkAutoTUnref<GrPathRange> glyphs(
218 static_cast<GrPathRange*>(ctx->findAndRefCachedResource(resourceKey)));
219 if (NULL == glyphs || (NULL != desc && !glyphs->isEqualTo(*desc))) {
220 glyphs.reset(ctx->getGpu()->pathRendering()->createGlyphs(typeface, desc, stroke));
221 ctx->addResourceToCache(resourceKey, glyphs);
222 }
223
224 return glyphs.detach();
225}
226
kkinnunenc6cb56f2014-06-24 00:12:27 -0700227void GrStencilAndCoverTextContext::init(const GrPaint& paint,
228 const SkPaint& skPaint,
cdaltonb2808cd2014-07-25 14:13:57 -0700229 size_t textByteLength,
joshualitt5531d512014-12-17 15:50:11 -0800230 RenderMode renderMode,
231 const SkMatrix& viewMatrix) {
kkinnunenc6cb56f2014-06-24 00:12:27 -0700232 GrTextContext::init(paint, skPaint);
233
joshualitt5531d512014-12-17 15:50:11 -0800234 fContextInitialMatrix = viewMatrix;
235 fViewMatrix = viewMatrix;
joshualitt290c09b2014-12-19 13:45:20 -0800236 fLocalMatrix = SkMatrix::I();
cdaltonb2808cd2014-07-25 14:13:57 -0700237
cdalton855d83f2014-09-18 13:51:53 -0700238 const bool otherBackendsWillDrawAsPaths =
cdaltonb2808cd2014-07-25 14:13:57 -0700239 SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700240
cdalton20b373c2014-12-01 08:38:55 -0800241 fUsingDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths &&
cdalton855d83f2014-09-18 13:51:53 -0700242 kMaxAccuracy_RenderMode == renderMode &&
243 SkToBool(fContextInitialMatrix.getType() &
244 (SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask));
kkinnunenc6cb56f2014-06-24 00:12:27 -0700245
cdalton20b373c2014-12-01 08:38:55 -0800246 if (fUsingDeviceSpaceGlyphs) {
cdalton855d83f2014-09-18 13:51:53 -0700247 // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms.
248 SkASSERT(!fContextInitialMatrix.hasPerspective());
cdaltonb2808cd2014-07-25 14:13:57 -0700249
cdalton20b373c2014-12-01 08:38:55 -0800250 // The whole shape (including stroke) will be baked into the glyph outlines. Make
251 // NVPR just fill the baked shapes.
252 fStroke = SkStrokeRec(SkStrokeRec::kFill_InitStyle);
253
cdalton855d83f2014-09-18 13:51:53 -0700254 fTextRatio = fTextInverseRatio = 1.0f;
255
256 // Glyphs loaded by GPU path rendering have an inverted y-direction.
257 SkMatrix m;
258 m.setScale(1, -1);
joshualitt5531d512014-12-17 15:50:11 -0800259 fViewMatrix = m;
cdalton855d83f2014-09-18 13:51:53 -0700260
261 // Post-flip the initial matrix so we're left with just the flip after
262 // the paint preConcats the inverse.
263 m = fContextInitialMatrix;
264 m.postScale(1, -1);
joshualitt290c09b2014-12-19 13:45:20 -0800265 if (!m.invert(&fLocalMatrix)) {
266 SkDebugf("Not invertible!\n");
267 return;
268 }
cdalton855d83f2014-09-18 13:51:53 -0700269
cdaltone05162d2014-12-01 08:57:33 -0800270 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, &fContextInitialMatrix,
271 true /*ignoreGamma*/);
cdalton855d83f2014-09-18 13:51:53 -0700272 fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
cdalton20b373c2014-12-01 08:38:55 -0800273 &fGlyphCache->getDescriptor(), fStroke);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700274 } else {
cdalton855d83f2014-09-18 13:51:53 -0700275 // Don't bake strokes into the glyph outlines. We will stroke the glyphs
276 // using the GPU instead. This is the fast path.
cdalton20b373c2014-12-01 08:38:55 -0800277 fStroke = SkStrokeRec(fSkPaint);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700278 fSkPaint.setStyle(SkPaint::kFill_Style);
cdalton855d83f2014-09-18 13:51:53 -0700279
cdalton20b373c2014-12-01 08:38:55 -0800280 if (fStroke.isHairlineStyle()) {
cdalton855d83f2014-09-18 13:51:53 -0700281 // Approximate hairline stroke.
282 SkScalar strokeWidth = SK_Scalar1 /
283 (SkVector::Make(fContextInitialMatrix.getScaleX(),
284 fContextInitialMatrix.getSkewY()).length());
cdalton20b373c2014-12-01 08:38:55 -0800285 fStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/);
cdalton855d83f2014-09-18 13:51:53 -0700286
287 } else if (fSkPaint.isFakeBoldText() &&
288#ifdef SK_USE_FREETYPE_EMBOLDEN
289 kMaxPerformance_RenderMode == renderMode &&
290#endif
cdalton20b373c2014-12-01 08:38:55 -0800291 SkStrokeRec::kStroke_Style != fStroke.getStyle()) {
cdalton855d83f2014-09-18 13:51:53 -0700292
293 // Instead of baking fake bold into the glyph outlines, do it with the GPU stroke.
294 SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(),
295 kStdFakeBoldInterpKeys,
296 kStdFakeBoldInterpValues,
297 kStdFakeBoldInterpLength);
298 SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale);
cdalton20b373c2014-12-01 08:38:55 -0800299 fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
300 true /*strokeAndFill*/);
cdalton855d83f2014-09-18 13:51:53 -0700301
302 fSkPaint.setFakeBoldText(false);
303 }
304
305 bool canUseRawPaths;
306
307 if (otherBackendsWillDrawAsPaths || kMaxPerformance_RenderMode == renderMode) {
308 // We can draw the glyphs from canonically sized paths.
309 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
310 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();
311
312 // Compensate for the glyphs being scaled by fTextRatio.
cdalton20b373c2014-12-01 08:38:55 -0800313 if (!fStroke.isFillStyle()) {
314 fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
315 SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
cdalton855d83f2014-09-18 13:51:53 -0700316 }
317
318 fSkPaint.setLinearText(true);
319 fSkPaint.setLCDRenderText(false);
320 fSkPaint.setAutohinted(false);
321 fSkPaint.setHinting(SkPaint::kNo_Hinting);
322 fSkPaint.setSubpixelText(true);
323 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
324
325 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() &&
326 0 == fSkPaint.getTextSkewX() &&
327 !fSkPaint.isFakeBoldText() &&
328 !fSkPaint.isVerticalText();
329 } else {
330 fTextRatio = fTextInverseRatio = 1.0f;
331 canUseRawPaths = false;
332 }
333
334 SkMatrix textMatrix;
cdalton855d83f2014-09-18 13:51:53 -0700335 // Glyphs loaded by GPU path rendering have an inverted y-direction.
cdalton38e13ad2014-11-07 06:02:15 -0800336 textMatrix.setScale(fTextRatio, -fTextRatio);
joshualitt5531d512014-12-17 15:50:11 -0800337 fViewMatrix.preConcat(textMatrix);
joshualitt290c09b2014-12-19 13:45:20 -0800338 fLocalMatrix = textMatrix;
cdalton855d83f2014-09-18 13:51:53 -0700339
cdaltone05162d2014-12-01 08:57:33 -0800340 fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, NULL, true /*ignoreGamma*/);
cdalton855d83f2014-09-18 13:51:53 -0700341 fGlyphs = canUseRawPaths ?
cdalton20b373c2014-12-01 08:38:55 -0800342 get_gr_glyphs(fContext, fSkPaint.getTypeface(), NULL, fStroke) :
cdalton855d83f2014-09-18 13:51:53 -0700343 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
cdalton20b373c2014-12-01 08:38:55 -0800344 &fGlyphCache->getDescriptor(), fStroke);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700345 }
cdalton855d83f2014-09-18 13:51:53 -0700346
joshualitt9853cce2014-11-17 14:22:48 -0800347 fStateRestore.set(&fDrawState);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700348
joshualitt8059eb92014-12-29 15:10:07 -0800349 fDrawState.setFromPaint(fPaint, fContext->getRenderTarget());
kkinnunenc6cb56f2014-06-24 00:12:27 -0700350
351 GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
352 kZero_StencilOp,
353 kZero_StencilOp,
354 kNotEqual_StencilFunc,
355 0xffff,
356 0x0000,
357 0xffff);
358
joshualitt9853cce2014-11-17 14:22:48 -0800359 *fDrawState.stencil() = kStencilPass;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700360
cdalton20b373c2014-12-01 08:38:55 -0800361 SkASSERT(0 == fQueuedGlyphCount);
362 SkASSERT(kGlyphBufferSize == fFallbackGlyphsIdx);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700363}
364
joshualitt5531d512014-12-17 15:50:11 -0800365bool GrStencilAndCoverTextContext::mapToFallbackContext(SkMatrix* inverse) {
cdalton20b373c2014-12-01 08:38:55 -0800366 // The current view matrix is flipped because GPU path rendering glyphs have an
367 // inverted y-direction. Unflip the view matrix for the fallback context. If using
368 // device-space glyphs, we'll also need to restore the original view matrix since
369 // we moved that transfomation into our local glyph cache for this scenario. Also
370 // track the inverse operation so the caller can unmap the paint and glyph positions.
371 if (fUsingDeviceSpaceGlyphs) {
joshualitt5531d512014-12-17 15:50:11 -0800372 fViewMatrix = fContextInitialMatrix;
cdalton20b373c2014-12-01 08:38:55 -0800373 if (!fContextInitialMatrix.invert(inverse)) {
374 return false;
375 }
376 inverse->preScale(1, -1);
377 } else {
378 inverse->setScale(1, -1);
379 const SkMatrix& unflip = *inverse; // unflip is equal to its own inverse.
joshualitt5531d512014-12-17 15:50:11 -0800380 fViewMatrix.preConcat(unflip);
cdalton20b373c2014-12-01 08:38:55 -0800381 }
382 return true;
383}
384
385inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) {
386 if (fQueuedGlyphCount >= fFallbackGlyphsIdx) {
387 SkASSERT(fQueuedGlyphCount == fFallbackGlyphsIdx);
cdaltonb2808cd2014-07-25 14:13:57 -0700388 this->flush();
389 }
390
cdalton20b373c2014-12-01 08:38:55 -0800391 // Stick the glyphs we can't draw at the end of the buffer, growing backwards.
392 int index = (SkMask::kARGB32_Format == glyph.fMaskFormat) ?
393 --fFallbackGlyphsIdx : fQueuedGlyphCount++;
cdaltonb85a0aa2014-07-21 15:32:44 -0700394
cdalton20b373c2014-12-01 08:38:55 -0800395 fGlyphIndices[index] = glyph.getGlyphID();
396 fGlyphPositions[index].set(fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y());
397}
398
399static const SkScalar* get_xy_scalar_array(const SkPoint* pointArray) {
400 GR_STATIC_ASSERT(2 * sizeof(SkScalar) == sizeof(SkPoint));
401 GR_STATIC_ASSERT(0 == offsetof(SkPoint, fX));
402
403 return &pointArray[0].fX;
cdaltonb85a0aa2014-07-21 15:32:44 -0700404}
405
406void GrStencilAndCoverTextContext::flush() {
cdalton20b373c2014-12-01 08:38:55 -0800407 if (fQueuedGlyphCount > 0) {
joshualitt8059eb92014-12-29 15:10:07 -0800408 SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(fPaint.getColor(),
409 fViewMatrix,
410 fLocalMatrix));
joshualitt56995b52014-12-11 15:44:02 -0800411 fDrawTarget->drawPaths(&fDrawState, pp, fGlyphs,
cdalton20b373c2014-12-01 08:38:55 -0800412 fGlyphIndices, GrPathRange::kU16_PathIndexType,
413 get_xy_scalar_array(fGlyphPositions),
414 GrPathRendering::kTranslate_PathTransformType,
415 fQueuedGlyphCount, GrPathRendering::kWinding_FillType);
416
417 fQueuedGlyphCount = 0;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700418 }
419
cdalton20b373c2014-12-01 08:38:55 -0800420 if (fFallbackGlyphsIdx < kGlyphBufferSize) {
421 int fallbackGlyphCount = kGlyphBufferSize - fFallbackGlyphsIdx;
cdaltonb85a0aa2014-07-21 15:32:44 -0700422
cdalton20b373c2014-12-01 08:38:55 -0800423 GrPaint paintFallback(fPaint);
424
425 SkPaint skPaintFallback(fSkPaint);
426 if (!fUsingDeviceSpaceGlyphs) {
427 fStroke.applyToPaint(&skPaintFallback);
428 }
429 skPaintFallback.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for.
430 skPaintFallback.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
431
cdalton20b373c2014-12-01 08:38:55 -0800432 SkMatrix inverse;
joshualitt5531d512014-12-17 15:50:11 -0800433 if (this->mapToFallbackContext(&inverse)) {
cdalton20b373c2014-12-01 08:38:55 -0800434 inverse.mapPoints(&fGlyphPositions[fFallbackGlyphsIdx], fallbackGlyphCount);
435 }
436
joshualitt5531d512014-12-17 15:50:11 -0800437 fFallbackTextContext->drawPosText(paintFallback, skPaintFallback, fViewMatrix,
cdalton20b373c2014-12-01 08:38:55 -0800438 (char*)&fGlyphIndices[fFallbackGlyphsIdx],
439 2 * fallbackGlyphCount,
440 get_xy_scalar_array(&fGlyphPositions[fFallbackGlyphsIdx]),
441 2, SkPoint::Make(0, 0));
442
443 fFallbackGlyphsIdx = kGlyphBufferSize;
444 }
kkinnunenc6cb56f2014-06-24 00:12:27 -0700445}
446
447void GrStencilAndCoverTextContext::finish() {
cdaltonb85a0aa2014-07-21 15:32:44 -0700448 this->flush();
kkinnunenc6cb56f2014-06-24 00:12:27 -0700449
cdalton855d83f2014-09-18 13:51:53 -0700450 fGlyphs->unref();
cdaltonb85a0aa2014-07-21 15:32:44 -0700451 fGlyphs = NULL;
cdalton855d83f2014-09-18 13:51:53 -0700452
453 SkGlyphCache::AttachCache(fGlyphCache);
cdaltonb85a0aa2014-07-21 15:32:44 -0700454 fGlyphCache = NULL;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700455
joshualitt9853cce2014-11-17 14:22:48 -0800456 fDrawState.stencil()->setDisabled();
kkinnunenc6cb56f2014-06-24 00:12:27 -0700457 fStateRestore.set(NULL);
joshualitt5531d512014-12-17 15:50:11 -0800458 fViewMatrix = fContextInitialMatrix;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700459 GrTextContext::finish();
460}
461