blob: 530fc9346552d4d168a0c1505342fa11f45f6567 [file] [log] [blame]
Mike Reeddee25cc2018-10-05 11:48:01 -04001/*
2 * Copyright 2018 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 "SkPaint.h"
9#include "SkColorFilter.h"
10#include "SkDraw.h"
11#include "SkFontDescriptor.h"
12#include "SkGlyphCache.h"
13#include "SkGraphics.h"
14#include "SkPaintDefaults.h"
15#include "SkPaintPriv.h"
16#include "SkPathEffect.h"
17#include "SkSafeRange.h"
18#include "SkScalar.h"
19#include "SkScalerContext.h"
20#include "SkShader.h"
21#include "SkShaderBase.h"
22#include "SkStringUtils.h"
23#include "SkTLazy.h"
24#include "SkTextBlob.h"
25#include "SkTextBlobPriv.h"
26#include "SkTextFormatParams.h"
27#include "SkTextToPathIter.h"
28#include "SkTo.h"
29#include "SkTypeface.h"
30
31///////////////////////////////////////////////////////////////////////////////
32
33static SkScalar mag2(SkScalar x, SkScalar y) {
34 return x * x + y * y;
35}
36
37static bool tooBig(const SkMatrix& m, SkScalar ma2max) {
38 return mag2(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewY]) > ma2max
39 ||
40 mag2(m[SkMatrix::kMSkewX], m[SkMatrix::kMScaleY]) > ma2max;
41}
42
43bool SkPaint::TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM, SkScalar maxLimit) {
44 SkASSERT(!ctm.hasPerspective());
45 SkASSERT(!textM.hasPerspective());
46
47 SkMatrix matrix;
48 matrix.setConcat(ctm, textM);
49 return tooBig(matrix, MaxCacheSize2(maxLimit));
50}
51
52SkScalar SkPaint::MaxCacheSize2(SkScalar maxLimit) {
53 // we have a self-imposed maximum, just for memory-usage sanity
54 const int limit = SkMin32(SkGraphics::GetFontCachePointSizeLimit(), maxLimit);
55 const SkScalar maxSize = SkIntToScalar(limit);
56 return maxSize * maxSize;
57}
58
59///////////////////////////////////////////////////////////////////////////////
60
61#include "SkGlyphCache.h"
62#include "SkUtils.h"
63
Mike Reed4ff40852018-11-23 16:20:28 -050064int SkPaint::countText(const void* text, size_t length) const {
Mike Reed0f9d33e2018-12-05 10:54:05 -050065 return SkFont::LEGACY_ExtractFromPaint(*this).countText(text, length, this->getTextEncoding());
Mike Reeddee25cc2018-10-05 11:48:01 -040066}
67
Mike Reed4ff40852018-11-23 16:20:28 -050068int SkPaint::textToGlyphs(const void* text, size_t length, uint16_t glyphs[]) const {
69 return SkFont::LEGACY_ExtractFromPaint(*this).textToGlyphs(text, length,
Mike Reed0f9d33e2018-12-05 10:54:05 -050070 this->getTextEncoding(),
Mike Reed4ff40852018-11-23 16:20:28 -050071 glyphs, length);
Mike Reeddee25cc2018-10-05 11:48:01 -040072}
73
Mike Reed4ff40852018-11-23 16:20:28 -050074bool SkPaint::containsText(const void* text, size_t length) const {
75 return SkFont::LEGACY_ExtractFromPaint(*this).containsText(text, length,
Mike Reed0f9d33e2018-12-05 10:54:05 -050076 this->getTextEncoding());
Mike Reeddee25cc2018-10-05 11:48:01 -040077}
78
79void SkPaint::glyphsToUnichars(const uint16_t glyphs[], int count, SkUnichar textData[]) const {
Mike Reed4e336e32018-12-06 17:08:11 -050080 SkFont::LEGACY_ExtractFromPaint(*this).glyphsToUnichars(glyphs, count, textData);
Mike Reeddee25cc2018-10-05 11:48:01 -040081}
82
83///////////////////////////////////////////////////////////////////////////////
84
85static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache,
86 const char** text,
87 const char* stop) {
88 SkASSERT(cache != nullptr);
89 SkASSERT(text != nullptr);
90
91 return cache->getUnicharMetrics(SkUTF::NextUTF8(text, stop));
92}
93
94static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache,
95 const char** text,
96 const char* stop) {
97 SkASSERT(cache != nullptr);
98 SkASSERT(text != nullptr);
99
100 return cache->getUnicharMetrics(
101 SkUTF::NextUTF16((const uint16_t**)text, (const uint16_t*)stop));
102}
103
104static const SkGlyph& sk_getMetrics_utf32_next(SkGlyphCache* cache,
105 const char** text,
106 const char* stop) {
107 SkASSERT(cache != nullptr);
108 SkASSERT(text != nullptr);
109
110 return cache->getUnicharMetrics(SkUTF::NextUTF32((const int32_t**)text, (const int32_t*)stop));
111}
112
113static const SkGlyph& sk_getMetrics_glyph_next(SkGlyphCache* cache,
114 const char** text,
115 const char* stop) {
116 SkASSERT(cache != nullptr);
117 SkASSERT(text != nullptr);
118
119 const uint16_t* ptr = *(const uint16_t**)text;
120 unsigned glyphID = *ptr;
121 ptr += 1;
122 *text = (const char*)ptr;
123 return cache->getGlyphIDMetrics(glyphID);
124}
125
126static const SkGlyph& sk_getAdvance_utf8_next(SkGlyphCache* cache,
127 const char** text,
128 const char* stop) {
129 SkASSERT(cache != nullptr);
130 SkASSERT(text != nullptr);
131
132 return cache->getUnicharAdvance(SkUTF::NextUTF8(text, stop));
133}
134
135static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache,
136 const char** text,
137 const char* stop) {
138 SkASSERT(cache != nullptr);
139 SkASSERT(text != nullptr);
140
141 return cache->getUnicharAdvance(
142 SkUTF::NextUTF16((const uint16_t**)text, (const uint16_t*)stop));
143}
144
145static const SkGlyph& sk_getAdvance_utf32_next(SkGlyphCache* cache,
146 const char** text,
147 const char* stop) {
148 SkASSERT(cache != nullptr);
149 SkASSERT(text != nullptr);
150
151 return cache->getUnicharAdvance(SkUTF::NextUTF32((const int32_t**)text, (const int32_t*)stop));
152}
153
154static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache,
155 const char** text,
156 const char* stop) {
157 SkASSERT(cache != nullptr);
158 SkASSERT(text != nullptr);
159
160 const uint16_t* ptr = *(const uint16_t**)text;
161 unsigned glyphID = *ptr;
162 ptr += 1;
163 *text = (const char*)ptr;
164 return cache->getGlyphIDAdvance(glyphID);
165}
166
Mike Reed064ca012018-11-10 09:13:13 -0500167SkFontPriv::GlyphCacheProc SkFontPriv::GetGlyphCacheProc(SkTextEncoding encoding,
168 bool needFullMetrics) {
Mike Reeddee25cc2018-10-05 11:48:01 -0400169 static const GlyphCacheProc gGlyphCacheProcs[] = {
170 sk_getMetrics_utf8_next,
171 sk_getMetrics_utf16_next,
172 sk_getMetrics_utf32_next,
173 sk_getMetrics_glyph_next,
174
175 sk_getAdvance_utf8_next,
176 sk_getAdvance_utf16_next,
177 sk_getAdvance_utf32_next,
178 sk_getAdvance_glyph_next,
179 };
180
Mike Reedd723ee12018-11-13 14:21:14 -0800181 unsigned index = static_cast<unsigned>(encoding);
Mike Reeddee25cc2018-10-05 11:48:01 -0400182
183 if (!needFullMetrics) {
184 index += 4;
185 }
186
187 SkASSERT(index < SK_ARRAY_COUNT(gGlyphCacheProcs));
188 return gGlyphCacheProcs[index];
189}
190
191///////////////////////////////////////////////////////////////////////////////
192
193SkScalar SkPaint::setupForAsPaths() {
194
195 constexpr uint32_t flagsToIgnore = SkPaint::kLinearText_Flag |
196 SkPaint::kLCDRenderText_Flag |
197 SkPaint::kEmbeddedBitmapText_Flag |
198 SkPaint::kAutoHinting_Flag;
199
200 uint32_t flags = this->getFlags();
201
202 // clear the flags we don't care about
203 flags &= ~flagsToIgnore;
204
205 // set the flags we do care about
206 flags |= SkPaint::kSubpixelText_Flag;
207
208 this->setFlags(flags);
Mike Reed9edbf422018-11-07 19:54:33 -0500209 this->setHinting(kNo_SkFontHinting);
Mike Reeddee25cc2018-10-05 11:48:01 -0400210 this->setStyle(SkPaint::kFill_Style);
211 this->setPathEffect(nullptr);
212
213 SkScalar textSize = fTextSize;
214 this->setTextSize(kCanonicalTextSizeForPaths);
215 return textSize / kCanonicalTextSizeForPaths;
216}
217
218class SkCanonicalizePaint {
219public:
220 SkCanonicalizePaint(const SkPaint& paint) : fPaint(&paint), fScale(0) {
221 if (paint.isLinearText() || SkDraw::ShouldDrawTextAsPaths(paint, SkMatrix::I())) {
222 SkPaint* p = fLazy.set(paint);
223 fScale = p->setupForAsPaths();
224 fPaint = p;
225 }
226 }
227
228 const SkPaint& getPaint() const { return *fPaint; }
229
230 /**
231 * Returns 0 if the paint was unmodified, or the scale factor need to
232 * the original textSize
233 */
234 SkScalar getScale() const { return fScale; }
235
236private:
237 const SkPaint* fPaint;
238 SkScalar fScale;
239 SkTLazy<SkPaint> fLazy;
240};
241
242static void set_bounds(const SkGlyph& g, SkRect* bounds) {
243 bounds->set(SkIntToScalar(g.fLeft),
244 SkIntToScalar(g.fTop),
245 SkIntToScalar(g.fLeft + g.fWidth),
246 SkIntToScalar(g.fTop + g.fHeight));
247}
248
249static void join_bounds_x(const SkGlyph& g, SkRect* bounds, SkScalar dx) {
250 bounds->join(SkIntToScalar(g.fLeft) + dx,
251 SkIntToScalar(g.fTop),
252 SkIntToScalar(g.fLeft + g.fWidth) + dx,
253 SkIntToScalar(g.fTop + g.fHeight));
254}
255
Mike Reeddee25cc2018-10-05 11:48:01 -0400256// xyIndex is 0 for fAdvanceX or 1 for fAdvanceY
Mike Reedc88cc772018-10-23 12:05:47 -0400257static SkScalar advance(const SkGlyph& glyph) {
258 return SkFloatToScalar(glyph.fAdvanceX);
Mike Reeddee25cc2018-10-05 11:48:01 -0400259}
260
261SkScalar SkPaint::measure_text(SkGlyphCache* cache,
262 const char* text, size_t byteLength,
263 int* count, SkRect* bounds) const {
264 SkASSERT(count);
265 if (byteLength == 0) {
266 *count = 0;
267 if (bounds) {
268 bounds->setEmpty();
269 }
270 return 0;
271 }
272
Mike Reed064ca012018-11-10 09:13:13 -0500273 SkFontPriv::GlyphCacheProc glyphCacheProc = SkFontPriv::GetGlyphCacheProc(
Mike Reed0f9d33e2018-12-05 10:54:05 -0500274 this->getTextEncoding(), nullptr != bounds);
Mike Reeddee25cc2018-10-05 11:48:01 -0400275
Mike Reeddee25cc2018-10-05 11:48:01 -0400276 int n = 1;
277 const char* stop = (const char*)text + byteLength;
278 const SkGlyph* g = &glyphCacheProc(cache, &text, stop);
Mike Reedc88cc772018-10-23 12:05:47 -0400279 SkScalar x = advance(*g);
Mike Reeddee25cc2018-10-05 11:48:01 -0400280
281 if (nullptr == bounds) {
282 for (; text < stop; n++) {
Mike Reedc88cc772018-10-23 12:05:47 -0400283 x += advance(glyphCacheProc(cache, &text, stop));
Mike Reeddee25cc2018-10-05 11:48:01 -0400284 }
285 } else {
286 set_bounds(*g, bounds);
287
288 for (; text < stop; n++) {
289 g = &glyphCacheProc(cache, &text, stop);
Mike Reedc88cc772018-10-23 12:05:47 -0400290 join_bounds_x(*g, bounds, x);
291 x += advance(*g);
Mike Reeddee25cc2018-10-05 11:48:01 -0400292 }
293 }
294 SkASSERT(text == stop);
295
296 *count = n;
297 return x;
298}
299
300SkScalar SkPaint::measureText(const void* textData, size_t length, SkRect* bounds) const {
301 const char* text = (const char*)textData;
302 SkASSERT(text != nullptr || length == 0);
303
304 SkCanonicalizePaint canon(*this);
305 const SkPaint& paint = canon.getPaint();
306 SkScalar scale = canon.getScale();
307
Mike Reed32c60662018-11-28 10:28:07 -0500308 const SkFont font = SkFont::LEGACY_ExtractFromPaint(paint);
309 auto cache = SkStrikeCache::FindOrCreateStrikeWithNoDeviceExclusive(font, paint);
Mike Reeddee25cc2018-10-05 11:48:01 -0400310
311 SkScalar width = 0;
312
313 if (length > 0) {
314 int tempCount;
315
316 width = paint.measure_text(cache.get(), text, length, &tempCount, bounds);
317 if (scale) {
318 width *= scale;
319 if (bounds) {
320 bounds->fLeft *= scale;
321 bounds->fTop *= scale;
322 bounds->fRight *= scale;
323 bounds->fBottom *= scale;
324 }
325 }
326 } else if (bounds) {
327 // ensure that even if we don't measure_text we still update the bounds
328 bounds->setEmpty();
329 }
330 return width;
331}
332
Mike Reedcb6f53e2018-11-06 12:44:54 -0500333SkScalar SkPaint::getFontMetrics(SkFontMetrics* metrics) const {
Mike Reed4ff40852018-11-23 16:20:28 -0500334 return SkFont::LEGACY_ExtractFromPaint(*this).getMetrics(metrics);
Mike Reeddee25cc2018-10-05 11:48:01 -0400335}
336
337///////////////////////////////////////////////////////////////////////////////
338
Mike Reed54bf6842018-11-27 12:27:15 -0500339int SkPaint::getTextWidths(const void* text, size_t len, SkScalar widths[], SkRect bounds[]) const {
340 const SkFont font = SkFont::LEGACY_ExtractFromPaint(*this);
Mike Reed0f9d33e2018-12-05 10:54:05 -0500341 SkAutoToGlyphs gly(font, text, len, this->getTextEncoding());
Mike Reed54bf6842018-11-27 12:27:15 -0500342 font.getWidthsBounds(gly.glyphs(), gly.count(), widths, bounds, this);
343 return gly.count();
Mike Reeddee25cc2018-10-05 11:48:01 -0400344}
345
346///////////////////////////////////////////////////////////////////////////////
347
348#include "SkDraw.h"
349
Mike Reedc16abee2018-11-24 13:27:27 -0500350struct PathPosRec {
351 SkPath* fDst;
352 const SkPoint* fPos;
353};
Mike Reed28715092018-11-24 22:55:54 -0500354static void PathPosProc(const SkPath* src, const SkMatrix& mx, void* ctx) {
Mike Reedc16abee2018-11-24 13:27:27 -0500355 PathPosRec* rec = static_cast<PathPosRec*>(ctx);
356 if (src) {
Mike Reed28715092018-11-24 22:55:54 -0500357 SkMatrix m(mx);
358 m.postTranslate(rec->fPos->fX, rec->fPos->fY);
359 rec->fDst->addPath(*src, m);
Mike Reeddee25cc2018-10-05 11:48:01 -0400360 }
Mike Reedc16abee2018-11-24 13:27:27 -0500361 rec->fPos += 1;
Mike Reeddee25cc2018-10-05 11:48:01 -0400362}
363
Mike Reedc16abee2018-11-24 13:27:27 -0500364void SkPaint::getTextPath(const void* text, size_t length,
365 SkScalar x, SkScalar y, SkPath* path) const {
366 SkFont font = SkFont::LEGACY_ExtractFromPaint(*this);
Mike Reed0f9d33e2018-12-05 10:54:05 -0500367 SkAutoToGlyphs gly(font, text, length, this->getTextEncoding());
Mike Reedc16abee2018-11-24 13:27:27 -0500368 SkAutoSTArray<32, SkPoint> fPos(gly.count());
369 font.getPos(gly.glyphs(), gly.count(), fPos.get(), {x, y});
Mike Reeddee25cc2018-10-05 11:48:01 -0400370
Mike Reeddee25cc2018-10-05 11:48:01 -0400371 path->reset();
Mike Reedc16abee2018-11-24 13:27:27 -0500372 PathPosRec rec = { path, fPos.get() };
373 font.getPaths(gly.glyphs(), gly.count(), PathPosProc, &rec);
374}
Mike Reeddee25cc2018-10-05 11:48:01 -0400375
Mike Reedc16abee2018-11-24 13:27:27 -0500376void SkPaint::getPosTextPath(const void* text, size_t length,
377 const SkPoint pos[], SkPath* path) const {
378 SkFont font = SkFont::LEGACY_ExtractFromPaint(*this);
Mike Reed0f9d33e2018-12-05 10:54:05 -0500379 SkAutoToGlyphs gly(font, text, length, this->getTextEncoding());
Mike Reedc16abee2018-11-24 13:27:27 -0500380
381 path->reset();
382 PathPosRec rec = { path, pos };
383 font.getPaths(gly.glyphs(), gly.count(), PathPosProc, &rec);
Mike Reeddee25cc2018-10-05 11:48:01 -0400384}
385
386template <SkTextInterceptsIter::TextType TextType, typename Func>
387int GetTextIntercepts(const SkPaint& paint, const void* text, size_t length,
388 const SkScalar bounds[2], SkScalar* array, Func posMaker) {
389 SkASSERT(length == 0 || text != nullptr);
390 if (!length) {
391 return 0;
392 }
393
394 const SkPoint pos0 = posMaker(0);
395 SkTextInterceptsIter iter(static_cast<const char*>(text), length, paint, bounds,
396 pos0.x(), pos0.y(), TextType);
397
398 int i = 0;
399 int count = 0;
400 while (iter.next(array, &count)) {
401 if (TextType == SkTextInterceptsIter::TextType::kPosText) {
402 const SkPoint pos = posMaker(++i);
403 iter.setPosition(pos.x(), pos.y());
404 }
405 }
406
407 return count;
408}
409
410int SkPaint::getTextIntercepts(const void* textData, size_t length,
411 SkScalar x, SkScalar y, const SkScalar bounds[2],
412 SkScalar* array) const {
413
414 return GetTextIntercepts<SkTextInterceptsIter::TextType::kText>(
415 *this, textData, length, bounds, array, [&x, &y] (int) -> SkPoint {
416 return SkPoint::Make(x, y);
417 });
418}
419
420int SkPaint::getPosTextIntercepts(const void* textData, size_t length, const SkPoint pos[],
421 const SkScalar bounds[2], SkScalar* array) const {
422
423 return GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
424 *this, textData, length, bounds, array, [&pos] (int i) -> SkPoint {
425 return pos[i];
426 });
427}
428
429int SkPaint::getPosTextHIntercepts(const void* textData, size_t length, const SkScalar xpos[],
430 SkScalar constY, const SkScalar bounds[2],
431 SkScalar* array) const {
432
433 return GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
434 *this, textData, length, bounds, array, [&xpos, &constY] (int i) -> SkPoint {
435 return SkPoint::Make(xpos[i], constY);
436 });
437}
438
439int SkPaint::getTextBlobIntercepts(const SkTextBlob* blob, const SkScalar bounds[2],
440 SkScalar* intervals) const {
441 int count = 0;
442 SkPaint runPaint(*this);
443
444 SkTextBlobRunIterator it(blob);
445 while (!it.done()) {
446 it.applyFontToPaint(&runPaint);
447 const size_t runByteCount = it.glyphCount() * sizeof(SkGlyphID);
448 SkScalar* runIntervals = intervals ? intervals + count : nullptr;
449
450 switch (it.positioning()) {
451 case SkTextBlobRunIterator::kDefault_Positioning:
452 count += runPaint.getTextIntercepts(it.glyphs(), runByteCount, it.offset().x(),
453 it.offset().y(), bounds, runIntervals);
454 break;
455 case SkTextBlobRunIterator::kHorizontal_Positioning:
456 count += runPaint.getPosTextHIntercepts(it.glyphs(), runByteCount, it.pos(),
457 it.offset().y(), bounds, runIntervals);
458 break;
459 case SkTextBlobRunIterator::kFull_Positioning:
460 count += runPaint.getPosTextIntercepts(it.glyphs(), runByteCount,
461 reinterpret_cast<const SkPoint*>(it.pos()),
462 bounds, runIntervals);
463 break;
464 }
465
466 it.next();
467 }
468
469 return count;
470}
471
Mike Reeddee25cc2018-10-05 11:48:01 -0400472// return true if the paint is just a single color (i.e. not a shader). If its
473// a shader, then we can't compute a const luminance for it :(
474static bool just_a_color(const SkPaint& paint, SkColor* color) {
475 SkColor c = paint.getColor();
476
477 const auto* shader = as_SB(paint.getShader());
478 if (shader && !shader->asLuminanceColor(&c)) {
479 return false;
480 }
481 if (paint.getColorFilter()) {
482 c = paint.getColorFilter()->filterColor(c);
483 }
484 if (color) {
485 *color = c;
486 }
487 return true;
488}
489
490SkColor SkPaint::computeLuminanceColor() const {
491 SkColor c;
492 if (!just_a_color(*this, &c)) {
493 c = SkColorSetRGB(0x7F, 0x80, 0x7F);
494 }
495 return c;
496}
497
498///////////////////////////////////////////////////////////////////////////////
499
500static bool has_thick_frame(const SkPaint& paint) {
501 return paint.getStrokeWidth() > 0 &&
502 paint.getStyle() != SkPaint::kFill_Style;
503}
504
505SkTextBaseIter::SkTextBaseIter(const char text[], size_t length,
506 const SkPaint& paint,
507 bool applyStrokeAndPathEffects)
508 : fPaint(paint) {
Mike Reed0f9d33e2018-12-05 10:54:05 -0500509 fGlyphCacheProc = SkFontPriv::GetGlyphCacheProc(paint.getTextEncoding(), true);
Mike Reeddee25cc2018-10-05 11:48:01 -0400510
511 fPaint.setLinearText(true);
512 fPaint.setMaskFilter(nullptr); // don't want this affecting our path-cache lookup
513
514 if (fPaint.getPathEffect() == nullptr && !has_thick_frame(fPaint)) {
515 applyStrokeAndPathEffects = false;
516 }
517
518 // can't use our canonical size if we need to apply patheffects
519 if (fPaint.getPathEffect() == nullptr) {
520 fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
521 fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
522 // Note: fScale can be zero here (even if it wasn't before the divide). It can also
523 // be very very small. We call sk_ieee_float_divide below to ensure IEEE divide behavior,
524 // since downstream we will check for the resulting coordinates being non-finite anyway.
525 // Thus we don't need to check for zero here.
526 if (has_thick_frame(fPaint)) {
527 fPaint.setStrokeWidth(sk_ieee_float_divide(fPaint.getStrokeWidth(), fScale));
528 }
529 } else {
530 fScale = SK_Scalar1;
531 }
532
533 if (!applyStrokeAndPathEffects) {
534 fPaint.setStyle(SkPaint::kFill_Style);
535 fPaint.setPathEffect(nullptr);
536 }
537
538 // SRGBTODO: Is this correct?
Mike Reed32c60662018-11-28 10:28:07 -0500539 const SkFont font = SkFont::LEGACY_ExtractFromPaint(fPaint);
540 fCache = SkStrikeCache::FindOrCreateStrikeWithNoDeviceExclusive(font, fPaint);
Mike Reeddee25cc2018-10-05 11:48:01 -0400541
542 SkPaint::Style style = SkPaint::kFill_Style;
543 sk_sp<SkPathEffect> pe;
544
545 if (!applyStrokeAndPathEffects) {
546 style = paint.getStyle(); // restore
547 pe = paint.refPathEffect(); // restore
548 }
549 fPaint.setStyle(style);
550 fPaint.setPathEffect(pe);
551 fPaint.setMaskFilter(paint.refMaskFilter()); // restore
552
553 // now compute fXOffset if needed
554
555 SkScalar xOffset = 0;
Mike Reeddee25cc2018-10-05 11:48:01 -0400556 fXPos = xOffset;
557 fPrevAdvance = 0;
558
559 fText = text;
560 fStop = text + length;
Mike Reeddee25cc2018-10-05 11:48:01 -0400561}
562
563bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) {
564 if (fText < fStop) {
565 const SkGlyph& glyph = fGlyphCacheProc(fCache.get(), &fText, fStop);
566
567 fXPos += fPrevAdvance * fScale;
Mike Reedc88cc772018-10-23 12:05:47 -0400568 fPrevAdvance = advance(glyph); // + fPaint.getTextTracking();
Mike Reeddee25cc2018-10-05 11:48:01 -0400569
570 if (glyph.fWidth) {
571 if (path) {
572 *path = fCache->findPath(glyph);
573 }
574 } else {
575 if (path) {
576 *path = nullptr;
577 }
578 }
579 if (xpos) {
580 *xpos = fXPos;
581 }
582 return true;
583 }
584 return false;
585}
586
587bool SkTextInterceptsIter::next(SkScalar* array, int* count) {
588 const SkGlyph& glyph = fGlyphCacheProc(fCache.get(), &fText, fStop);
589 fXPos += fPrevAdvance * fScale;
Mike Reedc88cc772018-10-23 12:05:47 -0400590 fPrevAdvance = advance(glyph); // + fPaint.getTextTracking();
Mike Reeddee25cc2018-10-05 11:48:01 -0400591 if (fCache->findPath(glyph)) {
Mike Reedc88cc772018-10-23 12:05:47 -0400592 fCache->findIntercepts(fBounds, fScale, fXPos, false,
Mike Reeddee25cc2018-10-05 11:48:01 -0400593 const_cast<SkGlyph*>(&glyph), array, count);
594 }
595 return fText < fStop;
596}