blob: 61f7f864d72ae122bca549a618da7cda9810571c [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"
joshualitt1d89e8d2015-04-01 12:40:54 -07009#include "GrAtlasTextContext.h"
robertphillipsea461502015-05-26 11:38:03 -070010#include "GrDrawContext.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070011#include "GrDrawTarget.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070012#include "GrPath.h"
cdaltonb85a0aa2014-07-21 15:32:44 -070013#include "GrPathRange.h"
bsalomond309e7a2015-04-30 14:18:54 -070014#include "GrResourceProvider.h"
jvanverthaab626c2014-10-16 08:04:39 -070015#include "SkAutoKern.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070016#include "SkDraw.h"
17#include "SkDrawProcs.h"
18#include "SkGlyphCache.h"
19#include "SkGpuDevice.h"
20#include "SkPath.h"
21#include "SkTextMapStateProc.h"
cdalton855d83f2014-09-18 13:51:53 -070022#include "SkTextFormatParams.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070023
bsalomon1fcc01c2015-09-09 09:48:06 -070024#include "batches/GrDrawPathBatch.h"
25
joshualitt6e8cd962015-03-20 10:30:14 -070026GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context,
robertphillipsfcf78292015-06-19 11:49:52 -070027 const SkSurfaceProps& surfaceProps)
cdalton3bd909a2015-10-05 14:57:20 -070028 : INHERITED(context, surfaceProps) {
kkinnunenc6cb56f2014-06-24 00:12:27 -070029}
30
joshualitt6e8cd962015-03-20 10:30:14 -070031GrStencilAndCoverTextContext*
robertphillipsf6703fa2015-09-01 05:36:47 -070032GrStencilAndCoverTextContext::Create(GrContext* context, const SkSurfaceProps& surfaceProps) {
33 GrStencilAndCoverTextContext* textContext =
34 new GrStencilAndCoverTextContext(context, surfaceProps);
35 textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, surfaceProps);
jvanverth8c27a182014-10-14 08:45:50 -070036
37 return textContext;
38}
39
kkinnunenc6cb56f2014-06-24 00:12:27 -070040GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() {
41}
42
cdaltone68f7362015-03-25 14:02:37 -070043bool GrStencilAndCoverTextContext::canDraw(const GrRenderTarget* rt,
44 const GrClip& clip,
45 const GrPaint& paint,
46 const SkPaint& skPaint,
47 const SkMatrix& viewMatrix) {
48 if (skPaint.getRasterizer()) {
jvanverth0fedb192014-10-08 09:07:27 -070049 return false;
50 }
cdaltone68f7362015-03-25 14:02:37 -070051 if (skPaint.getMaskFilter()) {
jvanverth0fedb192014-10-08 09:07:27 -070052 return false;
53 }
kkinnunen50b58e62015-05-18 23:02:07 -070054 if (SkPathEffect* pe = skPaint.getPathEffect()) {
halcanary96fcdcc2015-08-27 07:41:13 -070055 if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) {
kkinnunen50b58e62015-05-18 23:02:07 -070056 return false;
57 }
jvanverth0fedb192014-10-08 09:07:27 -070058 }
cdalton7d5c9502015-10-03 13:28:35 -070059 // No hairlines. They would require new paths with customized strokes for every new draw matrix.
60 return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrokeWidth();
jvanverth0fedb192014-10-08 09:07:27 -070061}
62
robertphillipsf6703fa2015-09-01 05:36:47 -070063void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -080064 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -080065 const GrPaint& paint,
cdalton20b373c2014-12-01 08:38:55 -080066 const SkPaint& skPaint,
joshualitt5531d512014-12-17 15:50:11 -080067 const SkMatrix& viewMatrix,
cdalton20b373c2014-12-01 08:38:55 -080068 const char text[],
69 size_t byteLength,
joshualitt6e8cd962015-03-20 10:30:14 -070070 SkScalar x, SkScalar y,
71 const SkIRect& regionClipBounds) {
cdalton3bd909a2015-10-05 14:57:20 -070072 TextRun run(skPaint);
73 run.setText(text, byteLength, x, y, fContext, &fSurfaceProps);
74 run.draw(dc, rt, clip, paint, viewMatrix, regionClipBounds, fFallbackTextContext, skPaint);
75}
jvanverthaab626c2014-10-16 08:04:39 -070076
cdalton3bd909a2015-10-05 14:57:20 -070077void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarget* rt,
78 const GrClip& clip,
79 const GrPaint& paint,
80 const SkPaint& skPaint,
81 const SkMatrix& viewMatrix,
82 const char text[],
83 size_t byteLength,
84 const SkScalar pos[],
85 int scalarsPerPosition,
86 const SkPoint& offset,
87 const SkIRect& regionClipBounds) {
88 TextRun run(skPaint);
89 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset, fContext, &fSurfaceProps);
90 run.draw(dc, rt, clip, paint, viewMatrix, regionClipBounds, fFallbackTextContext, skPaint);
91}
92
93////////////////////////////////////////////////////////////////////////////////////////////////////
94
cdalton02015e52015-10-05 15:28:20 -070095class GrStencilAndCoverTextContext::FallbackBlobBuilder {
96public:
97 FallbackBlobBuilder() : fBuffIdx(0) {}
98
99 bool isInitialized() const { return SkToBool(fBuilder); }
100
101 void init(const SkPaint& font, SkScalar textRatio);
102
103 void appendGlyph(uint16_t glyphId, const SkPoint& pos);
104
105 const SkTextBlob* buildIfInitialized();
106
107private:
108 enum { kWriteBufferSize = 1024 };
109
110 void flush();
111
112 SkAutoTDelete<SkTextBlobBuilder> fBuilder;
113 SkPaint fFont;
114 int fBuffIdx;
115 uint16_t fGlyphIds[kWriteBufferSize];
116 SkPoint fPositions[kWriteBufferSize];
117};
118
119////////////////////////////////////////////////////////////////////////////////////////////////////
120
cdalton3bd909a2015-10-05 14:57:20 -0700121GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
122 : fStroke(fontAndStroke),
123 fFont(fontAndStroke) {
124 SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported.
125
126 // Setting to "fill" ensures that no strokes get baked into font outlines. (We use the GPU path
127 // rendering API for stroking).
128 fFont.setStyle(SkPaint::kFill_Style);
129
130 if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle()) {
131 // Instead of letting fake bold get baked into the glyph outlines, do it with GPU stroke.
132 SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(),
133 kStdFakeBoldInterpKeys,
134 kStdFakeBoldInterpValues,
135 kStdFakeBoldInterpLength);
136 SkScalar extra = SkScalarMul(fFont.getTextSize(), fakeBoldScale);
137 fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
138 true /*strokeAndFill*/);
139
140 fFont.setFakeBoldText(false);
jvanverthaab626c2014-10-16 08:04:39 -0700141 }
142
cdalton3bd909a2015-10-05 14:57:20 -0700143 if (!fFont.getPathEffect() && !fStroke.isDashed()) {
144 // We can draw the glyphs from canonically sized paths.
145 fTextRatio = fFont.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
146 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fFont.getTextSize();
jvanverthaab626c2014-10-16 08:04:39 -0700147
cdalton3bd909a2015-10-05 14:57:20 -0700148 // Compensate for the glyphs being scaled by fTextRatio.
149 if (!fStroke.isFillStyle()) {
150 fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
151 SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
152 }
153
154 fFont.setLinearText(true);
155 fFont.setLCDRenderText(false);
156 fFont.setAutohinted(false);
157 fFont.setHinting(SkPaint::kNo_Hinting);
158 fFont.setSubpixelText(true);
159 fFont.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
160
161 fUsingRawGlyphPaths = SK_Scalar1 == fFont.getTextScaleX() &&
162 0 == fFont.getTextSkewX() &&
163 !fFont.isFakeBoldText() &&
164 !fFont.isVerticalText();
165 } else {
166 fTextRatio = fTextInverseRatio = 1.0f;
167 fUsingRawGlyphPaths = false;
168 }
169
170 // When drawing from canonically sized paths, the actual local coords are fTextRatio * coords.
171 fLocalMatrix.setScale(fTextRatio, fTextRatio);
172}
173
174GrStencilAndCoverTextContext::TextRun::~TextRun() {
175}
176
177void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t byteLength,
178 SkScalar x, SkScalar y, GrContext* ctx,
179 const SkSurfaceProps* surfaceProps) {
180 SkASSERT(byteLength == 0 || text != nullptr);
181
182 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr);
183 SkGlyphCache* glyphCache = autoGlyphCache.getCache();
184
185 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache),
186 GrPathRendering::kTranslate_PathTransformType,
187 fFont.countText(text, byteLength)));
188
189 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc();
jvanverthaab626c2014-10-16 08:04:39 -0700190
jvanverthaab626c2014-10-16 08:04:39 -0700191 const char* stop = text + byteLength;
192
193 // Measure first if needed.
cdalton3bd909a2015-10-05 14:57:20 -0700194 if (fFont.getTextAlign() != SkPaint::kLeft_Align) {
jvanverthaab626c2014-10-16 08:04:39 -0700195 SkFixed stopX = 0;
196 SkFixed stopY = 0;
197
198 const char* textPtr = text;
199 while (textPtr < stop) {
200 // We don't need x, y here, since all subpixel variants will have the
201 // same advance.
cdalton3bd909a2015-10-05 14:57:20 -0700202 const SkGlyph& glyph = glyphCacheProc(glyphCache, &textPtr, 0, 0);
jvanverthaab626c2014-10-16 08:04:39 -0700203
204 stopX += glyph.fAdvanceX;
205 stopY += glyph.fAdvanceY;
206 }
207 SkASSERT(textPtr == stop);
208
209 SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio;
210 SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio;
211
cdalton3bd909a2015-10-05 14:57:20 -0700212 if (fFont.getTextAlign() == SkPaint::kCenter_Align) {
jvanverthaab626c2014-10-16 08:04:39 -0700213 alignX = SkScalarHalf(alignX);
214 alignY = SkScalarHalf(alignY);
215 }
216
217 x -= alignX;
218 y -= alignY;
219 }
220
221 SkAutoKern autokern;
222
223 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio);
224
225 SkFixed fx = SkScalarToFixed(x);
226 SkFixed fy = SkScalarToFixed(y);
cdalton02015e52015-10-05 15:28:20 -0700227 FallbackBlobBuilder fallback;
jvanverthaab626c2014-10-16 08:04:39 -0700228 while (text < stop) {
cdalton3bd909a2015-10-05 14:57:20 -0700229 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0);
bungemand709ea82015-03-17 07:23:39 -0700230 fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio);
jvanverthaab626c2014-10-16 08:04:39 -0700231 if (glyph.fWidth) {
cdalton02015e52015-10-05 15:28:20 -0700232 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy)),
233 &fallback);
jvanverthaab626c2014-10-16 08:04:39 -0700234 }
235
bungemand709ea82015-03-17 07:23:39 -0700236 fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio);
237 fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio);
jvanverthaab626c2014-10-16 08:04:39 -0700238 }
cdalton02015e52015-10-05 15:28:20 -0700239
240 fFallbackTextBlob.reset(fallback.buildIfInitialized());
jvanverthaab626c2014-10-16 08:04:39 -0700241}
242
cdalton3bd909a2015-10-05 14:57:20 -0700243void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t byteLength,
244 const SkScalar pos[], int scalarsPerPosition,
245 const SkPoint& offset, GrContext* ctx,
246 const SkSurfaceProps* surfaceProps) {
halcanary96fcdcc2015-08-27 07:41:13 -0700247 SkASSERT(byteLength == 0 || text != nullptr);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700248 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
249
cdalton3bd909a2015-10-05 14:57:20 -0700250 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr);
251 SkGlyphCache* glyphCache = autoGlyphCache.getCache();
kkinnunenc6cb56f2014-06-24 00:12:27 -0700252
cdalton3bd909a2015-10-05 14:57:20 -0700253 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache),
254 GrPathRendering::kTranslate_PathTransformType,
255 fFont.countText(text, byteLength)));
kkinnunenc6cb56f2014-06-24 00:12:27 -0700256
cdalton3bd909a2015-10-05 14:57:20 -0700257 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc();
kkinnunenc6cb56f2014-06-24 00:12:27 -0700258
kkinnunenc6cb56f2014-06-24 00:12:27 -0700259 const char* stop = text + byteLength;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700260
cdalton38e13ad2014-11-07 06:02:15 -0800261 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
cdalton3bd909a2015-10-05 14:57:20 -0700262 SkTextAlignProc alignProc(fFont.getTextAlign());
cdalton02015e52015-10-05 15:28:20 -0700263 FallbackBlobBuilder fallback;
cdalton38e13ad2014-11-07 06:02:15 -0800264 while (text < stop) {
cdalton3bd909a2015-10-05 14:57:20 -0700265 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0);
cdalton38e13ad2014-11-07 06:02:15 -0800266 if (glyph.fWidth) {
267 SkPoint tmsLoc;
268 tmsProc(pos, &tmsLoc);
269 SkPoint loc;
270 alignProc(tmsLoc, glyph, &loc);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700271
cdalton02015e52015-10-05 15:28:20 -0700272 this->appendGlyph(glyph, loc, &fallback);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700273 }
cdalton38e13ad2014-11-07 06:02:15 -0800274 pos += scalarsPerPosition;
kkinnunenc6cb56f2014-06-24 00:12:27 -0700275 }
cdalton02015e52015-10-05 15:28:20 -0700276
277 fFallbackTextBlob.reset(fallback.buildIfInitialized());
kkinnunenc6cb56f2014-06-24 00:12:27 -0700278}
279
cdalton3bd909a2015-10-05 14:57:20 -0700280GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx,
281 SkGlyphCache* glyphCache) {
282 SkTypeface* typeface = fUsingRawGlyphPaths ? fFont.getTypeface()
283 : glyphCache->getScalerContext()->getTypeface();
284 const SkDescriptor* desc = fUsingRawGlyphPaths ? nullptr : &glyphCache->getDescriptor();
kkinnunen50b58e62015-05-18 23:02:07 -0700285
286 static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain();
cdalton3bd909a2015-10-05 14:57:20 -0700287 int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt();
kkinnunen50b58e62015-05-18 23:02:07 -0700288 GrUniqueKey glyphKey;
289 GrUniqueKey::Builder builder(&glyphKey, kPathGlyphDomain, 2 + strokeDataCount);
290 reinterpret_cast<uint32_t&>(builder[0]) = desc ? desc->getChecksum() : 0;
291 reinterpret_cast<uint32_t&>(builder[1]) = typeface ? typeface->uniqueID() : 0;
292 if (strokeDataCount > 0) {
cdalton3bd909a2015-10-05 14:57:20 -0700293 fStroke.asUniqueKeyFragment(&builder[2]);
kkinnunen50b58e62015-05-18 23:02:07 -0700294 }
bsalomon24db3b12015-01-23 04:24:04 -0800295 builder.finish();
cdalton855d83f2014-09-18 13:51:53 -0700296
297 SkAutoTUnref<GrPathRange> glyphs(
kkinnunen50b58e62015-05-18 23:02:07 -0700298 static_cast<GrPathRange*>(
299 ctx->resourceProvider()->findAndRefResourceByUniqueKey(glyphKey)));
halcanary96fcdcc2015-08-27 07:41:13 -0700300 if (nullptr == glyphs) {
cdalton3bd909a2015-10-05 14:57:20 -0700301 glyphs.reset(ctx->resourceProvider()->createGlyphs(typeface, desc, fStroke));
kkinnunen50b58e62015-05-18 23:02:07 -0700302 ctx->resourceProvider()->assignUniqueKeyToResource(glyphKey, glyphs);
303 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700304 SkASSERT(nullptr == desc || glyphs->isEqualTo(*desc));
cdalton855d83f2014-09-18 13:51:53 -0700305 }
306
307 return glyphs.detach();
308}
309
cdalton3bd909a2015-10-05 14:57:20 -0700310inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& glyph,
cdalton02015e52015-10-05 15:28:20 -0700311 const SkPoint& pos,
312 FallbackBlobBuilder* fallback) {
313 // Stick the glyphs we can't draw into the fallback text blob.
bsalomon1fcc01c2015-09-09 09:48:06 -0700314 if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
cdalton02015e52015-10-05 15:28:20 -0700315 if (!fallback->isInitialized()) {
316 fallback->init(fFont, fTextRatio);
317 }
318 fallback->appendGlyph(glyph.getGlyphID(), pos);
bsalomon1fcc01c2015-09-09 09:48:06 -0700319 } else {
cdalton7d5c9502015-10-03 13:28:35 -0700320 float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * pos.y() };
bsalomon1fcc01c2015-09-09 09:48:06 -0700321 fDraw->append(glyph.getGlyphID(), translate);
cdaltonb2808cd2014-07-25 14:13:57 -0700322 }
cdalton20b373c2014-12-01 08:38:55 -0800323}
324
cdalton3bd909a2015-10-05 14:57:20 -0700325void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc,
326 GrRenderTarget* rt,
327 const GrClip& clip,
328 const GrPaint& paint,
329 const SkMatrix& viewMatrix,
330 const SkIRect& regionClipBounds,
331 GrTextContext* fallbackTextContext,
332 const SkPaint& originalSkPaint) const {
333 SkASSERT(fDraw);
robertphillipsea461502015-05-26 11:38:03 -0700334
cdalton3bd909a2015-10-05 14:57:20 -0700335 if (fDraw->count()) {
336 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
337 SkASSERT(rt->isStencilBufferMultisampled() || !paint.isAntiAlias());
338 pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, paint.isAntiAlias());
joshualitt7b670db2015-07-09 13:25:02 -0700339
340 GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
341 kZero_StencilOp,
vbuzinovc5d58f02015-08-21 05:24:24 -0700342 kKeep_StencilOp,
joshualitt7b670db2015-07-09 13:25:02 -0700343 kNotEqual_StencilFunc,
344 0xffff,
345 0x0000,
346 0xffff);
347
348 *pipelineBuilder.stencil() = kStencilPass;
349
cdalton3bd909a2015-10-05 14:57:20 -0700350 SkMatrix drawMatrix(viewMatrix);
351 drawMatrix.preScale(fTextRatio, fTextRatio);
352
353 dc->drawPathsFromRange(&pipelineBuilder, drawMatrix, fLocalMatrix, paint.getColor(), fDraw,
354 GrPathRendering::kWinding_FillType);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700355 }
356
cdalton02015e52015-10-05 15:28:20 -0700357 if (fFallbackTextBlob) {
cdalton3bd909a2015-10-05 14:57:20 -0700358 SkPaint fallbackSkPaint(originalSkPaint);
cdalton7d5c9502015-10-03 13:28:35 -0700359 fStroke.applyToPaint(&fallbackSkPaint);
360 if (!fStroke.isFillStyle()) {
361 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio);
cdalton20b373c2014-12-01 08:38:55 -0800362 }
cdalton20b373c2014-12-01 08:38:55 -0800363
cdalton02015e52015-10-05 15:28:20 -0700364 fallbackTextContext->drawTextBlob(dc, rt, clip, fallbackSkPaint, viewMatrix,
365 fFallbackTextBlob, 0, 0, nullptr, regionClipBounds);
cdalton20b373c2014-12-01 08:38:55 -0800366 }
kkinnunenc6cb56f2014-06-24 00:12:27 -0700367}
cdalton02015e52015-10-05 15:28:20 -0700368
369////////////////////////////////////////////////////////////////////////////////////////////////////
370
371void GrStencilAndCoverTextContext::FallbackBlobBuilder::init(const SkPaint& font,
372 SkScalar textRatio) {
373 SkASSERT(!this->isInitialized());
374 fBuilder.reset(new SkTextBlobBuilder);
375 fFont = font;
376 fFont.setTextAlign(SkPaint::kLeft_Align); // The glyph positions will already account for align.
377 fFont.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
378 // No need for subpixel positioning with bitmap glyphs. TODO: revisit if non-bitmap color glyphs
379 // show up and https://code.google.com/p/skia/issues/detail?id=4408 gets resolved.
380 fFont.setSubpixelText(false);
381 fFont.setTextSize(fFont.getTextSize() * textRatio);
382 fBuffIdx = 0;
383}
384
385void GrStencilAndCoverTextContext::FallbackBlobBuilder::appendGlyph(uint16_t glyphId,
386 const SkPoint& pos) {
387 SkASSERT(this->isInitialized());
388 if (fBuffIdx >= kWriteBufferSize) {
389 this->flush();
390 }
391 fGlyphIds[fBuffIdx] = glyphId;
392 fPositions[fBuffIdx] = pos;
393 fBuffIdx++;
394}
395
396void GrStencilAndCoverTextContext::FallbackBlobBuilder::flush() {
397 SkASSERT(this->isInitialized());
398 SkASSERT(fBuffIdx <= kWriteBufferSize);
399 if (!fBuffIdx) {
400 return;
401 }
402 // This will automatically merge with previous runs since we use the same font.
403 const SkTextBlobBuilder::RunBuffer& buff = fBuilder->allocRunPos(fFont, fBuffIdx);
404 memcpy(buff.glyphs, fGlyphIds, fBuffIdx * sizeof(uint16_t));
405 memcpy(buff.pos, fPositions[0].asScalars(), fBuffIdx * 2 * sizeof(SkScalar));
406 fBuffIdx = 0;
407}
408
409const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfInitialized() {
410 if (!this->isInitialized()) {
411 return nullptr;
412 }
413 this->flush();
414 return fBuilder->build();
415}