blob: 59ecbc0fbabe03ad1235ed23b42795a19ea12e7d [file] [log] [blame]
joshualitt0a42e682015-12-10 13:20:58 -08001/*
2 * Copyright 2015 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 "GrTextUtils.h"
9
joshualitt29677982015-12-11 06:08:59 -080010#include "GrAtlasTextBlob.h"
11#include "GrBatchFontCache.h"
joshualitt0a42e682015-12-10 13:20:58 -080012#include "GrBlurUtils.h"
joshualitt0d2199b2016-01-20 06:36:09 -080013#include "GrCaps.h"
joshualitt0a42e682015-12-10 13:20:58 -080014#include "GrContext.h"
15#include "GrDrawContext.h"
joshualitt0d2199b2016-01-20 06:36:09 -080016
17#include "SkDistanceFieldGen.h"
joshualitt0a42e682015-12-10 13:20:58 -080018#include "SkDrawProcs.h"
joshualitt29677982015-12-11 06:08:59 -080019#include "SkFindAndPlaceGlyph.h"
joshualitt0a42e682015-12-10 13:20:58 -080020#include "SkGlyphCache.h"
21#include "SkPaint.h"
22#include "SkRect.h"
23#include "SkTextMapStateProc.h"
24#include "SkTextToPathIter.h"
25
joshualitt0d2199b2016-01-20 06:36:09 -080026namespace {
27static const int kMinDFFontSize = 18;
28static const int kSmallDFFontSize = 32;
29static const int kSmallDFFontLimit = 32;
30static const int kMediumDFFontSize = 72;
31static const int kMediumDFFontLimit = 72;
32static const int kLargeDFFontSize = 162;
33#ifdef SK_BUILD_FOR_ANDROID
34static const int kLargeDFFontLimit = 384;
35#else
36static const int kLargeDFFontLimit = 2 * kLargeDFFontSize;
37#endif
38};
39
joshualitt29677982015-12-11 06:08:59 -080040void GrTextUtils::DrawBmpText(GrAtlasTextBlob* blob, int runIndex,
41 GrBatchFontCache* fontCache,
joshualitte76b4bb32015-12-28 07:23:58 -080042 const SkSurfaceProps& props, const SkPaint& skPaint,
joshualitt29677982015-12-11 06:08:59 -080043 GrColor color,
44 const SkMatrix& viewMatrix,
45 const char text[], size_t byteLength,
46 SkScalar x, SkScalar y) {
47 SkASSERT(byteLength == 0 || text != nullptr);
48
49 // nothing to draw
50 if (text == nullptr || byteLength == 0) {
51 return;
52 }
53
joshualitta6bf4c52016-01-19 06:59:29 -080054 // Ensure the blob is set for bitmaptext
55 blob->setHasBitmap();
56
joshualitt29677982015-12-11 06:08:59 -080057 GrBatchTextStrike* currStrike = nullptr;
58
59 // Get GrFontScaler from cache
joshualitte76b4bb32015-12-28 07:23:58 -080060 SkGlyphCache* cache = blob->setupCache(runIndex, props, skPaint, &viewMatrix, false);
joshualitt8e84a1e2016-02-16 11:09:25 -080061 GrFontScaler* fontScaler = GrTextUtils::GetGrFontScaler(cache);
joshualitt29677982015-12-11 06:08:59 -080062
63 SkFindAndPlaceGlyph::ProcessText(
64 skPaint.getTextEncoding(), text, byteLength,
65 {x, y}, viewMatrix, skPaint.getTextAlign(),
66 cache,
67 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
68 position += rounding;
69 BmpAppendGlyph(
70 blob, runIndex, fontCache, &currStrike, glyph,
71 SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY),
72 color, fontScaler);
73 }
74 );
joshualitte76b4bb32015-12-28 07:23:58 -080075
76 SkGlyphCache::AttachCache(cache);
joshualitt29677982015-12-11 06:08:59 -080077}
78
79void GrTextUtils::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex,
80 GrBatchFontCache* fontCache,
joshualitte76b4bb32015-12-28 07:23:58 -080081 const SkSurfaceProps& props, const SkPaint& skPaint,
joshualitt29677982015-12-11 06:08:59 -080082 GrColor color,
83 const SkMatrix& viewMatrix,
84 const char text[], size_t byteLength,
85 const SkScalar pos[], int scalarsPerPosition,
86 const SkPoint& offset) {
87 SkASSERT(byteLength == 0 || text != nullptr);
88 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
89
90 // nothing to draw
91 if (text == nullptr || byteLength == 0) {
92 return;
93 }
94
joshualitta6bf4c52016-01-19 06:59:29 -080095 // Ensure the blob is set for bitmaptext
96 blob->setHasBitmap();
97
joshualitt29677982015-12-11 06:08:59 -080098 GrBatchTextStrike* currStrike = nullptr;
99
100 // Get GrFontScaler from cache
joshualitte76b4bb32015-12-28 07:23:58 -0800101 SkGlyphCache* cache = blob->setupCache(runIndex, props, skPaint, &viewMatrix, false);
joshualitt8e84a1e2016-02-16 11:09:25 -0800102 GrFontScaler* fontScaler = GrTextUtils::GetGrFontScaler(cache);
joshualitt29677982015-12-11 06:08:59 -0800103
104 SkFindAndPlaceGlyph::ProcessPosText(
105 skPaint.getTextEncoding(), text, byteLength,
106 offset, viewMatrix, pos, scalarsPerPosition,
107 skPaint.getTextAlign(), cache,
108 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
109 position += rounding;
110 BmpAppendGlyph(
111 blob, runIndex, fontCache, &currStrike, glyph,
112 SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY),
113 color, fontScaler);
114 }
115 );
joshualitte76b4bb32015-12-28 07:23:58 -0800116
117 SkGlyphCache::AttachCache(cache);
joshualitt29677982015-12-11 06:08:59 -0800118}
119
120void GrTextUtils::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex,
121 GrBatchFontCache* fontCache,
122 GrBatchTextStrike** strike, const SkGlyph& skGlyph,
123 int vx, int vy, GrColor color, GrFontScaler* scaler) {
124 if (!*strike) {
125 *strike = fontCache->getStrike(scaler);
126 }
127
128 GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
129 skGlyph.getSubXFixed(),
130 skGlyph.getSubYFixed(),
131 GrGlyph::kCoverage_MaskStyle);
132 GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, scaler);
133 if (!glyph) {
134 return;
135 }
136
137 int x = vx + glyph->fBounds.fLeft;
138 int y = vy + glyph->fBounds.fTop;
139
140 // keep them as ints until we've done the clip-test
141 int width = glyph->fBounds.width();
142 int height = glyph->fBounds.height();
143
144 SkRect r;
145 r.fLeft = SkIntToScalar(x);
146 r.fTop = SkIntToScalar(y);
147 r.fRight = r.fLeft + SkIntToScalar(width);
148 r.fBottom = r.fTop + SkIntToScalar(height);
149
150 blob->appendGlyph(runIndex, r, color, *strike, glyph, scaler, skGlyph,
151 SkIntToScalar(vx), SkIntToScalar(vy), 1.0f, false);
152}
153
joshualitt0d2199b2016-01-20 06:36:09 -0800154bool GrTextUtils::CanDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix& viewMatrix,
155 const SkSurfaceProps& props, const GrShaderCaps& caps) {
156 // TODO: support perspective (need getMaxScale replacement)
157 if (viewMatrix.hasPerspective()) {
158 return false;
159 }
160
161 SkScalar maxScale = viewMatrix.getMaxScale();
162 SkScalar scaledTextSize = maxScale*skPaint.getTextSize();
163 // Hinted text looks far better at small resolutions
164 // Scaling up beyond 2x yields undesireable artifacts
165 if (scaledTextSize < kMinDFFontSize ||
166 scaledTextSize > kLargeDFFontLimit) {
167 return false;
168 }
169
170 bool useDFT = props.isUseDeviceIndependentFonts();
171#if SK_FORCE_DISTANCE_FIELD_TEXT
172 useDFT = true;
173#endif
174
175 if (!useDFT && scaledTextSize < kLargeDFFontSize) {
176 return false;
177 }
178
179 // rasterizers and mask filters modify alpha, which doesn't
180 // translate well to distance
181 if (skPaint.getRasterizer() || skPaint.getMaskFilter() || !caps.shaderDerivativeSupport()) {
182 return false;
183 }
184
185 // TODO: add some stroking support
186 if (skPaint.getStyle() != SkPaint::kFill_Style) {
187 return false;
188 }
189
190 return true;
191}
192
193void GrTextUtils::InitDistanceFieldPaint(GrAtlasTextBlob* blob,
194 SkPaint* skPaint,
195 SkScalar* textRatio,
196 const SkMatrix& viewMatrix) {
197 // getMaxScale doesn't support perspective, so neither do we at the moment
198 SkASSERT(!viewMatrix.hasPerspective());
199 SkScalar maxScale = viewMatrix.getMaxScale();
200 SkScalar textSize = skPaint->getTextSize();
201 SkScalar scaledTextSize = textSize;
202 // if we have non-unity scale, we need to choose our base text size
203 // based on the SkPaint's text size multiplied by the max scale factor
204 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
205 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
206 scaledTextSize *= maxScale;
207 }
208
209 // We have three sizes of distance field text, and within each size 'bucket' there is a floor
210 // and ceiling. A scale outside of this range would require regenerating the distance fields
211 SkScalar dfMaskScaleFloor;
212 SkScalar dfMaskScaleCeil;
213 if (scaledTextSize <= kSmallDFFontLimit) {
214 dfMaskScaleFloor = kMinDFFontSize;
215 dfMaskScaleCeil = kSmallDFFontLimit;
216 *textRatio = textSize / kSmallDFFontSize;
217 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize));
218 } else if (scaledTextSize <= kMediumDFFontLimit) {
219 dfMaskScaleFloor = kSmallDFFontLimit;
220 dfMaskScaleCeil = kMediumDFFontLimit;
221 *textRatio = textSize / kMediumDFFontSize;
222 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize));
223 } else {
224 dfMaskScaleFloor = kMediumDFFontLimit;
225 dfMaskScaleCeil = kLargeDFFontLimit;
226 *textRatio = textSize / kLargeDFFontSize;
227 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize));
228 }
229
230 // Because there can be multiple runs in the blob, we want the overall maxMinScale, and
231 // minMaxScale to make regeneration decisions. Specifically, we want the maximum minimum scale
232 // we can tolerate before we'd drop to a lower mip size, and the minimum maximum scale we can
233 // tolerate before we'd have to move to a large mip size. When we actually test these values
234 // we look at the delta in scale between the new viewmatrix and the old viewmatrix, and test
235 // against these values to decide if we can reuse or not(ie, will a given scale change our mip
236 // level)
237 SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScaleCeil);
joshualitt323c2eb2016-01-20 06:48:47 -0800238 blob->setMinAndMaxScale(dfMaskScaleFloor / scaledTextSize, dfMaskScaleCeil / scaledTextSize);
joshualitt0d2199b2016-01-20 06:36:09 -0800239
240 skPaint->setLCDRenderText(false);
241 skPaint->setAutohinted(false);
242 skPaint->setHinting(SkPaint::kNormal_Hinting);
243 skPaint->setSubpixelText(true);
244}
245
246void GrTextUtils::DrawDFText(GrAtlasTextBlob* blob, int runIndex,
247 GrBatchFontCache* fontCache, const SkSurfaceProps& props,
248 const SkPaint& skPaint, GrColor color,
249 const SkMatrix& viewMatrix,
250 const char text[], size_t byteLength,
251 SkScalar x, SkScalar y) {
252 SkASSERT(byteLength == 0 || text != nullptr);
253
254 // nothing to draw
255 if (text == nullptr || byteLength == 0) {
256 return;
257 }
258
259 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
260 SkAutoDescriptor desc;
261 skPaint.getScalerContextDescriptor(&desc, props, nullptr, true);
262 SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(skPaint.getTypeface(),
263 desc.getDesc());
264
265 SkTArray<SkScalar> positions;
266
267 const char* textPtr = text;
268 SkFixed stopX = 0;
269 SkFixed stopY = 0;
270 SkFixed origin = 0;
271 switch (skPaint.getTextAlign()) {
272 case SkPaint::kRight_Align: origin = SK_Fixed1; break;
273 case SkPaint::kCenter_Align: origin = SK_FixedHalf; break;
274 case SkPaint::kLeft_Align: origin = 0; break;
275 }
276
277 SkAutoKern autokern;
278 const char* stop = text + byteLength;
279 while (textPtr < stop) {
280 // don't need x, y here, since all subpixel variants will have the
281 // same advance
282 const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr, 0, 0);
283
284 SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph);
285 positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width)));
286
287 SkFixed height = glyph.fAdvanceY;
288 positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height)));
289
290 stopX += width;
291 stopY += height;
292 }
293 SkASSERT(textPtr == stop);
294
295 SkGlyphCache::AttachCache(origPaintCache);
296
297 // now adjust starting point depending on alignment
298 SkScalar alignX = SkFixedToScalar(stopX);
299 SkScalar alignY = SkFixedToScalar(stopY);
300 if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
301 alignX = SkScalarHalf(alignX);
302 alignY = SkScalarHalf(alignY);
303 } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) {
304 alignX = 0;
305 alignY = 0;
306 }
307 x -= alignX;
308 y -= alignY;
309 SkPoint offset = SkPoint::Make(x, y);
310
311 DrawDFPosText(blob, runIndex, fontCache, props, skPaint, color, viewMatrix, text, byteLength,
312 positions.begin(), 2, offset);
313}
314
315void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex,
316 GrBatchFontCache* fontCache, const SkSurfaceProps& props,
317 const SkPaint& origPaint,
318 GrColor color, const SkMatrix& viewMatrix,
319 const char text[], size_t byteLength,
320 const SkScalar pos[], int scalarsPerPosition,
321 const SkPoint& offset) {
322 SkASSERT(byteLength == 0 || text != nullptr);
323 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
324
325 // nothing to draw
326 if (text == nullptr || byteLength == 0) {
327 return;
328 }
329
330 SkTDArray<char> fallbackTxt;
331 SkTDArray<SkScalar> fallbackPos;
332
333 // Setup distance field paint and text ratio
334 SkScalar textRatio;
335 SkPaint dfPaint(origPaint);
336 GrTextUtils::InitDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix);
337 blob->setHasDistanceField();
338 blob->setSubRunHasDistanceFields(runIndex, origPaint.isLCDRenderText());
339
340 GrBatchTextStrike* currStrike = nullptr;
341
342 SkGlyphCache* cache = blob->setupCache(runIndex, props, dfPaint, nullptr, true);
343 SkDrawCacheProc glyphCacheProc = dfPaint.getDrawCacheProc();
joshualitt8e84a1e2016-02-16 11:09:25 -0800344 GrFontScaler* fontScaler = GrTextUtils::GetGrFontScaler(cache);
joshualitt0d2199b2016-01-20 06:36:09 -0800345
346 const char* stop = text + byteLength;
347
348 if (SkPaint::kLeft_Align == dfPaint.getTextAlign()) {
349 while (text < stop) {
350 const char* lastText = text;
351 // the last 2 parameters are ignored
352 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
353
354 if (glyph.fWidth) {
355 SkScalar x = offset.x() + pos[0];
356 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);
357
358 if (!DfAppendGlyph(blob,
359 runIndex,
360 fontCache,
361 &currStrike,
362 glyph,
363 x, y, color, fontScaler,
364 textRatio, viewMatrix)) {
365 // couldn't append, send to fallback
366 fallbackTxt.append(SkToInt(text-lastText), lastText);
367 *fallbackPos.append() = pos[0];
368 if (2 == scalarsPerPosition) {
369 *fallbackPos.append() = pos[1];
370 }
371 }
372 }
373 pos += scalarsPerPosition;
374 }
375 } else {
376 SkScalar alignMul = SkPaint::kCenter_Align == dfPaint.getTextAlign() ? SK_ScalarHalf
377 : SK_Scalar1;
378 while (text < stop) {
379 const char* lastText = text;
380 // the last 2 parameters are ignored
381 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
382
383 if (glyph.fWidth) {
384 SkScalar x = offset.x() + pos[0];
385 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);
386
387 SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX) * alignMul * textRatio;
388 SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY) * alignMul * textRatio;
389
390 if (!DfAppendGlyph(blob,
391 runIndex,
392 fontCache,
393 &currStrike,
394 glyph,
395 x - advanceX, y - advanceY, color,
396 fontScaler,
397 textRatio,
398 viewMatrix)) {
399 // couldn't append, send to fallback
400 fallbackTxt.append(SkToInt(text-lastText), lastText);
401 *fallbackPos.append() = pos[0];
402 if (2 == scalarsPerPosition) {
403 *fallbackPos.append() = pos[1];
404 }
405 }
406 }
407 pos += scalarsPerPosition;
408 }
409 }
410
411 SkGlyphCache::AttachCache(cache);
412 if (fallbackTxt.count()) {
413 blob->initOverride(runIndex);
414 GrTextUtils::DrawBmpPosText(blob, runIndex, fontCache, props,
415 origPaint, origPaint.getColor(), viewMatrix,
416 fallbackTxt.begin(), fallbackTxt.count(),
417 fallbackPos.begin(), scalarsPerPosition, offset);
418 }
419}
420
421bool GrTextUtils::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrBatchFontCache* cache,
422 GrBatchTextStrike** strike, const SkGlyph& skGlyph,
423 SkScalar sx, SkScalar sy, GrColor color,
424 GrFontScaler* scaler,
425 SkScalar textRatio, const SkMatrix& viewMatrix) {
426 if (!*strike) {
427 *strike = cache->getStrike(scaler);
428 }
429
430 GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
431 skGlyph.getSubXFixed(),
432 skGlyph.getSubYFixed(),
433 GrGlyph::kDistance_MaskStyle);
434 GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, scaler);
435 if (!glyph) {
436 return true;
437 }
438
439 // fallback to color glyph support
440 if (kA8_GrMaskFormat != glyph->fMaskFormat) {
441 return false;
442 }
443
444 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
445 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
446 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceFieldInset);
447 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFieldInset);
448
449 SkScalar scale = textRatio;
450 dx *= scale;
451 dy *= scale;
452 width *= scale;
453 height *= scale;
454 sx += dx;
455 sy += dy;
456 SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height);
457
458 blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, scaler, skGlyph,
459 sx - dx, sy - dy, scale, true);
460 return true;
461}
462
joshualitt0a42e682015-12-10 13:20:58 -0800463void GrTextUtils::DrawTextAsPath(GrContext* context, GrDrawContext* dc,
464 const GrClip& clip,
465 const SkPaint& skPaint, const SkMatrix& viewMatrix,
466 const char text[], size_t byteLength, SkScalar x, SkScalar y,
467 const SkIRect& clipBounds) {
468 SkTextToPathIter iter(text, byteLength, skPaint, true);
469
470 SkMatrix matrix;
471 matrix.setScale(iter.getPathScale(), iter.getPathScale());
472 matrix.postTranslate(x, y);
473
474 const SkPath* iterPath;
475 SkScalar xpos, prevXPos = 0;
476
477 while (iter.next(&iterPath, &xpos)) {
478 matrix.postTranslate(xpos - prevXPos, 0);
479 if (iterPath) {
480 const SkPaint& pnt = iter.getPaint();
481 GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, *iterPath,
482 pnt, viewMatrix, &matrix, clipBounds, false);
483 }
484 prevXPos = xpos;
485 }
486}
487
488void GrTextUtils::DrawPosTextAsPath(GrContext* context,
489 GrDrawContext* dc,
490 const SkSurfaceProps& props,
491 const GrClip& clip,
492 const SkPaint& origPaint, const SkMatrix& viewMatrix,
493 const char text[], size_t byteLength,
494 const SkScalar pos[], int scalarsPerPosition,
495 const SkPoint& offset, const SkIRect& clipBounds) {
496 // setup our std paint, in hopes of getting hits in the cache
497 SkPaint paint(origPaint);
498 SkScalar matrixScale = paint.setupForAsPaths();
499
500 SkMatrix matrix;
501 matrix.setScale(matrixScale, matrixScale);
502
503 // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
504 paint.setStyle(SkPaint::kFill_Style);
505 paint.setPathEffect(nullptr);
506
507 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
508 SkAutoGlyphCache autoCache(paint, &props, nullptr);
509 SkGlyphCache* cache = autoCache.getCache();
510
511 const char* stop = text + byteLength;
512 SkTextAlignProc alignProc(paint.getTextAlign());
513 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
514
515 // Now restore the original settings, so we "draw" with whatever style/stroking.
516 paint.setStyle(origPaint.getStyle());
517 paint.setPathEffect(origPaint.getPathEffect());
518
519 while (text < stop) {
520 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
521 if (glyph.fWidth) {
522 const SkPath* path = cache->findPath(glyph);
523 if (path) {
524 SkPoint tmsLoc;
525 tmsProc(pos, &tmsLoc);
526 SkPoint loc;
527 alignProc(tmsLoc, glyph, &loc);
528
529 matrix[SkMatrix::kMTransX] = loc.fX;
530 matrix[SkMatrix::kMTransY] = loc.fY;
531 GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, *path, paint,
532 viewMatrix, &matrix, clipBounds, false);
533 }
534 }
535 pos += scalarsPerPosition;
536 }
537}
joshualitt8e84a1e2016-02-16 11:09:25 -0800538
539bool GrTextUtils::ShouldDisableLCD(const SkPaint& paint) {
540 return !SkXfermode::AsMode(paint.getXfermode(), nullptr) ||
541 paint.getMaskFilter() ||
542 paint.getRasterizer() ||
543 paint.getPathEffect() ||
544 paint.isFakeBoldText() ||
545 paint.getStyle() != SkPaint::kFill_Style;
546}
547
548uint32_t GrTextUtils::FilterTextFlags(const SkSurfaceProps& surfaceProps, const SkPaint& paint) {
549 uint32_t flags = paint.getFlags();
550
551 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
552 return flags;
553 }
554
555 if (kUnknown_SkPixelGeometry == surfaceProps.pixelGeometry() || ShouldDisableLCD(paint)) {
556 flags &= ~SkPaint::kLCDRenderText_Flag;
557 flags |= SkPaint::kGenA8FromLCD_Flag;
558 }
559
560 return flags;
561}
562
563static void glyph_cache_aux_proc(void* data) {
564 GrFontScaler* scaler = (GrFontScaler*)data;
565 SkSafeUnref(scaler);
566}
567
568GrFontScaler* GrTextUtils::GetGrFontScaler(SkGlyphCache* cache) {
569 void* auxData;
570 GrFontScaler* scaler = nullptr;
571
572 if (cache->getAuxProcData(glyph_cache_aux_proc, &auxData)) {
573 scaler = (GrFontScaler*)auxData;
574 }
575 if (nullptr == scaler) {
576 scaler = new GrFontScaler(cache);
577 cache->setAuxProc(glyph_cache_aux_proc, scaler);
578 }
579
580 return scaler;
581}