1 /*
2 * Copyright 2006 The Android Open Source Project
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 "SkPaintPriv.h"
10 #include "SkAutoKern.h"
11 #include "SkColorFilter.h"
12 #include "SkData.h"
13 #include "SkDraw.h"
14 #include "SkFontDescriptor.h"
15 #include "SkGraphics.h"
16 #include "SkGlyphCache.h"
17 #include "SkImageFilter.h"
18 #include "SkMaskFilter.h"
19 #include "SkMaskGamma.h"
20 #include "SkMutex.h"
21 #include "SkReadBuffer.h"
22 #include "SkWriteBuffer.h"
23 #include "SkOpts.h"
24 #include "SkPaintDefaults.h"
25 #include "SkPathEffect.h"
26 #include "SkSafeRange.h"
27 #include "SkScalar.h"
28 #include "SkScalerContext.h"
29 #include "SkShader.h"
30 #include "SkShaderBase.h"
31 #include "SkStringUtils.h"
32 #include "SkStroke.h"
33 #include "SkStrokeRec.h"
34 #include "SkSurfacePriv.h"
35 #include "SkTextBlob.h"
36 #include "SkTextBlobRunIterator.h"
37 #include "SkTextFormatParams.h"
38 #include "SkTextToPathIter.h"
39 #include "SkTLazy.h"
40 #include "SkTypeface.h"
41
set_clear_mask(uint32_t bits,bool cond,uint32_t mask)42 static inline uint32_t set_clear_mask(uint32_t bits, bool cond, uint32_t mask) {
43 return cond ? bits | mask : bits & ~mask;
44 }
45
46 // define this to get a printf for out-of-range parameter in setters
47 // e.g. setTextSize(-1)
48 //#define SK_REPORT_API_RANGE_CHECK
49
SkPaint()50 SkPaint::SkPaint() {
51 fTextSize = SkPaintDefaults_TextSize;
52 fTextScaleX = SK_Scalar1;
53 fTextSkewX = 0;
54 fColor = SK_ColorBLACK;
55 fWidth = 0;
56 fMiterLimit = SkPaintDefaults_MiterLimit;
57 fBlendMode = (unsigned)SkBlendMode::kSrcOver;
58
59 // Zero all bitfields, then set some non-zero defaults.
60 fBitfieldsUInt = 0;
61 fBitfields.fFlags = SkPaintDefaults_Flags;
62 fBitfields.fCapType = kDefault_Cap;
63 fBitfields.fJoinType = kDefault_Join;
64 fBitfields.fTextAlign = kLeft_Align;
65 fBitfields.fStyle = kFill_Style;
66 fBitfields.fTextEncoding = kUTF8_TextEncoding;
67 fBitfields.fHinting = SkPaintDefaults_Hinting;
68 }
69
SkPaint(const SkPaint & src)70 SkPaint::SkPaint(const SkPaint& src)
71 #define COPY(field) field(src.field)
72 : COPY(fTypeface)
73 , COPY(fPathEffect)
74 , COPY(fShader)
75 , COPY(fMaskFilter)
76 , COPY(fColorFilter)
77 , COPY(fDrawLooper)
78 , COPY(fImageFilter)
79 , COPY(fTextSize)
80 , COPY(fTextScaleX)
81 , COPY(fTextSkewX)
82 , COPY(fColor)
83 , COPY(fWidth)
84 , COPY(fMiterLimit)
85 , COPY(fBlendMode)
86 , COPY(fBitfields)
87 #undef COPY
88 {}
89
SkPaint(SkPaint && src)90 SkPaint::SkPaint(SkPaint&& src) {
91 #define MOVE(field) field = std::move(src.field)
92 MOVE(fTypeface);
93 MOVE(fPathEffect);
94 MOVE(fShader);
95 MOVE(fMaskFilter);
96 MOVE(fColorFilter);
97 MOVE(fDrawLooper);
98 MOVE(fImageFilter);
99 MOVE(fTextSize);
100 MOVE(fTextScaleX);
101 MOVE(fTextSkewX);
102 MOVE(fColor);
103 MOVE(fWidth);
104 MOVE(fMiterLimit);
105 MOVE(fBlendMode);
106 MOVE(fBitfields);
107 #undef MOVE
108 }
109
~SkPaint()110 SkPaint::~SkPaint() {}
111
operator =(const SkPaint & src)112 SkPaint& SkPaint::operator=(const SkPaint& src) {
113 if (this == &src) {
114 return *this;
115 }
116
117 #define ASSIGN(field) field = src.field
118 ASSIGN(fTypeface);
119 ASSIGN(fPathEffect);
120 ASSIGN(fShader);
121 ASSIGN(fMaskFilter);
122 ASSIGN(fColorFilter);
123 ASSIGN(fDrawLooper);
124 ASSIGN(fImageFilter);
125 ASSIGN(fTextSize);
126 ASSIGN(fTextScaleX);
127 ASSIGN(fTextSkewX);
128 ASSIGN(fColor);
129 ASSIGN(fWidth);
130 ASSIGN(fMiterLimit);
131 ASSIGN(fBlendMode);
132 ASSIGN(fBitfields);
133 #undef ASSIGN
134
135 return *this;
136 }
137
operator =(SkPaint && src)138 SkPaint& SkPaint::operator=(SkPaint&& src) {
139 if (this == &src) {
140 return *this;
141 }
142
143 #define MOVE(field) field = std::move(src.field)
144 MOVE(fTypeface);
145 MOVE(fPathEffect);
146 MOVE(fShader);
147 MOVE(fMaskFilter);
148 MOVE(fColorFilter);
149 MOVE(fDrawLooper);
150 MOVE(fImageFilter);
151 MOVE(fTextSize);
152 MOVE(fTextScaleX);
153 MOVE(fTextSkewX);
154 MOVE(fColor);
155 MOVE(fWidth);
156 MOVE(fMiterLimit);
157 MOVE(fBlendMode);
158 MOVE(fBitfields);
159 #undef MOVE
160
161 return *this;
162 }
163
operator ==(const SkPaint & a,const SkPaint & b)164 bool operator==(const SkPaint& a, const SkPaint& b) {
165 #define EQUAL(field) (a.field == b.field)
166 return EQUAL(fTypeface)
167 && EQUAL(fPathEffect)
168 && EQUAL(fShader)
169 && EQUAL(fMaskFilter)
170 && EQUAL(fColorFilter)
171 && EQUAL(fDrawLooper)
172 && EQUAL(fImageFilter)
173 && EQUAL(fTextSize)
174 && EQUAL(fTextScaleX)
175 && EQUAL(fTextSkewX)
176 && EQUAL(fColor)
177 && EQUAL(fWidth)
178 && EQUAL(fMiterLimit)
179 && EQUAL(fBlendMode)
180 && EQUAL(fBitfieldsUInt)
181 ;
182 #undef EQUAL
183 }
184
185 #define DEFINE_REF_FOO(type) sk_sp<Sk##type> SkPaint::ref##type() const { return f##type; }
186 DEFINE_REF_FOO(ColorFilter)
DEFINE_REF_FOO(DrawLooper)187 DEFINE_REF_FOO(DrawLooper)
188 DEFINE_REF_FOO(ImageFilter)
189 DEFINE_REF_FOO(MaskFilter)
190 DEFINE_REF_FOO(PathEffect)
191 DEFINE_REF_FOO(Shader)
192 DEFINE_REF_FOO(Typeface)
193 #undef DEFINE_REF_FOO
194
195 void SkPaint::reset() {
196 SkPaint init;
197 *this = init;
198 }
199
setFilterQuality(SkFilterQuality quality)200 void SkPaint::setFilterQuality(SkFilterQuality quality) {
201 fBitfields.fFilterQuality = quality;
202 }
203
setHinting(Hinting hintingLevel)204 void SkPaint::setHinting(Hinting hintingLevel) {
205 fBitfields.fHinting = hintingLevel;
206 }
207
setFlags(uint32_t flags)208 void SkPaint::setFlags(uint32_t flags) {
209 fBitfields.fFlags = flags;
210 }
211
setAntiAlias(bool doAA)212 void SkPaint::setAntiAlias(bool doAA) {
213 this->setFlags(set_clear_mask(fBitfields.fFlags, doAA, kAntiAlias_Flag));
214 }
215
setDither(bool doDither)216 void SkPaint::setDither(bool doDither) {
217 this->setFlags(set_clear_mask(fBitfields.fFlags, doDither, kDither_Flag));
218 }
219
setSubpixelText(bool doSubpixel)220 void SkPaint::setSubpixelText(bool doSubpixel) {
221 this->setFlags(set_clear_mask(fBitfields.fFlags, doSubpixel, kSubpixelText_Flag));
222 }
223
setLCDRenderText(bool doLCDRender)224 void SkPaint::setLCDRenderText(bool doLCDRender) {
225 this->setFlags(set_clear_mask(fBitfields.fFlags, doLCDRender, kLCDRenderText_Flag));
226 }
227
setEmbeddedBitmapText(bool doEmbeddedBitmapText)228 void SkPaint::setEmbeddedBitmapText(bool doEmbeddedBitmapText) {
229 this->setFlags(set_clear_mask(fBitfields.fFlags, doEmbeddedBitmapText, kEmbeddedBitmapText_Flag));
230 }
231
setAutohinted(bool useAutohinter)232 void SkPaint::setAutohinted(bool useAutohinter) {
233 this->setFlags(set_clear_mask(fBitfields.fFlags, useAutohinter, kAutoHinting_Flag));
234 }
235
setLinearText(bool doLinearText)236 void SkPaint::setLinearText(bool doLinearText) {
237 this->setFlags(set_clear_mask(fBitfields.fFlags, doLinearText, kLinearText_Flag));
238 }
239
setVerticalText(bool doVertical)240 void SkPaint::setVerticalText(bool doVertical) {
241 this->setFlags(set_clear_mask(fBitfields.fFlags, doVertical, kVerticalText_Flag));
242 }
243
setFakeBoldText(bool doFakeBold)244 void SkPaint::setFakeBoldText(bool doFakeBold) {
245 this->setFlags(set_clear_mask(fBitfields.fFlags, doFakeBold, kFakeBoldText_Flag));
246 }
247
setDevKernText(bool doDevKern)248 void SkPaint::setDevKernText(bool doDevKern) {
249 this->setFlags(set_clear_mask(fBitfields.fFlags, doDevKern, kDevKernText_Flag));
250 }
251
setStyle(Style style)252 void SkPaint::setStyle(Style style) {
253 if ((unsigned)style < kStyleCount) {
254 fBitfields.fStyle = style;
255 } else {
256 #ifdef SK_REPORT_API_RANGE_CHECK
257 SkDebugf("SkPaint::setStyle(%d) out of range\n", style);
258 #endif
259 }
260 }
261
setColor(SkColor color)262 void SkPaint::setColor(SkColor color) {
263 fColor = color;
264 }
265
setAlpha(U8CPU a)266 void SkPaint::setAlpha(U8CPU a) {
267 this->setColor(SkColorSetARGB(a, SkColorGetR(fColor),
268 SkColorGetG(fColor), SkColorGetB(fColor)));
269 }
270
setARGB(U8CPU a,U8CPU r,U8CPU g,U8CPU b)271 void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
272 this->setColor(SkColorSetARGB(a, r, g, b));
273 }
274
setStrokeWidth(SkScalar width)275 void SkPaint::setStrokeWidth(SkScalar width) {
276 if (width >= 0) {
277 fWidth = width;
278 } else {
279 #ifdef SK_REPORT_API_RANGE_CHECK
280 SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");
281 #endif
282 }
283 }
284
setStrokeMiter(SkScalar limit)285 void SkPaint::setStrokeMiter(SkScalar limit) {
286 if (limit >= 0) {
287 fMiterLimit = limit;
288 } else {
289 #ifdef SK_REPORT_API_RANGE_CHECK
290 SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");
291 #endif
292 }
293 }
294
setStrokeCap(Cap ct)295 void SkPaint::setStrokeCap(Cap ct) {
296 if ((unsigned)ct < kCapCount) {
297 fBitfields.fCapType = SkToU8(ct);
298 } else {
299 #ifdef SK_REPORT_API_RANGE_CHECK
300 SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);
301 #endif
302 }
303 }
304
setStrokeJoin(Join jt)305 void SkPaint::setStrokeJoin(Join jt) {
306 if ((unsigned)jt < kJoinCount) {
307 fBitfields.fJoinType = SkToU8(jt);
308 } else {
309 #ifdef SK_REPORT_API_RANGE_CHECK
310 SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);
311 #endif
312 }
313 }
314
315 ///////////////////////////////////////////////////////////////////////////////
316
setTextAlign(Align align)317 void SkPaint::setTextAlign(Align align) {
318 if ((unsigned)align < kAlignCount) {
319 fBitfields.fTextAlign = SkToU8(align);
320 } else {
321 #ifdef SK_REPORT_API_RANGE_CHECK
322 SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align);
323 #endif
324 }
325 }
326
setTextSize(SkScalar ts)327 void SkPaint::setTextSize(SkScalar ts) {
328 if (ts >= 0) {
329 fTextSize = ts;
330 } else {
331 #ifdef SK_REPORT_API_RANGE_CHECK
332 SkDebugf("SkPaint::setTextSize() called with negative value\n");
333 #endif
334 }
335 }
336
setTextScaleX(SkScalar scaleX)337 void SkPaint::setTextScaleX(SkScalar scaleX) {
338 fTextScaleX = scaleX;
339 }
340
setTextSkewX(SkScalar skewX)341 void SkPaint::setTextSkewX(SkScalar skewX) {
342 fTextSkewX = skewX;
343 }
344
setTextEncoding(TextEncoding encoding)345 void SkPaint::setTextEncoding(TextEncoding encoding) {
346 if ((unsigned)encoding <= kGlyphID_TextEncoding) {
347 fBitfields.fTextEncoding = encoding;
348 } else {
349 #ifdef SK_REPORT_API_RANGE_CHECK
350 SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding);
351 #endif
352 }
353 }
354
355 ///////////////////////////////////////////////////////////////////////////////
356
357 #define MOVE_FIELD(Field) void SkPaint::set##Field(sk_sp<Sk##Field> f) { f##Field = std::move(f); }
358 MOVE_FIELD(Typeface)
MOVE_FIELD(ImageFilter)359 MOVE_FIELD(ImageFilter)
360 MOVE_FIELD(Shader)
361 MOVE_FIELD(ColorFilter)
362 MOVE_FIELD(PathEffect)
363 MOVE_FIELD(MaskFilter)
364 MOVE_FIELD(DrawLooper)
365 #undef MOVE_FIELD
366 void SkPaint::setLooper(sk_sp<SkDrawLooper> looper) { fDrawLooper = std::move(looper); }
367
368 ///////////////////////////////////////////////////////////////////////////////
369
mag2(SkScalar x,SkScalar y)370 static SkScalar mag2(SkScalar x, SkScalar y) {
371 return x * x + y * y;
372 }
373
tooBig(const SkMatrix & m,SkScalar ma2max)374 static bool tooBig(const SkMatrix& m, SkScalar ma2max) {
375 return mag2(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewY]) > ma2max
376 ||
377 mag2(m[SkMatrix::kMSkewX], m[SkMatrix::kMScaleY]) > ma2max;
378 }
379
TooBigToUseCache(const SkMatrix & ctm,const SkMatrix & textM,SkScalar maxLimit)380 bool SkPaint::TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM, SkScalar maxLimit) {
381 SkASSERT(!ctm.hasPerspective());
382 SkASSERT(!textM.hasPerspective());
383
384 SkMatrix matrix;
385 matrix.setConcat(ctm, textM);
386 return tooBig(matrix, MaxCacheSize2(maxLimit));
387 }
388
MaxCacheSize2(SkScalar maxLimit)389 SkScalar SkPaint::MaxCacheSize2(SkScalar maxLimit) {
390 // we have a self-imposed maximum, just for memory-usage sanity
391 const int limit = SkMin32(SkGraphics::GetFontCachePointSizeLimit(), maxLimit);
392 const SkScalar maxSize = SkIntToScalar(limit);
393 return maxSize * maxSize;
394 }
395
396 ///////////////////////////////////////////////////////////////////////////////
397
398 #include "SkGlyphCache.h"
399 #include "SkUtils.h"
400
textToGlyphs(const void * textData,size_t byteLength,uint16_t glyphs[]) const401 int SkPaint::textToGlyphs(const void* textData, size_t byteLength, uint16_t glyphs[]) const {
402 if (byteLength == 0) {
403 return 0;
404 }
405
406 SkASSERT(textData != nullptr);
407
408 if (nullptr == glyphs) {
409 switch (this->getTextEncoding()) {
410 case kUTF8_TextEncoding:
411 return SkUTF8_CountUnichars(textData, byteLength);
412 case kUTF16_TextEncoding:
413 return SkUTF16_CountUnichars(textData, byteLength);
414 case kUTF32_TextEncoding:
415 return SkToInt(byteLength >> 2);
416 case kGlyphID_TextEncoding:
417 return SkToInt(byteLength >> 1);
418 default:
419 SkDEBUGFAIL("unknown text encoding");
420 }
421 return 0;
422 }
423
424 // if we get here, we have a valid glyphs[] array, so time to fill it in
425
426 // handle this encoding before the setup for the glyphcache
427 if (this->getTextEncoding() == kGlyphID_TextEncoding) {
428 // we want to ignore the low bit of byteLength
429 memcpy(glyphs, textData, byteLength >> 1 << 1);
430 return SkToInt(byteLength >> 1);
431 }
432
433 SkAutoGlyphCache autoCache(*this, nullptr, nullptr);
434 SkGlyphCache* cache = autoCache.getCache();
435
436 const char* text = (const char*)textData;
437 const char* stop = text + byteLength;
438 uint16_t* gptr = glyphs;
439
440 switch (this->getTextEncoding()) {
441 case SkPaint::kUTF8_TextEncoding:
442 while (text < stop) {
443 SkUnichar u = SkUTF8_NextUnicharWithError(&text, stop);
444 if (u < 0) {
445 return 0; // bad UTF-8 sequence
446 }
447 *gptr++ = cache->unicharToGlyph(u);
448 }
449 break;
450 case SkPaint::kUTF16_TextEncoding: {
451 const uint16_t* text16 = (const uint16_t*)text;
452 const uint16_t* stop16 = (const uint16_t*)stop;
453 while (text16 < stop16) {
454 *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16));
455 }
456 break;
457 }
458 case kUTF32_TextEncoding: {
459 const int32_t* text32 = (const int32_t*)text;
460 const int32_t* stop32 = (const int32_t*)stop;
461 while (text32 < stop32) {
462 *gptr++ = cache->unicharToGlyph(*text32++);
463 }
464 break;
465 }
466 default:
467 SkDEBUGFAIL("unknown text encoding");
468 }
469 return SkToInt(gptr - glyphs);
470 }
471
containsText(const void * textData,size_t byteLength) const472 bool SkPaint::containsText(const void* textData, size_t byteLength) const {
473 if (0 == byteLength) {
474 return true;
475 }
476
477 SkASSERT(textData != nullptr);
478
479 // handle this encoding before the setup for the glyphcache
480 if (this->getTextEncoding() == kGlyphID_TextEncoding) {
481 const uint16_t* glyphID = static_cast<const uint16_t*>(textData);
482 size_t count = byteLength >> 1;
483 for (size_t i = 0; i < count; i++) {
484 if (0 == glyphID[i]) {
485 return false;
486 }
487 }
488 return true;
489 }
490
491 SkAutoGlyphCache autoCache(*this, nullptr, nullptr);
492 SkGlyphCache* cache = autoCache.getCache();
493
494 switch (this->getTextEncoding()) {
495 case SkPaint::kUTF8_TextEncoding: {
496 const char* text = static_cast<const char*>(textData);
497 const char* stop = text + byteLength;
498 while (text < stop) {
499 if (0 == cache->unicharToGlyph(SkUTF8_NextUnichar(&text))) {
500 return false;
501 }
502 }
503 break;
504 }
505 case SkPaint::kUTF16_TextEncoding: {
506 const uint16_t* text = static_cast<const uint16_t*>(textData);
507 const uint16_t* stop = text + (byteLength >> 1);
508 while (text < stop) {
509 if (0 == cache->unicharToGlyph(SkUTF16_NextUnichar(&text))) {
510 return false;
511 }
512 }
513 break;
514 }
515 case SkPaint::kUTF32_TextEncoding: {
516 const int32_t* text = static_cast<const int32_t*>(textData);
517 const int32_t* stop = text + (byteLength >> 2);
518 while (text < stop) {
519 if (0 == cache->unicharToGlyph(*text++)) {
520 return false;
521 }
522 }
523 break;
524 }
525 default:
526 SkDEBUGFAIL("unknown text encoding");
527 return false;
528 }
529 return true;
530 }
531
glyphsToUnichars(const uint16_t glyphs[],int count,SkUnichar textData[]) const532 void SkPaint::glyphsToUnichars(const uint16_t glyphs[], int count, SkUnichar textData[]) const {
533 if (count <= 0) {
534 return;
535 }
536
537 SkASSERT(glyphs != nullptr);
538 SkASSERT(textData != nullptr);
539
540 SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
541 SkAutoGlyphCache autoCache(*this, &props, nullptr);
542 SkGlyphCache* cache = autoCache.getCache();
543
544 for (int index = 0; index < count; index++) {
545 textData[index] = cache->glyphToUnichar(glyphs[index]);
546 }
547 }
548
549 ///////////////////////////////////////////////////////////////////////////////
550
sk_getMetrics_utf8_next(SkGlyphCache * cache,const char ** text)551 static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache,
552 const char** text) {
553 SkASSERT(cache != nullptr);
554 SkASSERT(text != nullptr);
555
556 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text));
557 }
558
sk_getMetrics_utf16_next(SkGlyphCache * cache,const char ** text)559 static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache,
560 const char** text) {
561 SkASSERT(cache != nullptr);
562 SkASSERT(text != nullptr);
563
564 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text));
565 }
566
sk_getMetrics_utf32_next(SkGlyphCache * cache,const char ** text)567 static const SkGlyph& sk_getMetrics_utf32_next(SkGlyphCache* cache,
568 const char** text) {
569 SkASSERT(cache != nullptr);
570 SkASSERT(text != nullptr);
571
572 const int32_t* ptr = *(const int32_t**)text;
573 SkUnichar uni = *ptr++;
574 *text = (const char*)ptr;
575 return cache->getUnicharMetrics(uni);
576 }
577
sk_getMetrics_glyph_next(SkGlyphCache * cache,const char ** text)578 static const SkGlyph& sk_getMetrics_glyph_next(SkGlyphCache* cache,
579 const char** text) {
580 SkASSERT(cache != nullptr);
581 SkASSERT(text != nullptr);
582
583 const uint16_t* ptr = *(const uint16_t**)text;
584 unsigned glyphID = *ptr;
585 ptr += 1;
586 *text = (const char*)ptr;
587 return cache->getGlyphIDMetrics(glyphID);
588 }
589
sk_getAdvance_utf8_next(SkGlyphCache * cache,const char ** text)590 static const SkGlyph& sk_getAdvance_utf8_next(SkGlyphCache* cache,
591 const char** text) {
592 SkASSERT(cache != nullptr);
593 SkASSERT(text != nullptr);
594
595 return cache->getUnicharAdvance(SkUTF8_NextUnichar(text));
596 }
597
sk_getAdvance_utf16_next(SkGlyphCache * cache,const char ** text)598 static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache,
599 const char** text) {
600 SkASSERT(cache != nullptr);
601 SkASSERT(text != nullptr);
602
603 return cache->getUnicharAdvance(SkUTF16_NextUnichar((const uint16_t**)text));
604 }
605
sk_getAdvance_utf32_next(SkGlyphCache * cache,const char ** text)606 static const SkGlyph& sk_getAdvance_utf32_next(SkGlyphCache* cache,
607 const char** text) {
608 SkASSERT(cache != nullptr);
609 SkASSERT(text != nullptr);
610
611 const int32_t* ptr = *(const int32_t**)text;
612 SkUnichar uni = *ptr++;
613 *text = (const char*)ptr;
614 return cache->getUnicharAdvance(uni);
615 }
616
sk_getAdvance_glyph_next(SkGlyphCache * cache,const char ** text)617 static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache,
618 const char** text) {
619 SkASSERT(cache != nullptr);
620 SkASSERT(text != nullptr);
621
622 const uint16_t* ptr = *(const uint16_t**)text;
623 unsigned glyphID = *ptr;
624 ptr += 1;
625 *text = (const char*)ptr;
626 return cache->getGlyphIDAdvance(glyphID);
627 }
628
GetGlyphCacheProc(TextEncoding encoding,bool isDevKern,bool needFullMetrics)629 SkPaint::GlyphCacheProc SkPaint::GetGlyphCacheProc(TextEncoding encoding,
630 bool isDevKern,
631 bool needFullMetrics) {
632 static const GlyphCacheProc gGlyphCacheProcs[] = {
633 sk_getMetrics_utf8_next,
634 sk_getMetrics_utf16_next,
635 sk_getMetrics_utf32_next,
636 sk_getMetrics_glyph_next,
637
638 sk_getAdvance_utf8_next,
639 sk_getAdvance_utf16_next,
640 sk_getAdvance_utf32_next,
641 sk_getAdvance_glyph_next,
642 };
643
644 unsigned index = encoding;
645
646 if (!needFullMetrics && !isDevKern) {
647 index += 4;
648 }
649
650 SkASSERT(index < SK_ARRAY_COUNT(gGlyphCacheProcs));
651 return gGlyphCacheProcs[index];
652 }
653
654 ///////////////////////////////////////////////////////////////////////////////
655
656 #define TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE ( \
657 SkPaint::kDevKernText_Flag | \
658 SkPaint::kLinearText_Flag | \
659 SkPaint::kLCDRenderText_Flag | \
660 SkPaint::kEmbeddedBitmapText_Flag | \
661 SkPaint::kAutoHinting_Flag | \
662 SkPaint::kGenA8FromLCD_Flag )
663
setupForAsPaths()664 SkScalar SkPaint::setupForAsPaths() {
665 uint32_t flags = this->getFlags();
666 // clear the flags we don't care about
667 flags &= ~TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE;
668 // set the flags we do care about
669 flags |= SkPaint::kSubpixelText_Flag;
670
671 this->setFlags(flags);
672 this->setHinting(SkPaint::kNo_Hinting);
673
674 SkScalar textSize = fTextSize;
675 this->setTextSize(kCanonicalTextSizeForPaths);
676 return textSize / kCanonicalTextSizeForPaths;
677 }
678
679 class SkCanonicalizePaint {
680 public:
SkCanonicalizePaint(const SkPaint & paint)681 SkCanonicalizePaint(const SkPaint& paint) : fPaint(&paint), fScale(0) {
682 if (paint.isLinearText() || SkDraw::ShouldDrawTextAsPaths(paint, SkMatrix::I())) {
683 SkPaint* p = fLazy.set(paint);
684 fScale = p->setupForAsPaths();
685 fPaint = p;
686 }
687 }
688
getPaint() const689 const SkPaint& getPaint() const { return *fPaint; }
690
691 /**
692 * Returns 0 if the paint was unmodified, or the scale factor need to
693 * the original textSize
694 */
getScale() const695 SkScalar getScale() const { return fScale; }
696
697 private:
698 const SkPaint* fPaint;
699 SkScalar fScale;
700 SkTLazy<SkPaint> fLazy;
701 };
702
set_bounds(const SkGlyph & g,SkRect * bounds)703 static void set_bounds(const SkGlyph& g, SkRect* bounds) {
704 bounds->set(SkIntToScalar(g.fLeft),
705 SkIntToScalar(g.fTop),
706 SkIntToScalar(g.fLeft + g.fWidth),
707 SkIntToScalar(g.fTop + g.fHeight));
708 }
709
join_bounds_x(const SkGlyph & g,SkRect * bounds,SkScalar dx)710 static void join_bounds_x(const SkGlyph& g, SkRect* bounds, SkScalar dx) {
711 bounds->join(SkIntToScalar(g.fLeft) + dx,
712 SkIntToScalar(g.fTop),
713 SkIntToScalar(g.fLeft + g.fWidth) + dx,
714 SkIntToScalar(g.fTop + g.fHeight));
715 }
716
join_bounds_y(const SkGlyph & g,SkRect * bounds,SkScalar dy)717 static void join_bounds_y(const SkGlyph& g, SkRect* bounds, SkScalar dy) {
718 bounds->join(SkIntToScalar(g.fLeft),
719 SkIntToScalar(g.fTop) + dy,
720 SkIntToScalar(g.fLeft + g.fWidth),
721 SkIntToScalar(g.fTop + g.fHeight) + dy);
722 }
723
724 typedef void (*JoinBoundsProc)(const SkGlyph&, SkRect*, SkScalar);
725
726 // xyIndex is 0 for fAdvanceX or 1 for fAdvanceY
advance(const SkGlyph & glyph,int xyIndex)727 static SkScalar advance(const SkGlyph& glyph, int xyIndex) {
728 SkASSERT(0 == xyIndex || 1 == xyIndex);
729 return SkFloatToScalar((&glyph.fAdvanceX)[xyIndex]);
730 }
731
measure_text(SkGlyphCache * cache,const char * text,size_t byteLength,int * count,SkRect * bounds) const732 SkScalar SkPaint::measure_text(SkGlyphCache* cache,
733 const char* text, size_t byteLength,
734 int* count, SkRect* bounds) const {
735 SkASSERT(count);
736 if (byteLength == 0) {
737 *count = 0;
738 if (bounds) {
739 bounds->setEmpty();
740 }
741 return 0;
742 }
743
744 GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(this->getTextEncoding(),
745 this->isDevKernText(),
746 nullptr != bounds);
747
748 int xyIndex;
749 JoinBoundsProc joinBoundsProc;
750 if (this->isVerticalText()) {
751 xyIndex = 1;
752 joinBoundsProc = join_bounds_y;
753 } else {
754 xyIndex = 0;
755 joinBoundsProc = join_bounds_x;
756 }
757
758 int n = 1;
759 const char* stop = (const char*)text + byteLength;
760 const SkGlyph* g = &glyphCacheProc(cache, &text);
761 SkScalar x = advance(*g, xyIndex);
762
763 if (nullptr == bounds) {
764 if (this->isDevKernText()) {
765 for (; text < stop; n++) {
766 const int rsb = g->fRsbDelta;
767 g = &glyphCacheProc(cache, &text);
768 x += SkAutoKern_Adjust(rsb, g->fLsbDelta) + advance(*g, xyIndex);
769 }
770 } else {
771 for (; text < stop; n++) {
772 x += advance(glyphCacheProc(cache, &text), xyIndex);
773 }
774 }
775 } else {
776 set_bounds(*g, bounds);
777 if (this->isDevKernText()) {
778 for (; text < stop; n++) {
779 const int rsb = g->fRsbDelta;
780 g = &glyphCacheProc(cache, &text);
781 x += SkAutoKern_Adjust(rsb, g->fLsbDelta);
782 joinBoundsProc(*g, bounds, x);
783 x += advance(*g, xyIndex);
784 }
785 } else {
786 for (; text < stop; n++) {
787 g = &glyphCacheProc(cache, &text);
788 joinBoundsProc(*g, bounds, x);
789 x += advance(*g, xyIndex);
790 }
791 }
792 }
793 SkASSERT(text == stop);
794
795 *count = n;
796 return x;
797 }
798
measureText(const void * textData,size_t length,SkRect * bounds) const799 SkScalar SkPaint::measureText(const void* textData, size_t length, SkRect* bounds) const {
800 const char* text = (const char*)textData;
801 SkASSERT(text != nullptr || length == 0);
802
803 SkCanonicalizePaint canon(*this);
804 const SkPaint& paint = canon.getPaint();
805 SkScalar scale = canon.getScale();
806
807 SkAutoGlyphCache autoCache(paint, nullptr, nullptr);
808 SkGlyphCache* cache = autoCache.getCache();
809
810 SkScalar width = 0;
811
812 if (length > 0) {
813 int tempCount;
814
815 width = paint.measure_text(cache, text, length, &tempCount, bounds);
816 if (scale) {
817 width *= scale;
818 if (bounds) {
819 bounds->fLeft *= scale;
820 bounds->fTop *= scale;
821 bounds->fRight *= scale;
822 bounds->fBottom *= scale;
823 }
824 }
825 } else if (bounds) {
826 // ensure that even if we don't measure_text we still update the bounds
827 bounds->setEmpty();
828 }
829 return width;
830 }
831
breakText(const void * textD,size_t length,SkScalar maxWidth,SkScalar * measuredWidth) const832 size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
833 SkScalar* measuredWidth) const {
834 if (0 == length || 0 >= maxWidth) {
835 if (measuredWidth) {
836 *measuredWidth = 0;
837 }
838 return 0;
839 }
840
841 if (0 == fTextSize) {
842 if (measuredWidth) {
843 *measuredWidth = 0;
844 }
845 return length;
846 }
847
848 SkASSERT(textD != nullptr);
849 const char* text = (const char*)textD;
850 const char* stop = text + length;
851
852 SkCanonicalizePaint canon(*this);
853 const SkPaint& paint = canon.getPaint();
854 SkScalar scale = canon.getScale();
855
856 // adjust max in case we changed the textSize in paint
857 if (scale) {
858 maxWidth /= scale;
859 }
860
861 SkAutoGlyphCache autoCache(paint, nullptr, nullptr);
862 SkGlyphCache* cache = autoCache.getCache();
863
864 GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
865 paint.isDevKernText(),
866 false);
867 const int xyIndex = paint.isVerticalText() ? 1 : 0;
868 SkScalar width = 0;
869
870 if (this->isDevKernText()) {
871 int rsb = 0;
872 while (text < stop) {
873 const char* curr = text;
874 const SkGlyph& g = glyphCacheProc(cache, &text);
875 SkScalar x = SkAutoKern_Adjust(rsb, g.fLsbDelta) + advance(g, xyIndex);
876 if ((width += x) > maxWidth) {
877 width -= x;
878 text = curr;
879 break;
880 }
881 rsb = g.fRsbDelta;
882 }
883 } else {
884 while (text < stop) {
885 const char* curr = text;
886 SkScalar x = advance(glyphCacheProc(cache, &text), xyIndex);
887 if ((width += x) > maxWidth) {
888 width -= x;
889 text = curr;
890 break;
891 }
892 }
893 }
894
895 if (measuredWidth) {
896 if (scale) {
897 width *= scale;
898 }
899 *measuredWidth = width;
900 }
901
902 // return the number of bytes measured
903 return text - stop + length;
904 }
905
906 ///////////////////////////////////////////////////////////////////////////////
907
FontMetricsCacheProc(const SkGlyphCache * cache,void * context)908 static bool FontMetricsCacheProc(const SkGlyphCache* cache, void* context) {
909 *(SkPaint::FontMetrics*)context = cache->getFontMetrics();
910 return false; // don't detach the cache
911 }
912
getFontMetrics(FontMetrics * metrics,SkScalar zoom) const913 SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const {
914 SkCanonicalizePaint canon(*this);
915 const SkPaint& paint = canon.getPaint();
916 SkScalar scale = canon.getScale();
917
918 SkMatrix zoomMatrix, *zoomPtr = nullptr;
919 if (zoom) {
920 zoomMatrix.setScale(zoom, zoom);
921 zoomPtr = &zoomMatrix;
922 }
923
924 FontMetrics storage;
925 if (nullptr == metrics) {
926 metrics = &storage;
927 }
928
929 SkAutoDescriptor ad;
930 SkScalerContextEffects effects;
931
932 auto desc = SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
933 paint, nullptr, SkScalerContextFlags::kNone, zoomPtr, &ad, &effects);
934
935 SkGlyphCache::VisitCache(paint.getTypeface(), effects, desc, FontMetricsCacheProc, metrics);
936
937 if (scale) {
938 SkPaintPriv::ScaleFontMetrics(metrics, scale);
939 }
940 return metrics->fDescent - metrics->fAscent + metrics->fLeading;
941 }
942
943 ///////////////////////////////////////////////////////////////////////////////
944
set_bounds(const SkGlyph & g,SkRect * bounds,SkScalar scale)945 static void set_bounds(const SkGlyph& g, SkRect* bounds, SkScalar scale) {
946 bounds->set(g.fLeft * scale,
947 g.fTop * scale,
948 (g.fLeft + g.fWidth) * scale,
949 (g.fTop + g.fHeight) * scale);
950 }
951
getTextWidths(const void * textData,size_t byteLength,SkScalar widths[],SkRect bounds[]) const952 int SkPaint::getTextWidths(const void* textData, size_t byteLength,
953 SkScalar widths[], SkRect bounds[]) const {
954 if (0 == byteLength) {
955 return 0;
956 }
957
958 SkASSERT(textData);
959
960 if (nullptr == widths && nullptr == bounds) {
961 return this->countText(textData, byteLength);
962 }
963
964 SkCanonicalizePaint canon(*this);
965 const SkPaint& paint = canon.getPaint();
966 SkScalar scale = canon.getScale();
967
968 SkAutoGlyphCache autoCache(paint, nullptr, nullptr);
969 SkGlyphCache* cache = autoCache.getCache();
970 GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
971 paint.isDevKernText(),
972 nullptr != bounds);
973
974 const char* text = (const char*)textData;
975 const char* stop = text + byteLength;
976 int count = 0;
977 const int xyIndex = paint.isVerticalText() ? 1 : 0;
978
979 if (this->isDevKernText()) {
980 // we adjust the widths returned here through auto-kerning
981 SkAutoKern autokern;
982 SkScalar prevWidth = 0;
983
984 if (scale) {
985 while (text < stop) {
986 const SkGlyph& g = glyphCacheProc(cache, &text);
987 if (widths) {
988 SkScalar adjust = autokern.adjust(g);
989
990 if (count > 0) {
991 *widths++ = (prevWidth + adjust) * scale;
992 }
993 prevWidth = advance(g, xyIndex);
994 }
995 if (bounds) {
996 set_bounds(g, bounds++, scale);
997 }
998 ++count;
999 }
1000 if (count > 0 && widths) {
1001 *widths = prevWidth * scale;
1002 }
1003 } else {
1004 while (text < stop) {
1005 const SkGlyph& g = glyphCacheProc(cache, &text);
1006 if (widths) {
1007 SkScalar adjust = autokern.adjust(g);
1008
1009 if (count > 0) {
1010 *widths++ = prevWidth + adjust;
1011 }
1012 prevWidth = advance(g, xyIndex);
1013 }
1014 if (bounds) {
1015 set_bounds(g, bounds++);
1016 }
1017 ++count;
1018 }
1019 if (count > 0 && widths) {
1020 *widths = prevWidth;
1021 }
1022 }
1023 } else { // no devkern
1024 if (scale) {
1025 while (text < stop) {
1026 const SkGlyph& g = glyphCacheProc(cache, &text);
1027 if (widths) {
1028 *widths++ = advance(g, xyIndex) * scale;
1029 }
1030 if (bounds) {
1031 set_bounds(g, bounds++, scale);
1032 }
1033 ++count;
1034 }
1035 } else {
1036 while (text < stop) {
1037 const SkGlyph& g = glyphCacheProc(cache, &text);
1038 if (widths) {
1039 *widths++ = advance(g, xyIndex);
1040 }
1041 if (bounds) {
1042 set_bounds(g, bounds++);
1043 }
1044 ++count;
1045 }
1046 }
1047 }
1048
1049 SkASSERT(text == stop);
1050 return count;
1051 }
1052
1053 ///////////////////////////////////////////////////////////////////////////////
1054
1055 #include "SkDraw.h"
1056
getTextPath(const void * textData,size_t length,SkScalar x,SkScalar y,SkPath * path) const1057 void SkPaint::getTextPath(const void* textData, size_t length,
1058 SkScalar x, SkScalar y, SkPath* path) const {
1059 SkASSERT(length == 0 || textData != nullptr);
1060
1061 const char* text = (const char*)textData;
1062 if (text == nullptr || length == 0 || path == nullptr) {
1063 return;
1064 }
1065
1066 SkTextToPathIter iter(text, length, *this, false);
1067 SkMatrix matrix;
1068 SkScalar prevXPos = 0;
1069
1070 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1071 matrix.postTranslate(x, y);
1072 path->reset();
1073
1074 SkScalar xpos;
1075 const SkPath* iterPath;
1076 while (iter.next(&iterPath, &xpos)) {
1077 matrix.postTranslate(xpos - prevXPos, 0);
1078 if (iterPath) {
1079 path->addPath(*iterPath, matrix);
1080 }
1081 prevXPos = xpos;
1082 }
1083 }
1084
getPosTextPath(const void * textData,size_t length,const SkPoint pos[],SkPath * path) const1085 void SkPaint::getPosTextPath(const void* textData, size_t length,
1086 const SkPoint pos[], SkPath* path) const {
1087 SkASSERT(length == 0 || textData != nullptr);
1088
1089 const char* text = (const char*)textData;
1090 if (text == nullptr || length == 0 || path == nullptr) {
1091 return;
1092 }
1093
1094 SkTextToPathIter iter(text, length, *this, false);
1095 SkMatrix matrix;
1096 SkPoint prevPos;
1097 prevPos.set(0, 0);
1098
1099 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1100 path->reset();
1101
1102 unsigned int i = 0;
1103 const SkPath* iterPath;
1104 while (iter.next(&iterPath, nullptr)) {
1105 matrix.postTranslate(pos[i].fX - prevPos.fX, pos[i].fY - prevPos.fY);
1106 if (iterPath) {
1107 path->addPath(*iterPath, matrix);
1108 }
1109 prevPos = pos[i];
1110 i++;
1111 }
1112 }
1113
1114 template <SkTextInterceptsIter::TextType TextType, typename Func>
GetTextIntercepts(const SkPaint & paint,const void * text,size_t length,const SkScalar bounds[2],SkScalar * array,Func posMaker)1115 int GetTextIntercepts(const SkPaint& paint, const void* text, size_t length,
1116 const SkScalar bounds[2], SkScalar* array, Func posMaker) {
1117 SkASSERT(length == 0 || text != nullptr);
1118 if (!length) {
1119 return 0;
1120 }
1121
1122 const SkPoint pos0 = posMaker(0);
1123 SkTextInterceptsIter iter(static_cast<const char*>(text), length, paint, bounds,
1124 pos0.x(), pos0.y(), TextType);
1125
1126 int i = 0;
1127 int count = 0;
1128 while (iter.next(array, &count)) {
1129 if (TextType == SkTextInterceptsIter::TextType::kPosText) {
1130 const SkPoint pos = posMaker(++i);
1131 iter.setPosition(pos.x(), pos.y());
1132 }
1133 }
1134
1135 return count;
1136 }
1137
getTextIntercepts(const void * textData,size_t length,SkScalar x,SkScalar y,const SkScalar bounds[2],SkScalar * array) const1138 int SkPaint::getTextIntercepts(const void* textData, size_t length,
1139 SkScalar x, SkScalar y, const SkScalar bounds[2],
1140 SkScalar* array) const {
1141
1142 return GetTextIntercepts<SkTextInterceptsIter::TextType::kText>(
1143 *this, textData, length, bounds, array, [&x, &y] (int) -> SkPoint {
1144 return SkPoint::Make(x, y);
1145 });
1146 }
1147
getPosTextIntercepts(const void * textData,size_t length,const SkPoint pos[],const SkScalar bounds[2],SkScalar * array) const1148 int SkPaint::getPosTextIntercepts(const void* textData, size_t length, const SkPoint pos[],
1149 const SkScalar bounds[2], SkScalar* array) const {
1150
1151 return GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
1152 *this, textData, length, bounds, array, [&pos] (int i) -> SkPoint {
1153 return pos[i];
1154 });
1155 }
1156
getPosTextHIntercepts(const void * textData,size_t length,const SkScalar xpos[],SkScalar constY,const SkScalar bounds[2],SkScalar * array) const1157 int SkPaint::getPosTextHIntercepts(const void* textData, size_t length, const SkScalar xpos[],
1158 SkScalar constY, const SkScalar bounds[2],
1159 SkScalar* array) const {
1160
1161 return GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
1162 *this, textData, length, bounds, array, [&xpos, &constY] (int i) -> SkPoint {
1163 return SkPoint::Make(xpos[i], constY);
1164 });
1165 }
1166
getTextBlobIntercepts(const SkTextBlob * blob,const SkScalar bounds[2],SkScalar * intervals) const1167 int SkPaint::getTextBlobIntercepts(const SkTextBlob* blob, const SkScalar bounds[2],
1168 SkScalar* intervals) const {
1169 int count = 0;
1170 SkPaint runPaint(*this);
1171
1172 SkTextBlobRunIterator it(blob);
1173 while (!it.done()) {
1174 it.applyFontToPaint(&runPaint);
1175 const size_t runByteCount = it.glyphCount() * sizeof(SkGlyphID);
1176 SkScalar* runIntervals = intervals ? intervals + count : nullptr;
1177
1178 switch (it.positioning()) {
1179 case SkTextBlob::kDefault_Positioning:
1180 count += runPaint.getTextIntercepts(it.glyphs(), runByteCount, it.offset().x(),
1181 it.offset().y(), bounds, runIntervals);
1182 break;
1183 case SkTextBlob::kHorizontal_Positioning:
1184 count += runPaint.getPosTextHIntercepts(it.glyphs(), runByteCount, it.pos(),
1185 it.offset().y(), bounds, runIntervals);
1186 break;
1187 case SkTextBlob::kFull_Positioning:
1188 count += runPaint.getPosTextIntercepts(it.glyphs(), runByteCount,
1189 reinterpret_cast<const SkPoint*>(it.pos()),
1190 bounds, runIntervals);
1191 break;
1192 }
1193
1194 it.next();
1195 }
1196
1197 return count;
1198 }
1199
getFontBounds() const1200 SkRect SkPaint::getFontBounds() const {
1201 SkMatrix m;
1202 m.setScale(fTextSize * fTextScaleX, fTextSize);
1203 m.postSkew(fTextSkewX, 0);
1204
1205 SkTypeface* typeface = this->getTypeface();
1206 if (nullptr == typeface) {
1207 typeface = SkTypeface::GetDefaultTypeface();
1208 }
1209
1210 SkRect bounds;
1211 m.mapRect(&bounds, typeface->getBounds());
1212 return bounds;
1213 }
1214
1215 // return true if the paint is just a single color (i.e. not a shader). If its
1216 // a shader, then we can't compute a const luminance for it :(
just_a_color(const SkPaint & paint,SkColor * color)1217 static bool just_a_color(const SkPaint& paint, SkColor* color) {
1218 SkColor c = paint.getColor();
1219
1220 const auto* shader = as_SB(paint.getShader());
1221 if (shader && !shader->asLuminanceColor(&c)) {
1222 return false;
1223 }
1224 if (paint.getColorFilter()) {
1225 c = paint.getColorFilter()->filterColor(c);
1226 }
1227 if (color) {
1228 *color = c;
1229 }
1230 return true;
1231 }
1232
computeLuminanceColor() const1233 SkColor SkPaint::computeLuminanceColor() const {
1234 SkColor c;
1235 if (!just_a_color(*this, &c)) {
1236 c = SkColorSetRGB(0x7F, 0x80, 0x7F);
1237 }
1238 return c;
1239 }
1240
1241 /**
1242 * In order to call cachedDeviceLuminance, cachedPaintLuminance, or
1243 * cachedMaskGamma the caller must hold the gMaskGammaCacheMutex and continue
1244 * to hold it until the returned pointer is refed or forgotten.
1245 */
1246 SK_DECLARE_STATIC_MUTEX(gMaskGammaCacheMutex);
1247
1248 static SkMaskGamma* gLinearMaskGamma = nullptr;
1249 static SkMaskGamma* gMaskGamma = nullptr;
1250 static SkScalar gContrast = SK_ScalarMin;
1251 static SkScalar gPaintGamma = SK_ScalarMin;
1252 static SkScalar gDeviceGamma = SK_ScalarMin;
1253
1254 /**
1255 * The caller must hold the gMaskGammaCacheMutex and continue to hold it until
1256 * the returned SkMaskGamma pointer is refed or forgotten.
1257 */
cached_mask_gamma(SkScalar contrast,SkScalar paintGamma,SkScalar deviceGamma)1258 static const SkMaskGamma& cached_mask_gamma(SkScalar contrast, SkScalar paintGamma,
1259 SkScalar deviceGamma) {
1260 gMaskGammaCacheMutex.assertHeld();
1261 if (0 == contrast && SK_Scalar1 == paintGamma && SK_Scalar1 == deviceGamma) {
1262 if (nullptr == gLinearMaskGamma) {
1263 gLinearMaskGamma = new SkMaskGamma;
1264 }
1265 return *gLinearMaskGamma;
1266 }
1267 if (gContrast != contrast || gPaintGamma != paintGamma || gDeviceGamma != deviceGamma) {
1268 SkSafeUnref(gMaskGamma);
1269 gMaskGamma = new SkMaskGamma(contrast, paintGamma, deviceGamma);
1270 gContrast = contrast;
1271 gPaintGamma = paintGamma;
1272 gDeviceGamma = deviceGamma;
1273 }
1274 return *gMaskGamma;
1275 }
1276
1277 /**
1278 * Expands fDeviceGamma, fPaintGamma, fContrast, and fLumBits into a mask pre-blend.
1279 */
GetMaskPreBlend(const SkScalerContextRec & rec)1280 SkMaskGamma::PreBlend SkScalerContext::GetMaskPreBlend(const SkScalerContextRec& rec) {
1281 SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
1282 const SkMaskGamma& maskGamma = cached_mask_gamma(rec.getContrast(),
1283 rec.getPaintGamma(),
1284 rec.getDeviceGamma());
1285 return maskGamma.preBlend(rec.getLuminanceColor());
1286 }
1287
GetGammaLUTSize(SkScalar contrast,SkScalar paintGamma,SkScalar deviceGamma,int * width,int * height)1288 size_t SkScalerContext::GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma,
1289 SkScalar deviceGamma, int* width, int* height) {
1290 SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
1291 const SkMaskGamma& maskGamma = cached_mask_gamma(contrast,
1292 paintGamma,
1293 deviceGamma);
1294
1295 maskGamma.getGammaTableDimensions(width, height);
1296 size_t size = (*width)*(*height)*sizeof(uint8_t);
1297
1298 return size;
1299 }
1300
GetGammaLUTData(SkScalar contrast,SkScalar paintGamma,SkScalar deviceGamma,uint8_t * data)1301 bool SkScalerContext::GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
1302 uint8_t* data) {
1303 SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
1304 const SkMaskGamma& maskGamma = cached_mask_gamma(contrast,
1305 paintGamma,
1306 deviceGamma);
1307 const uint8_t* gammaTables = maskGamma.getGammaTables();
1308 if (!gammaTables) {
1309 return false;
1310 }
1311
1312 int width, height;
1313 maskGamma.getGammaTableDimensions(&width, &height);
1314 size_t size = width*height * sizeof(uint8_t);
1315 memcpy(data, gammaTables, size);
1316 return true;
1317 }
1318
1319 ///////////////////////////////////////////////////////////////////////////////
1320
1321 #include "SkStream.h"
1322
asint(const void * p)1323 static uintptr_t asint(const void* p) {
1324 return reinterpret_cast<uintptr_t>(p);
1325 }
1326
pack_4(unsigned a,unsigned b,unsigned c,unsigned d)1327 static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) {
1328 SkASSERT(a == (uint8_t)a);
1329 SkASSERT(b == (uint8_t)b);
1330 SkASSERT(c == (uint8_t)c);
1331 SkASSERT(d == (uint8_t)d);
1332 return (a << 24) | (b << 16) | (c << 8) | d;
1333 }
1334
1335 #ifdef SK_DEBUG
ASSERT_FITS_IN(uint32_t value,int bitCount)1336 static void ASSERT_FITS_IN(uint32_t value, int bitCount) {
1337 SkASSERT(bitCount > 0 && bitCount <= 32);
1338 uint32_t mask = ~0U;
1339 mask >>= (32 - bitCount);
1340 SkASSERT(0 == (value & ~mask));
1341 }
1342 #else
1343 #define ASSERT_FITS_IN(value, bitcount)
1344 #endif
1345
1346 enum FlatFlags {
1347 kHasTypeface_FlatFlag = 0x1,
1348 kHasEffects_FlatFlag = 0x2,
1349
1350 kFlatFlagMask = 0x3,
1351 };
1352
1353 enum BitsPerField {
1354 kFlags_BPF = 16,
1355 kHint_BPF = 2,
1356 kAlign_BPF = 2,
1357 kFilter_BPF = 2,
1358 kFlatFlags_BPF = 3,
1359 };
1360
BPF_Mask(int bits)1361 static inline int BPF_Mask(int bits) {
1362 return (1 << bits) - 1;
1363 }
1364
pack_paint_flags(unsigned flags,unsigned hint,unsigned align,unsigned filter,unsigned flatFlags)1365 static uint32_t pack_paint_flags(unsigned flags, unsigned hint, unsigned align,
1366 unsigned filter, unsigned flatFlags) {
1367 ASSERT_FITS_IN(flags, kFlags_BPF);
1368 ASSERT_FITS_IN(hint, kHint_BPF);
1369 ASSERT_FITS_IN(align, kAlign_BPF);
1370 ASSERT_FITS_IN(filter, kFilter_BPF);
1371 ASSERT_FITS_IN(flatFlags, kFlatFlags_BPF);
1372
1373 // left-align the fields of "known" size, and right-align the last (flatFlags) so it can easly
1374 // add more bits in the future.
1375 return (flags << 16) | (hint << 14) | (align << 12) | (filter << 10) | flatFlags;
1376 }
1377
unpack_paint_flags(SkPaint * paint,uint32_t packed)1378 static FlatFlags unpack_paint_flags(SkPaint* paint, uint32_t packed) {
1379 paint->setFlags(packed >> 16);
1380 paint->setHinting((SkPaint::Hinting)((packed >> 14) & BPF_Mask(kHint_BPF)));
1381 paint->setTextAlign((SkPaint::Align)((packed >> 12) & BPF_Mask(kAlign_BPF)));
1382 paint->setFilterQuality((SkFilterQuality)((packed >> 10) & BPF_Mask(kFilter_BPF)));
1383 return (FlatFlags)(packed & kFlatFlagMask);
1384 }
1385
1386 /* To save space/time, we analyze the paint, and write a truncated version of
1387 it if there are not tricky elements like shaders, etc.
1388 */
flatten(SkWriteBuffer & buffer) const1389 void SkPaint::flatten(SkWriteBuffer& buffer) const {
1390 SkTypeface* tf = this->getTypeface();
1391 if (!tf) {
1392 // We force recording our typeface, even if its "default" since the receiver process
1393 // may have a different notion of default.
1394 tf = SkTypeface::GetDefaultTypeface();
1395 SkASSERT(tf);
1396 }
1397
1398 uint8_t flatFlags = kHasTypeface_FlatFlag;
1399
1400 if (asint(this->getPathEffect()) |
1401 asint(this->getShader()) |
1402 asint(this->getMaskFilter()) |
1403 asint(this->getColorFilter()) |
1404 asint(this->getLooper()) |
1405 asint(this->getImageFilter())) {
1406 flatFlags |= kHasEffects_FlatFlag;
1407 }
1408
1409 buffer.writeScalar(this->getTextSize());
1410 buffer.writeScalar(this->getTextScaleX());
1411 buffer.writeScalar(this->getTextSkewX());
1412 buffer.writeScalar(this->getStrokeWidth());
1413 buffer.writeScalar(this->getStrokeMiter());
1414 buffer.writeColor(this->getColor());
1415
1416 buffer.writeUInt(pack_paint_flags(this->getFlags(), this->getHinting(), this->getTextAlign(),
1417 this->getFilterQuality(), flatFlags));
1418 buffer.writeUInt(pack_4(this->getStrokeCap(), this->getStrokeJoin(),
1419 (this->getStyle() << 4) | this->getTextEncoding(),
1420 fBlendMode));
1421
1422 buffer.writeTypeface(tf);
1423
1424 if (flatFlags & kHasEffects_FlatFlag) {
1425 buffer.writeFlattenable(this->getPathEffect());
1426 buffer.writeFlattenable(this->getShader());
1427 buffer.writeFlattenable(this->getMaskFilter());
1428 buffer.writeFlattenable(this->getColorFilter());
1429 buffer.write32(0); // use to be SkRasterizer
1430 buffer.writeFlattenable(this->getLooper());
1431 buffer.writeFlattenable(this->getImageFilter());
1432 }
1433 }
1434
unflatten(SkReadBuffer & buffer)1435 bool SkPaint::unflatten(SkReadBuffer& buffer) {
1436 SkSafeRange safe;
1437
1438 this->setTextSize(buffer.readScalar());
1439 this->setTextScaleX(buffer.readScalar());
1440 this->setTextSkewX(buffer.readScalar());
1441 this->setStrokeWidth(buffer.readScalar());
1442 this->setStrokeMiter(buffer.readScalar());
1443 this->setColor(buffer.readColor());
1444
1445 unsigned flatFlags = unpack_paint_flags(this, buffer.readUInt());
1446
1447 uint32_t tmp = buffer.readUInt();
1448 this->setStrokeCap(safe.checkLE((tmp >> 24) & 0xFF, kLast_Cap));
1449 this->setStrokeJoin(safe.checkLE((tmp >> 16) & 0xFF, kLast_Join));
1450 this->setStyle(safe.checkLE((tmp >> 12) & 0xF, kStrokeAndFill_Style));
1451 this->setTextEncoding(safe.checkLE((tmp >> 8) & 0xF, kGlyphID_TextEncoding));
1452 this->setBlendMode(safe.checkLE(tmp & 0xFF, SkBlendMode::kLastMode));
1453
1454 if (flatFlags & kHasTypeface_FlatFlag) {
1455 this->setTypeface(buffer.readTypeface());
1456 } else {
1457 this->setTypeface(nullptr);
1458 }
1459
1460 if (flatFlags & kHasEffects_FlatFlag) {
1461 this->setPathEffect(buffer.readPathEffect());
1462 this->setShader(buffer.readShader());
1463 this->setMaskFilter(buffer.readMaskFilter());
1464 this->setColorFilter(buffer.readColorFilter());
1465 (void)buffer.read32(); // use to be SkRasterizer
1466 this->setLooper(buffer.readDrawLooper());
1467 this->setImageFilter(buffer.readImageFilter());
1468 } else {
1469 this->setPathEffect(nullptr);
1470 this->setShader(nullptr);
1471 this->setMaskFilter(nullptr);
1472 this->setColorFilter(nullptr);
1473 this->setLooper(nullptr);
1474 this->setImageFilter(nullptr);
1475 }
1476
1477 if (!buffer.validate(safe)) {
1478 this->reset();
1479 return false;
1480 }
1481 return true;
1482 }
1483
1484 ///////////////////////////////////////////////////////////////////////////////
1485
getFillPath(const SkPath & src,SkPath * dst,const SkRect * cullRect,SkScalar resScale) const1486 bool SkPaint::getFillPath(const SkPath& src, SkPath* dst, const SkRect* cullRect,
1487 SkScalar resScale) const {
1488 if (!src.isFinite()) {
1489 dst->reset();
1490 return false;
1491 }
1492
1493 SkStrokeRec rec(*this, resScale);
1494
1495 const SkPath* srcPtr = &src;
1496 SkPath tmpPath;
1497
1498 if (fPathEffect && fPathEffect->filterPath(&tmpPath, src, &rec, cullRect)) {
1499 srcPtr = &tmpPath;
1500 }
1501
1502 if (!rec.applyToPath(dst, *srcPtr)) {
1503 if (srcPtr == &tmpPath) {
1504 // If path's were copy-on-write, this trick would not be needed.
1505 // As it is, we want to save making a deep-copy from tmpPath -> dst
1506 // since we know we're just going to delete tmpPath when we return,
1507 // so the swap saves that copy.
1508 dst->swap(tmpPath);
1509 } else {
1510 *dst = *srcPtr;
1511 }
1512 }
1513
1514 if (!dst->isFinite()) {
1515 dst->reset();
1516 return false;
1517 }
1518 return !rec.isHairlineStyle();
1519 }
1520
canComputeFastBounds() const1521 bool SkPaint::canComputeFastBounds() const {
1522 if (this->getLooper()) {
1523 return this->getLooper()->canComputeFastBounds(*this);
1524 }
1525 if (this->getImageFilter() && !this->getImageFilter()->canComputeFastBounds()) {
1526 return false;
1527 }
1528 return true;
1529 }
1530
doComputeFastBounds(const SkRect & origSrc,SkRect * storage,Style style) const1531 const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc,
1532 SkRect* storage,
1533 Style style) const {
1534 SkASSERT(storage);
1535
1536 const SkRect* src = &origSrc;
1537
1538 if (this->getLooper()) {
1539 SkASSERT(this->getLooper()->canComputeFastBounds(*this));
1540 this->getLooper()->computeFastBounds(*this, *src, storage);
1541 return *storage;
1542 }
1543
1544 SkRect tmpSrc;
1545 if (this->getPathEffect()) {
1546 this->getPathEffect()->computeFastBounds(&tmpSrc, origSrc);
1547 src = &tmpSrc;
1548 }
1549
1550 SkScalar radius = SkStrokeRec::GetInflationRadius(*this, style);
1551 *storage = src->makeOutset(radius, radius);
1552
1553 if (this->getMaskFilter()) {
1554 as_MFB(this->getMaskFilter())->computeFastBounds(*storage, storage);
1555 }
1556
1557 if (this->getImageFilter()) {
1558 *storage = this->getImageFilter()->computeFastBounds(*storage);
1559 }
1560
1561 return *storage;
1562 }
1563
1564 #ifndef SK_IGNORE_TO_STRING
1565
toString(SkString * str) const1566 void SkPaint::toString(SkString* str) const {
1567 str->append("<dl><dt>SkPaint:</dt><dd><dl>");
1568
1569 SkTypeface* typeface = this->getTypeface();
1570 if (typeface) {
1571 SkDynamicMemoryWStream ostream;
1572 typeface->serialize(&ostream);
1573 std::unique_ptr<SkStreamAsset> istream(ostream.detachAsStream());
1574
1575 SkFontDescriptor descriptor;
1576 if (!SkFontDescriptor::Deserialize(istream.get(), &descriptor)) {
1577 str->append("<dt>FontDescriptor deserialization failed</dt>");
1578 } else {
1579 str->append("<dt>Font Family Name:</dt><dd>");
1580 str->append(descriptor.getFamilyName());
1581 str->append("</dd><dt>Font Full Name:</dt><dd>");
1582 str->append(descriptor.getFullName());
1583 str->append("</dd><dt>Font PS Name:</dt><dd>");
1584 str->append(descriptor.getPostscriptName());
1585 str->append("</dd>");
1586 }
1587 }
1588
1589 str->append("<dt>TextSize:</dt><dd>");
1590 str->appendScalar(this->getTextSize());
1591 str->append("</dd>");
1592
1593 str->append("<dt>TextScaleX:</dt><dd>");
1594 str->appendScalar(this->getTextScaleX());
1595 str->append("</dd>");
1596
1597 str->append("<dt>TextSkewX:</dt><dd>");
1598 str->appendScalar(this->getTextSkewX());
1599 str->append("</dd>");
1600
1601 SkPathEffect* pathEffect = this->getPathEffect();
1602 if (pathEffect) {
1603 str->append("<dt>PathEffect:</dt><dd>");
1604 pathEffect->toString(str);
1605 str->append("</dd>");
1606 }
1607
1608 if (const auto* shader = as_SB(this->getShader())) {
1609 str->append("<dt>Shader:</dt><dd>");
1610 shader->toString(str);
1611 str->append("</dd>");
1612 }
1613
1614 if (!this->isSrcOver()) {
1615 str->appendf("<dt>Xfermode:</dt><dd>%d</dd>", fBlendMode);
1616 }
1617
1618 SkMaskFilter* maskFilter = this->getMaskFilter();
1619 if (maskFilter) {
1620 str->append("<dt>MaskFilter:</dt><dd>");
1621 as_MFB(maskFilter)->toString(str);
1622 str->append("</dd>");
1623 }
1624
1625 SkColorFilter* colorFilter = this->getColorFilter();
1626 if (colorFilter) {
1627 str->append("<dt>ColorFilter:</dt><dd>");
1628 colorFilter->toString(str);
1629 str->append("</dd>");
1630 }
1631
1632 SkDrawLooper* looper = this->getLooper();
1633 if (looper) {
1634 str->append("<dt>DrawLooper:</dt><dd>");
1635 looper->toString(str);
1636 str->append("</dd>");
1637 }
1638
1639 SkImageFilter* imageFilter = this->getImageFilter();
1640 if (imageFilter) {
1641 str->append("<dt>ImageFilter:</dt><dd>");
1642 imageFilter->toString(str);
1643 str->append("</dd>");
1644 }
1645
1646 str->append("<dt>Color:</dt><dd>0x");
1647 SkColor color = this->getColor();
1648 str->appendHex(color);
1649 str->append("</dd>");
1650
1651 str->append("<dt>Stroke Width:</dt><dd>");
1652 str->appendScalar(this->getStrokeWidth());
1653 str->append("</dd>");
1654
1655 str->append("<dt>Stroke Miter:</dt><dd>");
1656 str->appendScalar(this->getStrokeMiter());
1657 str->append("</dd>");
1658
1659 str->append("<dt>Flags:</dt><dd>(");
1660 if (this->getFlags()) {
1661 bool needSeparator = false;
1662 SkAddFlagToString(str, this->isAntiAlias(), "AntiAlias", &needSeparator);
1663 SkAddFlagToString(str, this->isDither(), "Dither", &needSeparator);
1664 SkAddFlagToString(str, this->isFakeBoldText(), "FakeBoldText", &needSeparator);
1665 SkAddFlagToString(str, this->isLinearText(), "LinearText", &needSeparator);
1666 SkAddFlagToString(str, this->isSubpixelText(), "SubpixelText", &needSeparator);
1667 SkAddFlagToString(str, this->isDevKernText(), "DevKernText", &needSeparator);
1668 SkAddFlagToString(str, this->isLCDRenderText(), "LCDRenderText", &needSeparator);
1669 SkAddFlagToString(str, this->isEmbeddedBitmapText(),
1670 "EmbeddedBitmapText", &needSeparator);
1671 SkAddFlagToString(str, this->isAutohinted(), "Autohinted", &needSeparator);
1672 SkAddFlagToString(str, this->isVerticalText(), "VerticalText", &needSeparator);
1673 SkAddFlagToString(str, SkToBool(this->getFlags() & SkPaint::kGenA8FromLCD_Flag),
1674 "GenA8FromLCD", &needSeparator);
1675 } else {
1676 str->append("None");
1677 }
1678 str->append(")</dd>");
1679
1680 str->append("<dt>FilterLevel:</dt><dd>");
1681 static const char* gFilterQualityStrings[] = { "None", "Low", "Medium", "High" };
1682 str->append(gFilterQualityStrings[this->getFilterQuality()]);
1683 str->append("</dd>");
1684
1685 str->append("<dt>TextAlign:</dt><dd>");
1686 static const char* gTextAlignStrings[SkPaint::kAlignCount] = { "Left", "Center", "Right" };
1687 str->append(gTextAlignStrings[this->getTextAlign()]);
1688 str->append("</dd>");
1689
1690 str->append("<dt>CapType:</dt><dd>");
1691 static const char* gStrokeCapStrings[SkPaint::kCapCount] = { "Butt", "Round", "Square" };
1692 str->append(gStrokeCapStrings[this->getStrokeCap()]);
1693 str->append("</dd>");
1694
1695 str->append("<dt>JoinType:</dt><dd>");
1696 static const char* gJoinStrings[SkPaint::kJoinCount] = { "Miter", "Round", "Bevel" };
1697 str->append(gJoinStrings[this->getStrokeJoin()]);
1698 str->append("</dd>");
1699
1700 str->append("<dt>Style:</dt><dd>");
1701 static const char* gStyleStrings[SkPaint::kStyleCount] = { "Fill", "Stroke", "StrokeAndFill" };
1702 str->append(gStyleStrings[this->getStyle()]);
1703 str->append("</dd>");
1704
1705 str->append("<dt>TextEncoding:</dt><dd>");
1706 static const char* gTextEncodingStrings[] = { "UTF8", "UTF16", "UTF32", "GlyphID" };
1707 str->append(gTextEncodingStrings[this->getTextEncoding()]);
1708 str->append("</dd>");
1709
1710 str->append("<dt>Hinting:</dt><dd>");
1711 static const char* gHintingStrings[] = { "None", "Slight", "Normal", "Full" };
1712 str->append(gHintingStrings[this->getHinting()]);
1713 str->append("</dd>");
1714
1715 str->append("</dd></dl></dl>");
1716 }
1717 #endif
1718
1719 ///////////////////////////////////////////////////////////////////////////////
1720
has_thick_frame(const SkPaint & paint)1721 static bool has_thick_frame(const SkPaint& paint) {
1722 return paint.getStrokeWidth() > 0 &&
1723 paint.getStyle() != SkPaint::kFill_Style;
1724 }
1725
SkTextBaseIter(const char text[],size_t length,const SkPaint & paint,bool applyStrokeAndPathEffects)1726 SkTextBaseIter::SkTextBaseIter(const char text[], size_t length,
1727 const SkPaint& paint,
1728 bool applyStrokeAndPathEffects)
1729 : fPaint(paint) {
1730 fGlyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
1731 paint.isDevKernText(),
1732 true);
1733
1734 fPaint.setLinearText(true);
1735 fPaint.setMaskFilter(nullptr); // don't want this affecting our path-cache lookup
1736
1737 if (fPaint.getPathEffect() == nullptr && !has_thick_frame(fPaint)) {
1738 applyStrokeAndPathEffects = false;
1739 }
1740
1741 // can't use our canonical size if we need to apply patheffects
1742 if (fPaint.getPathEffect() == nullptr) {
1743 fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
1744 fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
1745 if (has_thick_frame(fPaint)) {
1746 fPaint.setStrokeWidth(fPaint.getStrokeWidth() / fScale);
1747 }
1748 } else {
1749 fScale = SK_Scalar1;
1750 }
1751
1752 if (!applyStrokeAndPathEffects) {
1753 fPaint.setStyle(SkPaint::kFill_Style);
1754 fPaint.setPathEffect(nullptr);
1755 }
1756
1757 // SRGBTODO: Is this correct?
1758 fCache = SkGlyphCache::DetachCacheUsingPaint(fPaint, nullptr,
1759 SkScalerContextFlags::kFakeGammaAndBoostContrast,
1760 nullptr);
1761
1762 SkPaint::Style style = SkPaint::kFill_Style;
1763 sk_sp<SkPathEffect> pe;
1764
1765 if (!applyStrokeAndPathEffects) {
1766 style = paint.getStyle(); // restore
1767 pe = paint.refPathEffect(); // restore
1768 }
1769 fPaint.setStyle(style);
1770 fPaint.setPathEffect(pe);
1771 fPaint.setMaskFilter(paint.refMaskFilter()); // restore
1772
1773 // now compute fXOffset if needed
1774
1775 SkScalar xOffset = 0;
1776 if (paint.getTextAlign() != SkPaint::kLeft_Align) { // need to measure first
1777 int count;
1778 SkScalar width = fPaint.measure_text(fCache, text, length, &count, nullptr) * fScale;
1779 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1780 width = SkScalarHalf(width);
1781 }
1782 xOffset = -width;
1783 }
1784 fXPos = xOffset;
1785 fPrevAdvance = 0;
1786
1787 fText = text;
1788 fStop = text + length;
1789
1790 fXYIndex = paint.isVerticalText() ? 1 : 0;
1791 }
1792
~SkTextBaseIter()1793 SkTextBaseIter::~SkTextBaseIter() {
1794 SkGlyphCache::AttachCache(fCache);
1795 }
1796
next(const SkPath ** path,SkScalar * xpos)1797 bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) {
1798 if (fText < fStop) {
1799 const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText);
1800
1801 fXPos += (fPrevAdvance + fAutoKern.adjust(glyph)) * fScale;
1802 fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking();
1803
1804 if (glyph.fWidth) {
1805 if (path) {
1806 *path = fCache->findPath(glyph);
1807 }
1808 } else {
1809 if (path) {
1810 *path = nullptr;
1811 }
1812 }
1813 if (xpos) {
1814 *xpos = fXPos;
1815 }
1816 return true;
1817 }
1818 return false;
1819 }
1820
next(SkScalar * array,int * count)1821 bool SkTextInterceptsIter::next(SkScalar* array, int* count) {
1822 const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText);
1823 fXPos += (fPrevAdvance + fAutoKern.adjust(glyph)) * fScale;
1824 fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking();
1825 if (fCache->findPath(glyph)) {
1826 fCache->findIntercepts(fBounds, fScale, fXPos, SkToBool(fXYIndex),
1827 const_cast<SkGlyph*>(&glyph), array, count);
1828 }
1829 return fText < fStop;
1830 }
1831
1832 ///////////////////////////////////////////////////////////////////////////////
1833
1834 // return true if the filter exists, and may affect alpha
affects_alpha(const SkColorFilter * cf)1835 static bool affects_alpha(const SkColorFilter* cf) {
1836 return cf && !(cf->getFlags() & SkColorFilter::kAlphaUnchanged_Flag);
1837 }
1838
1839 // return true if the filter exists, and may affect alpha
affects_alpha(const SkImageFilter * imf)1840 static bool affects_alpha(const SkImageFilter* imf) {
1841 // TODO: check if we should allow imagefilters to broadcast that they don't affect alpha
1842 // ala colorfilters
1843 return imf != nullptr;
1844 }
1845
nothingToDraw() const1846 bool SkPaint::nothingToDraw() const {
1847 if (fDrawLooper) {
1848 return false;
1849 }
1850 switch ((SkBlendMode)fBlendMode) {
1851 case SkBlendMode::kSrcOver:
1852 case SkBlendMode::kSrcATop:
1853 case SkBlendMode::kDstOut:
1854 case SkBlendMode::kDstOver:
1855 case SkBlendMode::kPlus:
1856 if (0 == this->getAlpha()) {
1857 return !affects_alpha(fColorFilter.get()) && !affects_alpha(fImageFilter.get());
1858 }
1859 break;
1860 case SkBlendMode::kDst:
1861 return true;
1862 default:
1863 break;
1864 }
1865 return false;
1866 }
1867
getHash() const1868 uint32_t SkPaint::getHash() const {
1869 // We're going to hash 7 pointers and 7 32-bit values, finishing up with fBitfields,
1870 // so fBitfields should be 7 pointers and 6 32-bit values from the start.
1871 static_assert(offsetof(SkPaint, fBitfields) == 7 * sizeof(void*) + 7 * sizeof(uint32_t),
1872 "SkPaint_notPackedTightly");
1873 return SkOpts::hash(reinterpret_cast<const uint32_t*>(this),
1874 offsetof(SkPaint, fBitfields) + sizeof(fBitfields));
1875 }
1876