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 "SkRasterizer.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(fRasterizer)
78 , COPY(fDrawLooper)
79 , COPY(fImageFilter)
80 , COPY(fTextSize)
81 , COPY(fTextScaleX)
82 , COPY(fTextSkewX)
83 , COPY(fColor)
84 , COPY(fWidth)
85 , COPY(fMiterLimit)
86 , COPY(fBlendMode)
87 , COPY(fBitfields)
88 #undef COPY
89 {}
90
SkPaint(SkPaint && src)91 SkPaint::SkPaint(SkPaint&& src) {
92 #define MOVE(field) field = std::move(src.field)
93 MOVE(fTypeface);
94 MOVE(fPathEffect);
95 MOVE(fShader);
96 MOVE(fMaskFilter);
97 MOVE(fColorFilter);
98 MOVE(fRasterizer);
99 MOVE(fDrawLooper);
100 MOVE(fImageFilter);
101 MOVE(fTextSize);
102 MOVE(fTextScaleX);
103 MOVE(fTextSkewX);
104 MOVE(fColor);
105 MOVE(fWidth);
106 MOVE(fMiterLimit);
107 MOVE(fBlendMode);
108 MOVE(fBitfields);
109 #undef MOVE
110 }
111
~SkPaint()112 SkPaint::~SkPaint() {}
113
operator =(const SkPaint & src)114 SkPaint& SkPaint::operator=(const SkPaint& src) {
115 if (this == &src) {
116 return *this;
117 }
118
119 #define ASSIGN(field) field = src.field
120 ASSIGN(fTypeface);
121 ASSIGN(fPathEffect);
122 ASSIGN(fShader);
123 ASSIGN(fMaskFilter);
124 ASSIGN(fColorFilter);
125 ASSIGN(fRasterizer);
126 ASSIGN(fDrawLooper);
127 ASSIGN(fImageFilter);
128 ASSIGN(fTextSize);
129 ASSIGN(fTextScaleX);
130 ASSIGN(fTextSkewX);
131 ASSIGN(fColor);
132 ASSIGN(fWidth);
133 ASSIGN(fMiterLimit);
134 ASSIGN(fBlendMode);
135 ASSIGN(fBitfields);
136 #undef ASSIGN
137
138 return *this;
139 }
140
operator =(SkPaint && src)141 SkPaint& SkPaint::operator=(SkPaint&& src) {
142 if (this == &src) {
143 return *this;
144 }
145
146 #define MOVE(field) field = std::move(src.field)
147 MOVE(fTypeface);
148 MOVE(fPathEffect);
149 MOVE(fShader);
150 MOVE(fMaskFilter);
151 MOVE(fColorFilter);
152 MOVE(fRasterizer);
153 MOVE(fDrawLooper);
154 MOVE(fImageFilter);
155 MOVE(fTextSize);
156 MOVE(fTextScaleX);
157 MOVE(fTextSkewX);
158 MOVE(fColor);
159 MOVE(fWidth);
160 MOVE(fMiterLimit);
161 MOVE(fBlendMode);
162 MOVE(fBitfields);
163 #undef MOVE
164
165 return *this;
166 }
167
operator ==(const SkPaint & a,const SkPaint & b)168 bool operator==(const SkPaint& a, const SkPaint& b) {
169 #define EQUAL(field) (a.field == b.field)
170 return EQUAL(fTypeface)
171 && EQUAL(fPathEffect)
172 && EQUAL(fShader)
173 && EQUAL(fMaskFilter)
174 && EQUAL(fColorFilter)
175 && EQUAL(fRasterizer)
176 && EQUAL(fDrawLooper)
177 && EQUAL(fImageFilter)
178 && EQUAL(fTextSize)
179 && EQUAL(fTextScaleX)
180 && EQUAL(fTextSkewX)
181 && EQUAL(fColor)
182 && EQUAL(fWidth)
183 && EQUAL(fMiterLimit)
184 && EQUAL(fBlendMode)
185 && EQUAL(fBitfieldsUInt)
186 ;
187 #undef EQUAL
188 }
189
190 #define DEFINE_REF_FOO(type) sk_sp<Sk##type> SkPaint::ref##type() const { return f##type; }
191 DEFINE_REF_FOO(ColorFilter)
DEFINE_REF_FOO(DrawLooper)192 DEFINE_REF_FOO(DrawLooper)
193 DEFINE_REF_FOO(ImageFilter)
194 DEFINE_REF_FOO(MaskFilter)
195 DEFINE_REF_FOO(PathEffect)
196 DEFINE_REF_FOO(Rasterizer)
197 DEFINE_REF_FOO(Shader)
198 DEFINE_REF_FOO(Typeface)
199 #undef DEFINE_REF_FOO
200
201 void SkPaint::reset() {
202 SkPaint init;
203 *this = init;
204 }
205
setFilterQuality(SkFilterQuality quality)206 void SkPaint::setFilterQuality(SkFilterQuality quality) {
207 fBitfields.fFilterQuality = quality;
208 }
209
setHinting(Hinting hintingLevel)210 void SkPaint::setHinting(Hinting hintingLevel) {
211 fBitfields.fHinting = hintingLevel;
212 }
213
setFlags(uint32_t flags)214 void SkPaint::setFlags(uint32_t flags) {
215 fBitfields.fFlags = flags;
216 }
217
setAntiAlias(bool doAA)218 void SkPaint::setAntiAlias(bool doAA) {
219 this->setFlags(set_clear_mask(fBitfields.fFlags, doAA, kAntiAlias_Flag));
220 }
221
setDither(bool doDither)222 void SkPaint::setDither(bool doDither) {
223 this->setFlags(set_clear_mask(fBitfields.fFlags, doDither, kDither_Flag));
224 }
225
setSubpixelText(bool doSubpixel)226 void SkPaint::setSubpixelText(bool doSubpixel) {
227 this->setFlags(set_clear_mask(fBitfields.fFlags, doSubpixel, kSubpixelText_Flag));
228 }
229
setLCDRenderText(bool doLCDRender)230 void SkPaint::setLCDRenderText(bool doLCDRender) {
231 this->setFlags(set_clear_mask(fBitfields.fFlags, doLCDRender, kLCDRenderText_Flag));
232 }
233
setEmbeddedBitmapText(bool doEmbeddedBitmapText)234 void SkPaint::setEmbeddedBitmapText(bool doEmbeddedBitmapText) {
235 this->setFlags(set_clear_mask(fBitfields.fFlags, doEmbeddedBitmapText, kEmbeddedBitmapText_Flag));
236 }
237
setAutohinted(bool useAutohinter)238 void SkPaint::setAutohinted(bool useAutohinter) {
239 this->setFlags(set_clear_mask(fBitfields.fFlags, useAutohinter, kAutoHinting_Flag));
240 }
241
setLinearText(bool doLinearText)242 void SkPaint::setLinearText(bool doLinearText) {
243 this->setFlags(set_clear_mask(fBitfields.fFlags, doLinearText, kLinearText_Flag));
244 }
245
setVerticalText(bool doVertical)246 void SkPaint::setVerticalText(bool doVertical) {
247 this->setFlags(set_clear_mask(fBitfields.fFlags, doVertical, kVerticalText_Flag));
248 }
249
setFakeBoldText(bool doFakeBold)250 void SkPaint::setFakeBoldText(bool doFakeBold) {
251 this->setFlags(set_clear_mask(fBitfields.fFlags, doFakeBold, kFakeBoldText_Flag));
252 }
253
setDevKernText(bool doDevKern)254 void SkPaint::setDevKernText(bool doDevKern) {
255 this->setFlags(set_clear_mask(fBitfields.fFlags, doDevKern, kDevKernText_Flag));
256 }
257
setStyle(Style style)258 void SkPaint::setStyle(Style style) {
259 if ((unsigned)style < kStyleCount) {
260 fBitfields.fStyle = style;
261 } else {
262 #ifdef SK_REPORT_API_RANGE_CHECK
263 SkDebugf("SkPaint::setStyle(%d) out of range\n", style);
264 #endif
265 }
266 }
267
setColor(SkColor color)268 void SkPaint::setColor(SkColor color) {
269 fColor = color;
270 }
271
setAlpha(U8CPU a)272 void SkPaint::setAlpha(U8CPU a) {
273 this->setColor(SkColorSetARGB(a, SkColorGetR(fColor),
274 SkColorGetG(fColor), SkColorGetB(fColor)));
275 }
276
setARGB(U8CPU a,U8CPU r,U8CPU g,U8CPU b)277 void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
278 this->setColor(SkColorSetARGB(a, r, g, b));
279 }
280
setStrokeWidth(SkScalar width)281 void SkPaint::setStrokeWidth(SkScalar width) {
282 if (width >= 0) {
283 fWidth = width;
284 } else {
285 #ifdef SK_REPORT_API_RANGE_CHECK
286 SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");
287 #endif
288 }
289 }
290
setStrokeMiter(SkScalar limit)291 void SkPaint::setStrokeMiter(SkScalar limit) {
292 if (limit >= 0) {
293 fMiterLimit = limit;
294 } else {
295 #ifdef SK_REPORT_API_RANGE_CHECK
296 SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");
297 #endif
298 }
299 }
300
setStrokeCap(Cap ct)301 void SkPaint::setStrokeCap(Cap ct) {
302 if ((unsigned)ct < kCapCount) {
303 fBitfields.fCapType = SkToU8(ct);
304 } else {
305 #ifdef SK_REPORT_API_RANGE_CHECK
306 SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);
307 #endif
308 }
309 }
310
setStrokeJoin(Join jt)311 void SkPaint::setStrokeJoin(Join jt) {
312 if ((unsigned)jt < kJoinCount) {
313 fBitfields.fJoinType = SkToU8(jt);
314 } else {
315 #ifdef SK_REPORT_API_RANGE_CHECK
316 SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);
317 #endif
318 }
319 }
320
321 ///////////////////////////////////////////////////////////////////////////////
322
setTextAlign(Align align)323 void SkPaint::setTextAlign(Align align) {
324 if ((unsigned)align < kAlignCount) {
325 fBitfields.fTextAlign = SkToU8(align);
326 } else {
327 #ifdef SK_REPORT_API_RANGE_CHECK
328 SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align);
329 #endif
330 }
331 }
332
setTextSize(SkScalar ts)333 void SkPaint::setTextSize(SkScalar ts) {
334 if (ts >= 0) {
335 fTextSize = ts;
336 } else {
337 #ifdef SK_REPORT_API_RANGE_CHECK
338 SkDebugf("SkPaint::setTextSize() called with negative value\n");
339 #endif
340 }
341 }
342
setTextScaleX(SkScalar scaleX)343 void SkPaint::setTextScaleX(SkScalar scaleX) {
344 fTextScaleX = scaleX;
345 }
346
setTextSkewX(SkScalar skewX)347 void SkPaint::setTextSkewX(SkScalar skewX) {
348 fTextSkewX = skewX;
349 }
350
setTextEncoding(TextEncoding encoding)351 void SkPaint::setTextEncoding(TextEncoding encoding) {
352 if ((unsigned)encoding <= kGlyphID_TextEncoding) {
353 fBitfields.fTextEncoding = encoding;
354 } else {
355 #ifdef SK_REPORT_API_RANGE_CHECK
356 SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding);
357 #endif
358 }
359 }
360
361 ///////////////////////////////////////////////////////////////////////////////
362
363 #define MOVE_FIELD(Field) void SkPaint::set##Field(sk_sp<Sk##Field> f) { f##Field = std::move(f); }
364 MOVE_FIELD(Typeface)
MOVE_FIELD(Rasterizer)365 MOVE_FIELD(Rasterizer)
366 MOVE_FIELD(ImageFilter)
367 MOVE_FIELD(Shader)
368 MOVE_FIELD(ColorFilter)
369 MOVE_FIELD(PathEffect)
370 MOVE_FIELD(MaskFilter)
371 MOVE_FIELD(DrawLooper)
372 #undef MOVE_FIELD
373 void SkPaint::setLooper(sk_sp<SkDrawLooper> looper) { fDrawLooper = std::move(looper); }
374
375 ///////////////////////////////////////////////////////////////////////////////
376
mag2(SkScalar x,SkScalar y)377 static SkScalar mag2(SkScalar x, SkScalar y) {
378 return x * x + y * y;
379 }
380
tooBig(const SkMatrix & m,SkScalar ma2max)381 static bool tooBig(const SkMatrix& m, SkScalar ma2max) {
382 return mag2(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewY]) > ma2max
383 ||
384 mag2(m[SkMatrix::kMSkewX], m[SkMatrix::kMScaleY]) > ma2max;
385 }
386
TooBigToUseCache(const SkMatrix & ctm,const SkMatrix & textM)387 bool SkPaint::TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM) {
388 SkASSERT(!ctm.hasPerspective());
389 SkASSERT(!textM.hasPerspective());
390
391 SkMatrix matrix;
392 matrix.setConcat(ctm, textM);
393 return tooBig(matrix, MaxCacheSize2());
394 }
395
MaxCacheSize2()396 SkScalar SkPaint::MaxCacheSize2() {
397 // we have a self-imposed maximum, just for memory-usage sanity
398 const int limit = SkMin32(SkGraphics::GetFontCachePointSizeLimit(), 1024);
399 const SkScalar maxSize = SkIntToScalar(limit);
400 return maxSize * maxSize;
401 }
402
403 ///////////////////////////////////////////////////////////////////////////////
404
405 #include "SkGlyphCache.h"
406 #include "SkUtils.h"
407
DetachDescProc(SkTypeface * typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc,void * context)408 static void DetachDescProc(SkTypeface* typeface, const SkScalerContextEffects& effects,
409 const SkDescriptor* desc, void* context) {
410 *((SkGlyphCache**)context) = SkGlyphCache::DetachCache(typeface, effects, desc);
411 }
412
textToGlyphs(const void * textData,size_t byteLength,uint16_t glyphs[]) const413 int SkPaint::textToGlyphs(const void* textData, size_t byteLength, uint16_t glyphs[]) const {
414 if (byteLength == 0) {
415 return 0;
416 }
417
418 SkASSERT(textData != nullptr);
419
420 if (nullptr == glyphs) {
421 switch (this->getTextEncoding()) {
422 case kUTF8_TextEncoding:
423 return SkUTF8_CountUnichars((const char*)textData, byteLength);
424 case kUTF16_TextEncoding:
425 return SkUTF16_CountUnichars((const uint16_t*)textData, SkToInt(byteLength >> 1));
426 case kUTF32_TextEncoding:
427 return SkToInt(byteLength >> 2);
428 case kGlyphID_TextEncoding:
429 return SkToInt(byteLength >> 1);
430 default:
431 SkDEBUGFAIL("unknown text encoding");
432 }
433 return 0;
434 }
435
436 // if we get here, we have a valid glyphs[] array, so time to fill it in
437
438 // handle this encoding before the setup for the glyphcache
439 if (this->getTextEncoding() == kGlyphID_TextEncoding) {
440 // we want to ignore the low bit of byteLength
441 memcpy(glyphs, textData, byteLength >> 1 << 1);
442 return SkToInt(byteLength >> 1);
443 }
444
445 SkAutoGlyphCache autoCache(*this, nullptr, nullptr);
446 SkGlyphCache* cache = autoCache.getCache();
447
448 const char* text = (const char*)textData;
449 const char* stop = text + byteLength;
450 uint16_t* gptr = glyphs;
451
452 switch (this->getTextEncoding()) {
453 case SkPaint::kUTF8_TextEncoding:
454 while (text < stop) {
455 SkUnichar u = SkUTF8_NextUnicharWithError(&text, stop);
456 if (u < 0) {
457 return 0; // bad UTF-8 sequence
458 }
459 *gptr++ = cache->unicharToGlyph(u);
460 }
461 break;
462 case SkPaint::kUTF16_TextEncoding: {
463 const uint16_t* text16 = (const uint16_t*)text;
464 const uint16_t* stop16 = (const uint16_t*)stop;
465 while (text16 < stop16) {
466 *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16));
467 }
468 break;
469 }
470 case kUTF32_TextEncoding: {
471 const int32_t* text32 = (const int32_t*)text;
472 const int32_t* stop32 = (const int32_t*)stop;
473 while (text32 < stop32) {
474 *gptr++ = cache->unicharToGlyph(*text32++);
475 }
476 break;
477 }
478 default:
479 SkDEBUGFAIL("unknown text encoding");
480 }
481 return SkToInt(gptr - glyphs);
482 }
483
containsText(const void * textData,size_t byteLength) const484 bool SkPaint::containsText(const void* textData, size_t byteLength) const {
485 if (0 == byteLength) {
486 return true;
487 }
488
489 SkASSERT(textData != nullptr);
490
491 // handle this encoding before the setup for the glyphcache
492 if (this->getTextEncoding() == kGlyphID_TextEncoding) {
493 const uint16_t* glyphID = static_cast<const uint16_t*>(textData);
494 size_t count = byteLength >> 1;
495 for (size_t i = 0; i < count; i++) {
496 if (0 == glyphID[i]) {
497 return false;
498 }
499 }
500 return true;
501 }
502
503 SkAutoGlyphCache autoCache(*this, nullptr, nullptr);
504 SkGlyphCache* cache = autoCache.getCache();
505
506 switch (this->getTextEncoding()) {
507 case SkPaint::kUTF8_TextEncoding: {
508 const char* text = static_cast<const char*>(textData);
509 const char* stop = text + byteLength;
510 while (text < stop) {
511 if (0 == cache->unicharToGlyph(SkUTF8_NextUnichar(&text))) {
512 return false;
513 }
514 }
515 break;
516 }
517 case SkPaint::kUTF16_TextEncoding: {
518 const uint16_t* text = static_cast<const uint16_t*>(textData);
519 const uint16_t* stop = text + (byteLength >> 1);
520 while (text < stop) {
521 if (0 == cache->unicharToGlyph(SkUTF16_NextUnichar(&text))) {
522 return false;
523 }
524 }
525 break;
526 }
527 case SkPaint::kUTF32_TextEncoding: {
528 const int32_t* text = static_cast<const int32_t*>(textData);
529 const int32_t* stop = text + (byteLength >> 2);
530 while (text < stop) {
531 if (0 == cache->unicharToGlyph(*text++)) {
532 return false;
533 }
534 }
535 break;
536 }
537 default:
538 SkDEBUGFAIL("unknown text encoding");
539 return false;
540 }
541 return true;
542 }
543
glyphsToUnichars(const uint16_t glyphs[],int count,SkUnichar textData[]) const544 void SkPaint::glyphsToUnichars(const uint16_t glyphs[], int count, SkUnichar textData[]) const {
545 if (count <= 0) {
546 return;
547 }
548
549 SkASSERT(glyphs != nullptr);
550 SkASSERT(textData != nullptr);
551
552 SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
553 SkAutoGlyphCache autoCache(*this, &props, nullptr);
554 SkGlyphCache* cache = autoCache.getCache();
555
556 for (int index = 0; index < count; index++) {
557 textData[index] = cache->glyphToUnichar(glyphs[index]);
558 }
559 }
560
561 ///////////////////////////////////////////////////////////////////////////////
562
sk_getMetrics_utf8_next(SkGlyphCache * cache,const char ** text)563 static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache,
564 const char** text) {
565 SkASSERT(cache != nullptr);
566 SkASSERT(text != nullptr);
567
568 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text));
569 }
570
sk_getMetrics_utf16_next(SkGlyphCache * cache,const char ** text)571 static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache,
572 const char** text) {
573 SkASSERT(cache != nullptr);
574 SkASSERT(text != nullptr);
575
576 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text));
577 }
578
sk_getMetrics_utf32_next(SkGlyphCache * cache,const char ** text)579 static const SkGlyph& sk_getMetrics_utf32_next(SkGlyphCache* cache,
580 const char** text) {
581 SkASSERT(cache != nullptr);
582 SkASSERT(text != nullptr);
583
584 const int32_t* ptr = *(const int32_t**)text;
585 SkUnichar uni = *ptr++;
586 *text = (const char*)ptr;
587 return cache->getUnicharMetrics(uni);
588 }
589
sk_getMetrics_glyph_next(SkGlyphCache * cache,const char ** text)590 static const SkGlyph& sk_getMetrics_glyph_next(SkGlyphCache* cache,
591 const char** text) {
592 SkASSERT(cache != nullptr);
593 SkASSERT(text != nullptr);
594
595 const uint16_t* ptr = *(const uint16_t**)text;
596 unsigned glyphID = *ptr;
597 ptr += 1;
598 *text = (const char*)ptr;
599 return cache->getGlyphIDMetrics(glyphID);
600 }
601
sk_getAdvance_utf8_next(SkGlyphCache * cache,const char ** text)602 static const SkGlyph& sk_getAdvance_utf8_next(SkGlyphCache* cache,
603 const char** text) {
604 SkASSERT(cache != nullptr);
605 SkASSERT(text != nullptr);
606
607 return cache->getUnicharAdvance(SkUTF8_NextUnichar(text));
608 }
609
sk_getAdvance_utf16_next(SkGlyphCache * cache,const char ** text)610 static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache,
611 const char** text) {
612 SkASSERT(cache != nullptr);
613 SkASSERT(text != nullptr);
614
615 return cache->getUnicharAdvance(SkUTF16_NextUnichar((const uint16_t**)text));
616 }
617
sk_getAdvance_utf32_next(SkGlyphCache * cache,const char ** text)618 static const SkGlyph& sk_getAdvance_utf32_next(SkGlyphCache* cache,
619 const char** text) {
620 SkASSERT(cache != nullptr);
621 SkASSERT(text != nullptr);
622
623 const int32_t* ptr = *(const int32_t**)text;
624 SkUnichar uni = *ptr++;
625 *text = (const char*)ptr;
626 return cache->getUnicharAdvance(uni);
627 }
628
sk_getAdvance_glyph_next(SkGlyphCache * cache,const char ** text)629 static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache,
630 const char** text) {
631 SkASSERT(cache != nullptr);
632 SkASSERT(text != nullptr);
633
634 const uint16_t* ptr = *(const uint16_t**)text;
635 unsigned glyphID = *ptr;
636 ptr += 1;
637 *text = (const char*)ptr;
638 return cache->getGlyphIDAdvance(glyphID);
639 }
640
GetGlyphCacheProc(TextEncoding encoding,bool isDevKern,bool needFullMetrics)641 SkPaint::GlyphCacheProc SkPaint::GetGlyphCacheProc(TextEncoding encoding,
642 bool isDevKern,
643 bool needFullMetrics) {
644 static const GlyphCacheProc gGlyphCacheProcs[] = {
645 sk_getMetrics_utf8_next,
646 sk_getMetrics_utf16_next,
647 sk_getMetrics_utf32_next,
648 sk_getMetrics_glyph_next,
649
650 sk_getAdvance_utf8_next,
651 sk_getAdvance_utf16_next,
652 sk_getAdvance_utf32_next,
653 sk_getAdvance_glyph_next,
654 };
655
656 unsigned index = encoding;
657
658 if (!needFullMetrics && !isDevKern) {
659 index += 4;
660 }
661
662 SkASSERT(index < SK_ARRAY_COUNT(gGlyphCacheProcs));
663 return gGlyphCacheProcs[index];
664 }
665
666 ///////////////////////////////////////////////////////////////////////////////
667
668 #define TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE ( \
669 SkPaint::kDevKernText_Flag | \
670 SkPaint::kLinearText_Flag | \
671 SkPaint::kLCDRenderText_Flag | \
672 SkPaint::kEmbeddedBitmapText_Flag | \
673 SkPaint::kAutoHinting_Flag | \
674 SkPaint::kGenA8FromLCD_Flag )
675
setupForAsPaths()676 SkScalar SkPaint::setupForAsPaths() {
677 uint32_t flags = this->getFlags();
678 // clear the flags we don't care about
679 flags &= ~TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE;
680 // set the flags we do care about
681 flags |= SkPaint::kSubpixelText_Flag;
682
683 this->setFlags(flags);
684 this->setHinting(SkPaint::kNo_Hinting);
685
686 SkScalar textSize = fTextSize;
687 this->setTextSize(kCanonicalTextSizeForPaths);
688 return textSize / kCanonicalTextSizeForPaths;
689 }
690
691 class SkCanonicalizePaint {
692 public:
SkCanonicalizePaint(const SkPaint & paint)693 SkCanonicalizePaint(const SkPaint& paint) : fPaint(&paint), fScale(0) {
694 if (paint.isLinearText() || SkDraw::ShouldDrawTextAsPaths(paint, SkMatrix::I())) {
695 SkPaint* p = fLazy.set(paint);
696 fScale = p->setupForAsPaths();
697 fPaint = p;
698 }
699 }
700
getPaint() const701 const SkPaint& getPaint() const { return *fPaint; }
702
703 /**
704 * Returns 0 if the paint was unmodified, or the scale factor need to
705 * the original textSize
706 */
getScale() const707 SkScalar getScale() const { return fScale; }
708
709 private:
710 const SkPaint* fPaint;
711 SkScalar fScale;
712 SkTLazy<SkPaint> fLazy;
713 };
714
set_bounds(const SkGlyph & g,SkRect * bounds)715 static void set_bounds(const SkGlyph& g, SkRect* bounds) {
716 bounds->set(SkIntToScalar(g.fLeft),
717 SkIntToScalar(g.fTop),
718 SkIntToScalar(g.fLeft + g.fWidth),
719 SkIntToScalar(g.fTop + g.fHeight));
720 }
721
join_bounds_x(const SkGlyph & g,SkRect * bounds,SkScalar dx)722 static void join_bounds_x(const SkGlyph& g, SkRect* bounds, SkScalar dx) {
723 bounds->join(SkIntToScalar(g.fLeft) + dx,
724 SkIntToScalar(g.fTop),
725 SkIntToScalar(g.fLeft + g.fWidth) + dx,
726 SkIntToScalar(g.fTop + g.fHeight));
727 }
728
join_bounds_y(const SkGlyph & g,SkRect * bounds,SkScalar dy)729 static void join_bounds_y(const SkGlyph& g, SkRect* bounds, SkScalar dy) {
730 bounds->join(SkIntToScalar(g.fLeft),
731 SkIntToScalar(g.fTop) + dy,
732 SkIntToScalar(g.fLeft + g.fWidth),
733 SkIntToScalar(g.fTop + g.fHeight) + dy);
734 }
735
736 typedef void (*JoinBoundsProc)(const SkGlyph&, SkRect*, SkScalar);
737
738 // xyIndex is 0 for fAdvanceX or 1 for fAdvanceY
advance(const SkGlyph & glyph,int xyIndex)739 static SkScalar advance(const SkGlyph& glyph, int xyIndex) {
740 SkASSERT(0 == xyIndex || 1 == xyIndex);
741 return SkFloatToScalar((&glyph.fAdvanceX)[xyIndex]);
742 }
743
measure_text(SkGlyphCache * cache,const char * text,size_t byteLength,int * count,SkRect * bounds) const744 SkScalar SkPaint::measure_text(SkGlyphCache* cache,
745 const char* text, size_t byteLength,
746 int* count, SkRect* bounds) const {
747 SkASSERT(count);
748 if (byteLength == 0) {
749 *count = 0;
750 if (bounds) {
751 bounds->setEmpty();
752 }
753 return 0;
754 }
755
756 GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(this->getTextEncoding(),
757 this->isDevKernText(),
758 nullptr != bounds);
759
760 int xyIndex;
761 JoinBoundsProc joinBoundsProc;
762 if (this->isVerticalText()) {
763 xyIndex = 1;
764 joinBoundsProc = join_bounds_y;
765 } else {
766 xyIndex = 0;
767 joinBoundsProc = join_bounds_x;
768 }
769
770 int n = 1;
771 const char* stop = (const char*)text + byteLength;
772 const SkGlyph* g = &glyphCacheProc(cache, &text);
773 SkScalar x = advance(*g, xyIndex);
774
775 if (nullptr == bounds) {
776 if (this->isDevKernText()) {
777 for (; text < stop; n++) {
778 const int rsb = g->fRsbDelta;
779 g = &glyphCacheProc(cache, &text);
780 x += SkAutoKern_Adjust(rsb, g->fLsbDelta) + advance(*g, xyIndex);
781 }
782 } else {
783 for (; text < stop; n++) {
784 x += advance(glyphCacheProc(cache, &text), xyIndex);
785 }
786 }
787 } else {
788 set_bounds(*g, bounds);
789 if (this->isDevKernText()) {
790 for (; text < stop; n++) {
791 const int rsb = g->fRsbDelta;
792 g = &glyphCacheProc(cache, &text);
793 x += SkAutoKern_Adjust(rsb, g->fLsbDelta);
794 joinBoundsProc(*g, bounds, x);
795 x += advance(*g, xyIndex);
796 }
797 } else {
798 for (; text < stop; n++) {
799 g = &glyphCacheProc(cache, &text);
800 joinBoundsProc(*g, bounds, x);
801 x += advance(*g, xyIndex);
802 }
803 }
804 }
805 SkASSERT(text == stop);
806
807 *count = n;
808 return x;
809 }
810
measureText(const void * textData,size_t length,SkRect * bounds) const811 SkScalar SkPaint::measureText(const void* textData, size_t length, SkRect* bounds) const {
812 const char* text = (const char*)textData;
813 SkASSERT(text != nullptr || length == 0);
814
815 SkCanonicalizePaint canon(*this);
816 const SkPaint& paint = canon.getPaint();
817 SkScalar scale = canon.getScale();
818
819 SkAutoGlyphCache autoCache(paint, nullptr, nullptr);
820 SkGlyphCache* cache = autoCache.getCache();
821
822 SkScalar width = 0;
823
824 if (length > 0) {
825 int tempCount;
826
827 width = paint.measure_text(cache, text, length, &tempCount, bounds);
828 if (scale) {
829 width *= scale;
830 if (bounds) {
831 bounds->fLeft *= scale;
832 bounds->fTop *= scale;
833 bounds->fRight *= scale;
834 bounds->fBottom *= scale;
835 }
836 }
837 } else if (bounds) {
838 // ensure that even if we don't measure_text we still update the bounds
839 bounds->setEmpty();
840 }
841 return width;
842 }
843
breakText(const void * textD,size_t length,SkScalar maxWidth,SkScalar * measuredWidth) const844 size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
845 SkScalar* measuredWidth) const {
846 if (0 == length || 0 >= maxWidth) {
847 if (measuredWidth) {
848 *measuredWidth = 0;
849 }
850 return 0;
851 }
852
853 if (0 == fTextSize) {
854 if (measuredWidth) {
855 *measuredWidth = 0;
856 }
857 return length;
858 }
859
860 SkASSERT(textD != nullptr);
861 const char* text = (const char*)textD;
862 const char* stop = text + length;
863
864 SkCanonicalizePaint canon(*this);
865 const SkPaint& paint = canon.getPaint();
866 SkScalar scale = canon.getScale();
867
868 // adjust max in case we changed the textSize in paint
869 if (scale) {
870 maxWidth /= scale;
871 }
872
873 SkAutoGlyphCache autoCache(paint, nullptr, nullptr);
874 SkGlyphCache* cache = autoCache.getCache();
875
876 GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
877 paint.isDevKernText(),
878 false);
879 const int xyIndex = paint.isVerticalText() ? 1 : 0;
880 SkScalar width = 0;
881
882 if (this->isDevKernText()) {
883 int rsb = 0;
884 while (text < stop) {
885 const char* curr = text;
886 const SkGlyph& g = glyphCacheProc(cache, &text);
887 SkScalar x = SkAutoKern_Adjust(rsb, g.fLsbDelta) + advance(g, xyIndex);
888 if ((width += x) > maxWidth) {
889 width -= x;
890 text = curr;
891 break;
892 }
893 rsb = g.fRsbDelta;
894 }
895 } else {
896 while (text < stop) {
897 const char* curr = text;
898 SkScalar x = advance(glyphCacheProc(cache, &text), xyIndex);
899 if ((width += x) > maxWidth) {
900 width -= x;
901 text = curr;
902 break;
903 }
904 }
905 }
906
907 if (measuredWidth) {
908 if (scale) {
909 width *= scale;
910 }
911 *measuredWidth = width;
912 }
913
914 // return the number of bytes measured
915 return text - stop + length;
916 }
917
918 ///////////////////////////////////////////////////////////////////////////////
919
FontMetricsCacheProc(const SkGlyphCache * cache,void * context)920 static bool FontMetricsCacheProc(const SkGlyphCache* cache, void* context) {
921 *(SkPaint::FontMetrics*)context = cache->getFontMetrics();
922 return false; // don't detach the cache
923 }
924
FontMetricsDescProc(SkTypeface * typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc,void * context)925 static void FontMetricsDescProc(SkTypeface* typeface, const SkScalerContextEffects& effects,
926 const SkDescriptor* desc, void* context) {
927 SkGlyphCache::VisitCache(typeface, effects, desc, FontMetricsCacheProc, context);
928 }
929
getFontMetrics(FontMetrics * metrics,SkScalar zoom) const930 SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const {
931 SkCanonicalizePaint canon(*this);
932 const SkPaint& paint = canon.getPaint();
933 SkScalar scale = canon.getScale();
934
935 SkMatrix zoomMatrix, *zoomPtr = nullptr;
936 if (zoom) {
937 zoomMatrix.setScale(zoom, zoom);
938 zoomPtr = &zoomMatrix;
939 }
940
941 FontMetrics storage;
942 if (nullptr == metrics) {
943 metrics = &storage;
944 }
945
946 paint.descriptorProc(nullptr, kNone_ScalerContextFlags, zoomPtr, FontMetricsDescProc, metrics);
947
948 if (scale) {
949 SkPaintPriv::ScaleFontMetrics(metrics, scale);
950 }
951 return metrics->fDescent - metrics->fAscent + metrics->fLeading;
952 }
953
954 ///////////////////////////////////////////////////////////////////////////////
955
set_bounds(const SkGlyph & g,SkRect * bounds,SkScalar scale)956 static void set_bounds(const SkGlyph& g, SkRect* bounds, SkScalar scale) {
957 bounds->set(g.fLeft * scale,
958 g.fTop * scale,
959 (g.fLeft + g.fWidth) * scale,
960 (g.fTop + g.fHeight) * scale);
961 }
962
getTextWidths(const void * textData,size_t byteLength,SkScalar widths[],SkRect bounds[]) const963 int SkPaint::getTextWidths(const void* textData, size_t byteLength,
964 SkScalar widths[], SkRect bounds[]) const {
965 if (0 == byteLength) {
966 return 0;
967 }
968
969 SkASSERT(textData);
970
971 if (nullptr == widths && nullptr == bounds) {
972 return this->countText(textData, byteLength);
973 }
974
975 SkCanonicalizePaint canon(*this);
976 const SkPaint& paint = canon.getPaint();
977 SkScalar scale = canon.getScale();
978
979 SkAutoGlyphCache autoCache(paint, nullptr, nullptr);
980 SkGlyphCache* cache = autoCache.getCache();
981 GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
982 paint.isDevKernText(),
983 nullptr != bounds);
984
985 const char* text = (const char*)textData;
986 const char* stop = text + byteLength;
987 int count = 0;
988 const int xyIndex = paint.isVerticalText() ? 1 : 0;
989
990 if (this->isDevKernText()) {
991 // we adjust the widths returned here through auto-kerning
992 SkAutoKern autokern;
993 SkScalar prevWidth = 0;
994
995 if (scale) {
996 while (text < stop) {
997 const SkGlyph& g = glyphCacheProc(cache, &text);
998 if (widths) {
999 SkScalar adjust = autokern.adjust(g);
1000
1001 if (count > 0) {
1002 *widths++ = (prevWidth + adjust) * scale;
1003 }
1004 prevWidth = advance(g, xyIndex);
1005 }
1006 if (bounds) {
1007 set_bounds(g, bounds++, scale);
1008 }
1009 ++count;
1010 }
1011 if (count > 0 && widths) {
1012 *widths = prevWidth * scale;
1013 }
1014 } else {
1015 while (text < stop) {
1016 const SkGlyph& g = glyphCacheProc(cache, &text);
1017 if (widths) {
1018 SkScalar adjust = autokern.adjust(g);
1019
1020 if (count > 0) {
1021 *widths++ = prevWidth + adjust;
1022 }
1023 prevWidth = advance(g, xyIndex);
1024 }
1025 if (bounds) {
1026 set_bounds(g, bounds++);
1027 }
1028 ++count;
1029 }
1030 if (count > 0 && widths) {
1031 *widths = prevWidth;
1032 }
1033 }
1034 } else { // no devkern
1035 if (scale) {
1036 while (text < stop) {
1037 const SkGlyph& g = glyphCacheProc(cache, &text);
1038 if (widths) {
1039 *widths++ = advance(g, xyIndex) * scale;
1040 }
1041 if (bounds) {
1042 set_bounds(g, bounds++, scale);
1043 }
1044 ++count;
1045 }
1046 } else {
1047 while (text < stop) {
1048 const SkGlyph& g = glyphCacheProc(cache, &text);
1049 if (widths) {
1050 *widths++ = advance(g, xyIndex);
1051 }
1052 if (bounds) {
1053 set_bounds(g, bounds++);
1054 }
1055 ++count;
1056 }
1057 }
1058 }
1059
1060 SkASSERT(text == stop);
1061 return count;
1062 }
1063
1064 ///////////////////////////////////////////////////////////////////////////////
1065
1066 #include "SkDraw.h"
1067
getTextPath(const void * textData,size_t length,SkScalar x,SkScalar y,SkPath * path) const1068 void SkPaint::getTextPath(const void* textData, size_t length,
1069 SkScalar x, SkScalar y, SkPath* path) const {
1070 SkASSERT(length == 0 || textData != nullptr);
1071
1072 const char* text = (const char*)textData;
1073 if (text == nullptr || length == 0 || path == nullptr) {
1074 return;
1075 }
1076
1077 SkTextToPathIter iter(text, length, *this, false);
1078 SkMatrix matrix;
1079 SkScalar prevXPos = 0;
1080
1081 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1082 matrix.postTranslate(x, y);
1083 path->reset();
1084
1085 SkScalar xpos;
1086 const SkPath* iterPath;
1087 while (iter.next(&iterPath, &xpos)) {
1088 matrix.postTranslate(xpos - prevXPos, 0);
1089 if (iterPath) {
1090 path->addPath(*iterPath, matrix);
1091 }
1092 prevXPos = xpos;
1093 }
1094 }
1095
getPosTextPath(const void * textData,size_t length,const SkPoint pos[],SkPath * path) const1096 void SkPaint::getPosTextPath(const void* textData, size_t length,
1097 const SkPoint pos[], SkPath* path) const {
1098 SkASSERT(length == 0 || textData != nullptr);
1099
1100 const char* text = (const char*)textData;
1101 if (text == nullptr || length == 0 || path == nullptr) {
1102 return;
1103 }
1104
1105 SkTextToPathIter iter(text, length, *this, false);
1106 SkMatrix matrix;
1107 SkPoint prevPos;
1108 prevPos.set(0, 0);
1109
1110 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1111 path->reset();
1112
1113 unsigned int i = 0;
1114 const SkPath* iterPath;
1115 while (iter.next(&iterPath, nullptr)) {
1116 matrix.postTranslate(pos[i].fX - prevPos.fX, pos[i].fY - prevPos.fY);
1117 if (iterPath) {
1118 path->addPath(*iterPath, matrix);
1119 }
1120 prevPos = pos[i];
1121 i++;
1122 }
1123 }
1124
1125 template <SkTextInterceptsIter::TextType TextType, typename Func>
GetTextIntercepts(const SkPaint & paint,const void * text,size_t length,const SkScalar bounds[2],SkScalar * array,Func posMaker)1126 int GetTextIntercepts(const SkPaint& paint, const void* text, size_t length,
1127 const SkScalar bounds[2], SkScalar* array, Func posMaker) {
1128 SkASSERT(length == 0 || text != nullptr);
1129 if (!length) {
1130 return 0;
1131 }
1132
1133 const SkPoint pos0 = posMaker(0);
1134 SkTextInterceptsIter iter(static_cast<const char*>(text), length, paint, bounds,
1135 pos0.x(), pos0.y(), TextType);
1136
1137 int i = 0;
1138 int count = 0;
1139 while (iter.next(array, &count)) {
1140 if (TextType == SkTextInterceptsIter::TextType::kPosText) {
1141 const SkPoint pos = posMaker(++i);
1142 iter.setPosition(pos.x(), pos.y());
1143 }
1144 }
1145
1146 return count;
1147 }
1148
getTextIntercepts(const void * textData,size_t length,SkScalar x,SkScalar y,const SkScalar bounds[2],SkScalar * array) const1149 int SkPaint::getTextIntercepts(const void* textData, size_t length,
1150 SkScalar x, SkScalar y, const SkScalar bounds[2],
1151 SkScalar* array) const {
1152
1153 return GetTextIntercepts<SkTextInterceptsIter::TextType::kText>(
1154 *this, textData, length, bounds, array, [&x, &y] (int) -> SkPoint {
1155 return SkPoint::Make(x, y);
1156 });
1157 }
1158
getPosTextIntercepts(const void * textData,size_t length,const SkPoint pos[],const SkScalar bounds[2],SkScalar * array) const1159 int SkPaint::getPosTextIntercepts(const void* textData, size_t length, const SkPoint pos[],
1160 const SkScalar bounds[2], SkScalar* array) const {
1161
1162 return GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
1163 *this, textData, length, bounds, array, [&pos] (int i) -> SkPoint {
1164 return pos[i];
1165 });
1166 }
1167
getPosTextHIntercepts(const void * textData,size_t length,const SkScalar xpos[],SkScalar constY,const SkScalar bounds[2],SkScalar * array) const1168 int SkPaint::getPosTextHIntercepts(const void* textData, size_t length, const SkScalar xpos[],
1169 SkScalar constY, const SkScalar bounds[2],
1170 SkScalar* array) const {
1171
1172 return GetTextIntercepts<SkTextInterceptsIter::TextType::kPosText>(
1173 *this, textData, length, bounds, array, [&xpos, &constY] (int i) -> SkPoint {
1174 return SkPoint::Make(xpos[i], constY);
1175 });
1176 }
1177
getTextBlobIntercepts(const SkTextBlob * blob,const SkScalar bounds[2],SkScalar * intervals) const1178 int SkPaint::getTextBlobIntercepts(const SkTextBlob* blob, const SkScalar bounds[2],
1179 SkScalar* intervals) const {
1180 int count = 0;
1181 SkPaint runPaint(*this);
1182
1183 SkTextBlobRunIterator it(blob);
1184 while (!it.done()) {
1185 it.applyFontToPaint(&runPaint);
1186 const size_t runByteCount = it.glyphCount() * sizeof(SkGlyphID);
1187 SkScalar* runIntervals = intervals ? intervals + count : nullptr;
1188
1189 switch (it.positioning()) {
1190 case SkTextBlob::kDefault_Positioning:
1191 count += runPaint.getTextIntercepts(it.glyphs(), runByteCount, it.offset().x(),
1192 it.offset().y(), bounds, runIntervals);
1193 break;
1194 case SkTextBlob::kHorizontal_Positioning:
1195 count += runPaint.getPosTextHIntercepts(it.glyphs(), runByteCount, it.pos(),
1196 it.offset().y(), bounds, runIntervals);
1197 break;
1198 case SkTextBlob::kFull_Positioning:
1199 count += runPaint.getPosTextIntercepts(it.glyphs(), runByteCount,
1200 reinterpret_cast<const SkPoint*>(it.pos()),
1201 bounds, runIntervals);
1202 break;
1203 }
1204
1205 it.next();
1206 }
1207
1208 return count;
1209 }
1210
getFontBounds() const1211 SkRect SkPaint::getFontBounds() const {
1212 SkMatrix m;
1213 m.setScale(fTextSize * fTextScaleX, fTextSize);
1214 m.postSkew(fTextSkewX, 0);
1215
1216 SkTypeface* typeface = this->getTypeface();
1217 if (nullptr == typeface) {
1218 typeface = SkTypeface::GetDefaultTypeface();
1219 }
1220
1221 SkRect bounds;
1222 m.mapRect(&bounds, typeface->getBounds());
1223 return bounds;
1224 }
1225
add_flattenable(SkDescriptor * desc,uint32_t tag,SkBinaryWriteBuffer * buffer)1226 static void add_flattenable(SkDescriptor* desc, uint32_t tag,
1227 SkBinaryWriteBuffer* buffer) {
1228 buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), nullptr));
1229 }
1230
compute_mask_format(const SkPaint & paint)1231 static SkMask::Format compute_mask_format(const SkPaint& paint) {
1232 uint32_t flags = paint.getFlags();
1233
1234 // Antialiasing being disabled trumps all other settings.
1235 if (!(flags & SkPaint::kAntiAlias_Flag)) {
1236 return SkMask::kBW_Format;
1237 }
1238
1239 if (flags & SkPaint::kLCDRenderText_Flag) {
1240 return SkMask::kLCD16_Format;
1241 }
1242
1243 return SkMask::kA8_Format;
1244 }
1245
1246 // if linear-text is on, then we force hinting to be off (since that's sort of
1247 // the point of linear-text.
computeHinting(const SkPaint & paint)1248 static SkPaint::Hinting computeHinting(const SkPaint& paint) {
1249 SkPaint::Hinting h = paint.getHinting();
1250 if (paint.isLinearText()) {
1251 h = SkPaint::kNo_Hinting;
1252 }
1253 return h;
1254 }
1255
1256 // return true if the paint is just a single color (i.e. not a shader). If its
1257 // a shader, then we can't compute a const luminance for it :(
justAColor(const SkPaint & paint,SkColor * color)1258 static bool justAColor(const SkPaint& paint, SkColor* color) {
1259 SkColor c = paint.getColor();
1260
1261 const auto* shader = as_SB(paint.getShader());
1262 if (shader && !shader->asLuminanceColor(&c)) {
1263 return false;
1264 }
1265 if (paint.getColorFilter()) {
1266 c = paint.getColorFilter()->filterColor(c);
1267 }
1268 if (color) {
1269 *color = c;
1270 }
1271 return true;
1272 }
1273
computeLuminanceColor() const1274 SkColor SkPaint::computeLuminanceColor() const {
1275 SkColor c;
1276 if (!justAColor(*this, &c)) {
1277 c = SkColorSetRGB(0x7F, 0x80, 0x7F);
1278 }
1279 return c;
1280 }
1281
1282 #define assert_byte(x) SkASSERT(0 == ((x) >> 8))
1283
1284 // Beyond this size, LCD doesn't appreciably improve quality, but it always
1285 // cost more RAM and draws slower, so we set a cap.
1286 #ifndef SK_MAX_SIZE_FOR_LCDTEXT
1287 #define SK_MAX_SIZE_FOR_LCDTEXT 48
1288 #endif
1289
1290 const SkScalar gMaxSize2ForLCDText = SK_MAX_SIZE_FOR_LCDTEXT * SK_MAX_SIZE_FOR_LCDTEXT;
1291
too_big_for_lcd(const SkScalerContext::Rec & rec,bool checkPost2x2)1292 static bool too_big_for_lcd(const SkScalerContext::Rec& rec, bool checkPost2x2) {
1293 if (checkPost2x2) {
1294 SkScalar area = rec.fPost2x2[0][0] * rec.fPost2x2[1][1] -
1295 rec.fPost2x2[1][0] * rec.fPost2x2[0][1];
1296 area *= rec.fTextSize * rec.fTextSize;
1297 return area > gMaxSize2ForLCDText;
1298 } else {
1299 return rec.fTextSize > SK_MAX_SIZE_FOR_LCDTEXT;
1300 }
1301 }
1302
1303 /*
1304 * Return the scalar with only limited fractional precision. Used to consolidate matrices
1305 * that vary only slightly when we create our key into the font cache, since the font scaler
1306 * typically returns the same looking resuts for tiny changes in the matrix.
1307 */
sk_relax(SkScalar x)1308 static SkScalar sk_relax(SkScalar x) {
1309 SkScalar n = SkScalarRoundToScalar(x * 1024);
1310 return n / 1024.0f;
1311 }
1312
MakeRec(const SkPaint & paint,const SkSurfaceProps * surfaceProps,const SkMatrix * deviceMatrix,Rec * rec)1313 void SkScalerContext::MakeRec(const SkPaint& paint,
1314 const SkSurfaceProps* surfaceProps,
1315 const SkMatrix* deviceMatrix,
1316 Rec* rec) {
1317 SkASSERT(deviceMatrix == nullptr || !deviceMatrix->hasPerspective());
1318
1319 SkTypeface* typeface = paint.getTypeface();
1320 if (nullptr == typeface) {
1321 typeface = SkTypeface::GetDefaultTypeface();
1322 }
1323 rec->fFontID = typeface->uniqueID();
1324 rec->fTextSize = paint.getTextSize();
1325 rec->fPreScaleX = paint.getTextScaleX();
1326 rec->fPreSkewX = paint.getTextSkewX();
1327
1328 bool checkPost2x2 = false;
1329
1330 if (deviceMatrix) {
1331 const SkMatrix::TypeMask mask = deviceMatrix->getType();
1332 if (mask & SkMatrix::kScale_Mask) {
1333 rec->fPost2x2[0][0] = sk_relax(deviceMatrix->getScaleX());
1334 rec->fPost2x2[1][1] = sk_relax(deviceMatrix->getScaleY());
1335 checkPost2x2 = true;
1336 } else {
1337 rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1;
1338 }
1339 if (mask & SkMatrix::kAffine_Mask) {
1340 rec->fPost2x2[0][1] = sk_relax(deviceMatrix->getSkewX());
1341 rec->fPost2x2[1][0] = sk_relax(deviceMatrix->getSkewY());
1342 checkPost2x2 = true;
1343 } else {
1344 rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0;
1345 }
1346 } else {
1347 rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1;
1348 rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0;
1349 }
1350
1351 SkPaint::Style style = paint.getStyle();
1352 SkScalar strokeWidth = paint.getStrokeWidth();
1353
1354 unsigned flags = 0;
1355
1356 if (paint.isFakeBoldText()) {
1357 #ifdef SK_USE_FREETYPE_EMBOLDEN
1358 flags |= SkScalerContext::kEmbolden_Flag;
1359 #else
1360 SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(),
1361 kStdFakeBoldInterpKeys,
1362 kStdFakeBoldInterpValues,
1363 kStdFakeBoldInterpLength);
1364 SkScalar extra = paint.getTextSize() * fakeBoldScale;
1365
1366 if (style == SkPaint::kFill_Style) {
1367 style = SkPaint::kStrokeAndFill_Style;
1368 strokeWidth = extra; // ignore paint's strokeWidth if it was "fill"
1369 } else {
1370 strokeWidth += extra;
1371 }
1372 #endif
1373 }
1374
1375 if (paint.isDevKernText()) {
1376 flags |= SkScalerContext::kDevKernText_Flag;
1377 }
1378
1379 if (style != SkPaint::kFill_Style && strokeWidth > 0) {
1380 rec->fFrameWidth = strokeWidth;
1381 rec->fMiterLimit = paint.getStrokeMiter();
1382 rec->fStrokeJoin = SkToU8(paint.getStrokeJoin());
1383 rec->fStrokeCap = SkToU8(paint.getStrokeCap());
1384
1385 if (style == SkPaint::kStrokeAndFill_Style) {
1386 flags |= SkScalerContext::kFrameAndFill_Flag;
1387 }
1388 } else {
1389 rec->fFrameWidth = 0;
1390 rec->fMiterLimit = 0;
1391 rec->fStrokeJoin = 0;
1392 rec->fStrokeCap = 0;
1393 }
1394
1395 rec->fMaskFormat = SkToU8(compute_mask_format(paint));
1396
1397 if (SkMask::kLCD16_Format == rec->fMaskFormat) {
1398 if (too_big_for_lcd(*rec, checkPost2x2)) {
1399 rec->fMaskFormat = SkMask::kA8_Format;
1400 flags |= SkScalerContext::kGenA8FromLCD_Flag;
1401 } else {
1402 SkPixelGeometry geometry = surfaceProps
1403 ? surfaceProps->pixelGeometry()
1404 : SkSurfacePropsDefaultPixelGeometry();
1405 switch (geometry) {
1406 case kUnknown_SkPixelGeometry:
1407 // eeek, can't support LCD
1408 rec->fMaskFormat = SkMask::kA8_Format;
1409 flags |= SkScalerContext::kGenA8FromLCD_Flag;
1410 break;
1411 case kRGB_H_SkPixelGeometry:
1412 // our default, do nothing.
1413 break;
1414 case kBGR_H_SkPixelGeometry:
1415 flags |= SkScalerContext::kLCD_BGROrder_Flag;
1416 break;
1417 case kRGB_V_SkPixelGeometry:
1418 flags |= SkScalerContext::kLCD_Vertical_Flag;
1419 break;
1420 case kBGR_V_SkPixelGeometry:
1421 flags |= SkScalerContext::kLCD_Vertical_Flag;
1422 flags |= SkScalerContext::kLCD_BGROrder_Flag;
1423 break;
1424 }
1425 }
1426 }
1427
1428 if (paint.isEmbeddedBitmapText()) {
1429 flags |= SkScalerContext::kEmbeddedBitmapText_Flag;
1430 }
1431 if (paint.isSubpixelText()) {
1432 flags |= SkScalerContext::kSubpixelPositioning_Flag;
1433 }
1434 if (paint.isAutohinted()) {
1435 flags |= SkScalerContext::kForceAutohinting_Flag;
1436 }
1437 if (paint.isVerticalText()) {
1438 flags |= SkScalerContext::kVertical_Flag;
1439 }
1440 if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) {
1441 flags |= SkScalerContext::kGenA8FromLCD_Flag;
1442 }
1443 rec->fFlags = SkToU16(flags);
1444
1445 // these modify fFlags, so do them after assigning fFlags
1446 rec->setHinting(computeHinting(paint));
1447
1448 rec->setLuminanceColor(paint.computeLuminanceColor());
1449
1450 //For now always set the paint gamma equal to the device gamma.
1451 //The math in SkMaskGamma can handle them being different,
1452 //but it requires superluminous masks when
1453 //Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large.
1454 rec->setDeviceGamma(SK_GAMMA_EXPONENT);
1455 rec->setPaintGamma(SK_GAMMA_EXPONENT);
1456
1457 #ifdef SK_GAMMA_CONTRAST
1458 rec->setContrast(SK_GAMMA_CONTRAST);
1459 #else
1460 /**
1461 * A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise.
1462 * With lower values small text appears washed out (though correctly so).
1463 * With higher values lcd fringing is worse and the smoothing effect of
1464 * partial coverage is diminished.
1465 */
1466 rec->setContrast(0.5f);
1467 #endif
1468
1469 rec->fReservedAlign = 0;
1470
1471 /* Allow the fonthost to modify our rec before we use it as a key into the
1472 cache. This way if we're asking for something that they will ignore,
1473 they can modify our rec up front, so we don't create duplicate cache
1474 entries.
1475 */
1476 typeface->onFilterRec(rec);
1477
1478 // be sure to call PostMakeRec(rec) before you actually use it!
1479 }
1480
1481 /**
1482 * In order to call cachedDeviceLuminance, cachedPaintLuminance, or
1483 * cachedMaskGamma the caller must hold the gMaskGammaCacheMutex and continue
1484 * to hold it until the returned pointer is refed or forgotten.
1485 */
1486 SK_DECLARE_STATIC_MUTEX(gMaskGammaCacheMutex);
1487
1488 static SkMaskGamma* gLinearMaskGamma = nullptr;
1489 static SkMaskGamma* gMaskGamma = nullptr;
1490 static SkScalar gContrast = SK_ScalarMin;
1491 static SkScalar gPaintGamma = SK_ScalarMin;
1492 static SkScalar gDeviceGamma = SK_ScalarMin;
1493 /**
1494 * The caller must hold the gMaskGammaCacheMutex and continue to hold it until
1495 * the returned SkMaskGamma pointer is refed or forgotten.
1496 */
cachedMaskGamma(SkScalar contrast,SkScalar paintGamma,SkScalar deviceGamma)1497 static const SkMaskGamma& cachedMaskGamma(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma) {
1498 gMaskGammaCacheMutex.assertHeld();
1499 if (0 == contrast && SK_Scalar1 == paintGamma && SK_Scalar1 == deviceGamma) {
1500 if (nullptr == gLinearMaskGamma) {
1501 gLinearMaskGamma = new SkMaskGamma;
1502 }
1503 return *gLinearMaskGamma;
1504 }
1505 if (gContrast != contrast || gPaintGamma != paintGamma || gDeviceGamma != deviceGamma) {
1506 SkSafeUnref(gMaskGamma);
1507 gMaskGamma = new SkMaskGamma(contrast, paintGamma, deviceGamma);
1508 gContrast = contrast;
1509 gPaintGamma = paintGamma;
1510 gDeviceGamma = deviceGamma;
1511 }
1512 return *gMaskGamma;
1513 }
1514
1515 /**
1516 * We ensure that the rec is self-consistent and efficient (where possible)
1517 */
PostMakeRec(const SkPaint &,SkScalerContext::Rec * rec)1518 void SkScalerContext::PostMakeRec(const SkPaint&, SkScalerContext::Rec* rec) {
1519 /**
1520 * If we're asking for A8, we force the colorlum to be gray, since that
1521 * limits the number of unique entries, and the scaler will only look at
1522 * the lum of one of them.
1523 */
1524 switch (rec->fMaskFormat) {
1525 case SkMask::kLCD16_Format: {
1526 // filter down the luminance color to a finite number of bits
1527 SkColor color = rec->getLuminanceColor();
1528 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color));
1529 break;
1530 }
1531 case SkMask::kA8_Format: {
1532 // filter down the luminance to a single component, since A8 can't
1533 // use per-component information
1534 SkColor color = rec->getLuminanceColor();
1535 U8CPU lum = SkComputeLuminance(SkColorGetR(color),
1536 SkColorGetG(color),
1537 SkColorGetB(color));
1538 // reduce to our finite number of bits
1539 color = SkColorSetRGB(lum, lum, lum);
1540 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color));
1541 break;
1542 }
1543 case SkMask::kBW_Format:
1544 // No need to differentiate gamma or apply contrast if we're BW
1545 rec->ignorePreBlend();
1546 break;
1547 }
1548 }
1549
1550 #define MIN_SIZE_FOR_EFFECT_BUFFER 1024
1551
1552 #ifdef SK_DEBUG
1553 #define TEST_DESC
1554 #endif
1555
write_out_descriptor(SkDescriptor * desc,const SkScalerContext::Rec & rec,const SkPathEffect * pe,SkBinaryWriteBuffer * peBuffer,const SkMaskFilter * mf,SkBinaryWriteBuffer * mfBuffer,const SkRasterizer * ra,SkBinaryWriteBuffer * raBuffer,size_t descSize)1556 static void write_out_descriptor(SkDescriptor* desc, const SkScalerContext::Rec& rec,
1557 const SkPathEffect* pe, SkBinaryWriteBuffer* peBuffer,
1558 const SkMaskFilter* mf, SkBinaryWriteBuffer* mfBuffer,
1559 const SkRasterizer* ra, SkBinaryWriteBuffer* raBuffer,
1560 size_t descSize) {
1561 desc->init();
1562 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
1563
1564 if (pe) {
1565 add_flattenable(desc, kPathEffect_SkDescriptorTag, peBuffer);
1566 }
1567 if (mf) {
1568 add_flattenable(desc, kMaskFilter_SkDescriptorTag, mfBuffer);
1569 }
1570 if (ra) {
1571 add_flattenable(desc, kRasterizer_SkDescriptorTag, raBuffer);
1572 }
1573
1574 desc->computeChecksum();
1575 }
1576
fill_out_rec(const SkPaint & paint,SkScalerContext::Rec * rec,const SkSurfaceProps * surfaceProps,bool fakeGamma,bool boostContrast,const SkMatrix * deviceMatrix,const SkPathEffect * pe,SkBinaryWriteBuffer * peBuffer,const SkMaskFilter * mf,SkBinaryWriteBuffer * mfBuffer,const SkRasterizer * ra,SkBinaryWriteBuffer * raBuffer)1577 static size_t fill_out_rec(const SkPaint& paint, SkScalerContext::Rec* rec,
1578 const SkSurfaceProps* surfaceProps,
1579 bool fakeGamma, bool boostContrast,
1580 const SkMatrix* deviceMatrix,
1581 const SkPathEffect* pe, SkBinaryWriteBuffer* peBuffer,
1582 const SkMaskFilter* mf, SkBinaryWriteBuffer* mfBuffer,
1583 const SkRasterizer* ra, SkBinaryWriteBuffer* raBuffer) {
1584 SkScalerContext::MakeRec(paint, surfaceProps, deviceMatrix, rec);
1585 if (!fakeGamma) {
1586 rec->ignoreGamma();
1587 }
1588 if (!boostContrast) {
1589 rec->setContrast(0);
1590 }
1591
1592 int entryCount = 1;
1593 size_t descSize = sizeof(*rec);
1594
1595 if (pe) {
1596 pe->flatten(*peBuffer);
1597 descSize += peBuffer->bytesWritten();
1598 entryCount += 1;
1599 rec->fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion
1600 // seems like we could support kLCD as well at this point...
1601 }
1602 if (mf) {
1603 mf->flatten(*mfBuffer);
1604 descSize += mfBuffer->bytesWritten();
1605 entryCount += 1;
1606 rec->fMaskFormat = SkMask::kA8_Format; // force antialiasing with maskfilters
1607 /* Pre-blend is not currently applied to filtered text.
1608 The primary filter is blur, for which contrast makes no sense,
1609 and for which the destination guess error is more visible.
1610 Also, all existing users of blur have calibrated for linear. */
1611 rec->ignorePreBlend();
1612 }
1613 if (ra) {
1614 ra->flatten(*raBuffer);
1615 descSize += raBuffer->bytesWritten();
1616 entryCount += 1;
1617 rec->fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion
1618 }
1619
1620 ///////////////////////////////////////////////////////////////////////////
1621 // Now that we're done tweaking the rec, call the PostMakeRec cleanup
1622 SkScalerContext::PostMakeRec(paint, rec);
1623
1624 descSize += SkDescriptor::ComputeOverhead(entryCount);
1625 return descSize;
1626 }
1627
1628 #ifdef TEST_DESC
test_desc(const SkScalerContext::Rec & rec,const SkPathEffect * pe,SkBinaryWriteBuffer * peBuffer,const SkMaskFilter * mf,SkBinaryWriteBuffer * mfBuffer,const SkRasterizer * ra,SkBinaryWriteBuffer * raBuffer,const SkDescriptor * desc,size_t descSize)1629 static void test_desc(const SkScalerContext::Rec& rec,
1630 const SkPathEffect* pe, SkBinaryWriteBuffer* peBuffer,
1631 const SkMaskFilter* mf, SkBinaryWriteBuffer* mfBuffer,
1632 const SkRasterizer* ra, SkBinaryWriteBuffer* raBuffer,
1633 const SkDescriptor* desc, size_t descSize) {
1634 // Check that we completely write the bytes in desc (our key), and that
1635 // there are no uninitialized bytes. If there were, then we would get
1636 // false-misses (or worse, false-hits) in our fontcache.
1637 //
1638 // We do this buy filling 2 others, one with 0s and the other with 1s
1639 // and create those, and then check that all 3 are identical.
1640 SkAutoDescriptor ad1(descSize);
1641 SkAutoDescriptor ad2(descSize);
1642 SkDescriptor* desc1 = ad1.getDesc();
1643 SkDescriptor* desc2 = ad2.getDesc();
1644
1645 memset(desc1, 0x00, descSize);
1646 memset(desc2, 0xFF, descSize);
1647
1648 desc1->init();
1649 desc2->init();
1650 desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
1651 desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
1652
1653 if (pe) {
1654 add_flattenable(desc1, kPathEffect_SkDescriptorTag, peBuffer);
1655 add_flattenable(desc2, kPathEffect_SkDescriptorTag, peBuffer);
1656 }
1657 if (mf) {
1658 add_flattenable(desc1, kMaskFilter_SkDescriptorTag, mfBuffer);
1659 add_flattenable(desc2, kMaskFilter_SkDescriptorTag, mfBuffer);
1660 }
1661 if (ra) {
1662 add_flattenable(desc1, kRasterizer_SkDescriptorTag, raBuffer);
1663 add_flattenable(desc2, kRasterizer_SkDescriptorTag, raBuffer);
1664 }
1665
1666 SkASSERT(descSize == desc1->getLength());
1667 SkASSERT(descSize == desc2->getLength());
1668 desc1->computeChecksum();
1669 desc2->computeChecksum();
1670 SkASSERT(!memcmp(desc, desc1, descSize));
1671 SkASSERT(!memcmp(desc, desc2, descSize));
1672 }
1673 #endif
1674
1675 /* see the note on ignoreGamma on descriptorProc */
getScalerContextDescriptor(SkScalerContextEffects * effects,SkAutoDescriptor * ad,const SkSurfaceProps & surfaceProps,uint32_t scalerContextFlags,const SkMatrix * deviceMatrix) const1676 void SkPaint::getScalerContextDescriptor(SkScalerContextEffects* effects,
1677 SkAutoDescriptor* ad,
1678 const SkSurfaceProps& surfaceProps,
1679 uint32_t scalerContextFlags,
1680 const SkMatrix* deviceMatrix) const {
1681 SkScalerContext::Rec rec;
1682
1683 SkPathEffect* pe = this->getPathEffect();
1684 SkMaskFilter* mf = this->getMaskFilter();
1685 SkRasterizer* ra = this->getRasterizer();
1686
1687 SkBinaryWriteBuffer peBuffer, mfBuffer, raBuffer;
1688 size_t descSize = fill_out_rec(*this, &rec, &surfaceProps,
1689 SkToBool(scalerContextFlags & kFakeGamma_ScalerContextFlag),
1690 SkToBool(scalerContextFlags & kBoostContrast_ScalerContextFlag),
1691 deviceMatrix, pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer);
1692
1693 ad->reset(descSize);
1694 SkDescriptor* desc = ad->getDesc();
1695
1696 write_out_descriptor(desc, rec, pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer, descSize);
1697
1698 SkASSERT(descSize == desc->getLength());
1699
1700 #ifdef TEST_DESC
1701 test_desc(rec, pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer, desc, descSize);
1702 #endif
1703
1704 effects->fPathEffect = pe;
1705 effects->fMaskFilter = mf;
1706 effects->fRasterizer = ra;
1707 }
1708
1709 /*
1710 * ignoreGamma tells us that the caller just wants metrics that are unaffected
1711 * by gamma correction, so we set the rec to ignore preblend: i.e. gamma = 1,
1712 * contrast = 0, luminanceColor = transparent black.
1713 */
descriptorProc(const SkSurfaceProps * surfaceProps,uint32_t scalerContextFlags,const SkMatrix * deviceMatrix,void (* proc)(SkTypeface *,const SkScalerContextEffects &,const SkDescriptor *,void *),void * context) const1714 void SkPaint::descriptorProc(const SkSurfaceProps* surfaceProps,
1715 uint32_t scalerContextFlags,
1716 const SkMatrix* deviceMatrix,
1717 void (*proc)(SkTypeface*, const SkScalerContextEffects&,
1718 const SkDescriptor*, void*),
1719 void* context) const {
1720 SkScalerContext::Rec rec;
1721
1722 SkPathEffect* pe = this->getPathEffect();
1723 SkMaskFilter* mf = this->getMaskFilter();
1724 SkRasterizer* ra = this->getRasterizer();
1725
1726 SkBinaryWriteBuffer peBuffer, mfBuffer, raBuffer;
1727 size_t descSize = fill_out_rec(*this, &rec, surfaceProps,
1728 SkToBool(scalerContextFlags & kFakeGamma_ScalerContextFlag),
1729 SkToBool(scalerContextFlags & kBoostContrast_ScalerContextFlag),
1730 deviceMatrix, pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer);
1731
1732 SkAutoDescriptor ad(descSize);
1733 SkDescriptor* desc = ad.getDesc();
1734
1735 write_out_descriptor(desc, rec, pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer, descSize);
1736
1737 SkASSERT(descSize == desc->getLength());
1738
1739 #ifdef TEST_DESC
1740 test_desc(rec, pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer, desc, descSize);
1741 #endif
1742
1743 proc(fTypeface.get(), { pe, mf, ra }, desc, context);
1744 }
1745
detachCache(const SkSurfaceProps * surfaceProps,uint32_t scalerContextFlags,const SkMatrix * deviceMatrix) const1746 SkGlyphCache* SkPaint::detachCache(const SkSurfaceProps* surfaceProps,
1747 uint32_t scalerContextFlags,
1748 const SkMatrix* deviceMatrix) const {
1749 SkGlyphCache* cache;
1750 this->descriptorProc(surfaceProps, scalerContextFlags, deviceMatrix, DetachDescProc, &cache);
1751 return cache;
1752 }
1753
1754 /**
1755 * Expands fDeviceGamma, fPaintGamma, fContrast, and fLumBits into a mask pre-blend.
1756 */
1757 //static
GetMaskPreBlend(const SkScalerContext::Rec & rec)1758 SkMaskGamma::PreBlend SkScalerContext::GetMaskPreBlend(const SkScalerContext::Rec& rec) {
1759 SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
1760 const SkMaskGamma& maskGamma = cachedMaskGamma(rec.getContrast(),
1761 rec.getPaintGamma(),
1762 rec.getDeviceGamma());
1763 return maskGamma.preBlend(rec.getLuminanceColor());
1764 }
1765
GetGammaLUTSize(SkScalar contrast,SkScalar paintGamma,SkScalar deviceGamma,int * width,int * height)1766 size_t SkScalerContext::GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma,
1767 SkScalar deviceGamma, int* width, int* height) {
1768 SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
1769 const SkMaskGamma& maskGamma = cachedMaskGamma(contrast,
1770 paintGamma,
1771 deviceGamma);
1772
1773 maskGamma.getGammaTableDimensions(width, height);
1774 size_t size = (*width)*(*height)*sizeof(uint8_t);
1775
1776 return size;
1777 }
1778
GetGammaLUTData(SkScalar contrast,SkScalar paintGamma,SkScalar deviceGamma,void * data)1779 void SkScalerContext::GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma,
1780 void* data) {
1781 SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
1782 const SkMaskGamma& maskGamma = cachedMaskGamma(contrast,
1783 paintGamma,
1784 deviceGamma);
1785 int width, height;
1786 maskGamma.getGammaTableDimensions(&width, &height);
1787 size_t size = width*height*sizeof(uint8_t);
1788 const uint8_t* gammaTables = maskGamma.getGammaTables();
1789 memcpy(data, gammaTables, size);
1790 }
1791
1792
1793 ///////////////////////////////////////////////////////////////////////////////
1794
1795 #include "SkStream.h"
1796
asint(const void * p)1797 static uintptr_t asint(const void* p) {
1798 return reinterpret_cast<uintptr_t>(p);
1799 }
1800
pack_4(unsigned a,unsigned b,unsigned c,unsigned d)1801 static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) {
1802 SkASSERT(a == (uint8_t)a);
1803 SkASSERT(b == (uint8_t)b);
1804 SkASSERT(c == (uint8_t)c);
1805 SkASSERT(d == (uint8_t)d);
1806 return (a << 24) | (b << 16) | (c << 8) | d;
1807 }
1808
1809 #ifdef SK_DEBUG
ASSERT_FITS_IN(uint32_t value,int bitCount)1810 static void ASSERT_FITS_IN(uint32_t value, int bitCount) {
1811 SkASSERT(bitCount > 0 && bitCount <= 32);
1812 uint32_t mask = ~0U;
1813 mask >>= (32 - bitCount);
1814 SkASSERT(0 == (value & ~mask));
1815 }
1816 #else
1817 #define ASSERT_FITS_IN(value, bitcount)
1818 #endif
1819
1820 enum FlatFlags {
1821 kHasTypeface_FlatFlag = 0x1,
1822 kHasEffects_FlatFlag = 0x2,
1823
1824 kFlatFlagMask = 0x3,
1825 };
1826
1827 enum BitsPerField {
1828 kFlags_BPF = 16,
1829 kHint_BPF = 2,
1830 kAlign_BPF = 2,
1831 kFilter_BPF = 2,
1832 kFlatFlags_BPF = 3,
1833 };
1834
BPF_Mask(int bits)1835 static inline int BPF_Mask(int bits) {
1836 return (1 << bits) - 1;
1837 }
1838
pack_paint_flags(unsigned flags,unsigned hint,unsigned align,unsigned filter,unsigned flatFlags)1839 static uint32_t pack_paint_flags(unsigned flags, unsigned hint, unsigned align,
1840 unsigned filter, unsigned flatFlags) {
1841 ASSERT_FITS_IN(flags, kFlags_BPF);
1842 ASSERT_FITS_IN(hint, kHint_BPF);
1843 ASSERT_FITS_IN(align, kAlign_BPF);
1844 ASSERT_FITS_IN(filter, kFilter_BPF);
1845 ASSERT_FITS_IN(flatFlags, kFlatFlags_BPF);
1846
1847 // left-align the fields of "known" size, and right-align the last (flatFlags) so it can easly
1848 // add more bits in the future.
1849 return (flags << 16) | (hint << 14) | (align << 12) | (filter << 10) | flatFlags;
1850 }
1851
unpack_paint_flags(SkPaint * paint,uint32_t packed)1852 static FlatFlags unpack_paint_flags(SkPaint* paint, uint32_t packed) {
1853 paint->setFlags(packed >> 16);
1854 paint->setHinting((SkPaint::Hinting)((packed >> 14) & BPF_Mask(kHint_BPF)));
1855 paint->setTextAlign((SkPaint::Align)((packed >> 12) & BPF_Mask(kAlign_BPF)));
1856 paint->setFilterQuality((SkFilterQuality)((packed >> 10) & BPF_Mask(kFilter_BPF)));
1857 return (FlatFlags)(packed & kFlatFlagMask);
1858 }
1859
1860 /* To save space/time, we analyze the paint, and write a truncated version of
1861 it if there are not tricky elements like shaders, etc.
1862 */
flatten(SkWriteBuffer & buffer) const1863 void SkPaint::flatten(SkWriteBuffer& buffer) const {
1864 // If the writer is xprocess, then we force recording our typeface, even if its "default"
1865 // since the other process may have a different notion of default.
1866 SkTypeface* tf = this->getTypeface();
1867 if (!tf && buffer.isCrossProcess()) {
1868 tf = SkTypeface::GetDefaultTypeface(SkTypeface::kNormal);
1869 }
1870
1871 uint8_t flatFlags = 0;
1872 if (tf) {
1873 flatFlags |= kHasTypeface_FlatFlag;
1874 }
1875 if (asint(this->getPathEffect()) |
1876 asint(this->getShader()) |
1877 asint(this->getMaskFilter()) |
1878 asint(this->getColorFilter()) |
1879 asint(this->getRasterizer()) |
1880 asint(this->getLooper()) |
1881 asint(this->getImageFilter())) {
1882 flatFlags |= kHasEffects_FlatFlag;
1883 }
1884
1885 buffer.writeScalar(this->getTextSize());
1886 buffer.writeScalar(this->getTextScaleX());
1887 buffer.writeScalar(this->getTextSkewX());
1888 buffer.writeScalar(this->getStrokeWidth());
1889 buffer.writeScalar(this->getStrokeMiter());
1890 buffer.writeColor(this->getColor());
1891
1892 buffer.writeUInt(pack_paint_flags(this->getFlags(), this->getHinting(), this->getTextAlign(),
1893 this->getFilterQuality(), flatFlags));
1894 buffer.writeUInt(pack_4(this->getStrokeCap(), this->getStrokeJoin(),
1895 (this->getStyle() << 4) | this->getTextEncoding(),
1896 fBlendMode));
1897
1898 // now we're done with ptr and the (pre)reserved space. If we need to write
1899 // additional fields, use the buffer directly
1900 if (flatFlags & kHasTypeface_FlatFlag) {
1901 buffer.writeTypeface(tf);
1902 }
1903 if (flatFlags & kHasEffects_FlatFlag) {
1904 buffer.writeFlattenable(this->getPathEffect());
1905 buffer.writeFlattenable(this->getShader());
1906 buffer.writeFlattenable(this->getMaskFilter());
1907 buffer.writeFlattenable(this->getColorFilter());
1908 buffer.writeFlattenable(this->getRasterizer());
1909 buffer.writeFlattenable(this->getLooper());
1910 buffer.writeFlattenable(this->getImageFilter());
1911 }
1912 }
1913
unflatten(SkReadBuffer & buffer)1914 void SkPaint::unflatten(SkReadBuffer& buffer) {
1915 this->setTextSize(buffer.readScalar());
1916 this->setTextScaleX(buffer.readScalar());
1917 this->setTextSkewX(buffer.readScalar());
1918 this->setStrokeWidth(buffer.readScalar());
1919 this->setStrokeMiter(buffer.readScalar());
1920 this->setColor(buffer.readColor());
1921
1922 unsigned flatFlags = unpack_paint_flags(this, buffer.readUInt());
1923
1924 uint32_t tmp = buffer.readUInt();
1925 this->setStrokeCap(static_cast<Cap>((tmp >> 24) & 0xFF));
1926 this->setStrokeJoin(static_cast<Join>((tmp >> 16) & 0xFF));
1927 this->setStyle(static_cast<Style>((tmp >> 12) & 0xF));
1928 this->setTextEncoding(static_cast<TextEncoding>((tmp >> 8) & 0xF));
1929 this->setBlendMode((SkBlendMode)(tmp & 0xFF));
1930
1931 if (flatFlags & kHasTypeface_FlatFlag) {
1932 this->setTypeface(buffer.readTypeface());
1933 } else {
1934 this->setTypeface(nullptr);
1935 }
1936
1937 if (flatFlags & kHasEffects_FlatFlag) {
1938 this->setPathEffect(buffer.readPathEffect());
1939 this->setShader(buffer.readShader());
1940 this->setMaskFilter(buffer.readMaskFilter());
1941 this->setColorFilter(buffer.readColorFilter());
1942 this->setRasterizer(buffer.readRasterizer());
1943 this->setLooper(buffer.readDrawLooper());
1944 this->setImageFilter(buffer.readImageFilter());
1945 } else {
1946 this->setPathEffect(nullptr);
1947 this->setShader(nullptr);
1948 this->setMaskFilter(nullptr);
1949 this->setColorFilter(nullptr);
1950 this->setRasterizer(nullptr);
1951 this->setLooper(nullptr);
1952 this->setImageFilter(nullptr);
1953 }
1954 }
1955
1956 ///////////////////////////////////////////////////////////////////////////////
1957
getFillPath(const SkPath & src,SkPath * dst,const SkRect * cullRect,SkScalar resScale) const1958 bool SkPaint::getFillPath(const SkPath& src, SkPath* dst, const SkRect* cullRect,
1959 SkScalar resScale) const {
1960 SkStrokeRec rec(*this, resScale);
1961
1962 const SkPath* srcPtr = &src;
1963 SkPath tmpPath;
1964
1965 if (fPathEffect && fPathEffect->filterPath(&tmpPath, src, &rec, cullRect)) {
1966 srcPtr = &tmpPath;
1967 }
1968
1969 if (!rec.applyToPath(dst, *srcPtr)) {
1970 if (srcPtr == &tmpPath) {
1971 // If path's were copy-on-write, this trick would not be needed.
1972 // As it is, we want to save making a deep-copy from tmpPath -> dst
1973 // since we know we're just going to delete tmpPath when we return,
1974 // so the swap saves that copy.
1975 dst->swap(tmpPath);
1976 } else {
1977 *dst = *srcPtr;
1978 }
1979 }
1980 return !rec.isHairlineStyle();
1981 }
1982
canComputeFastBounds() const1983 bool SkPaint::canComputeFastBounds() const {
1984 if (this->getLooper()) {
1985 return this->getLooper()->canComputeFastBounds(*this);
1986 }
1987 if (this->getImageFilter() && !this->getImageFilter()->canComputeFastBounds()) {
1988 return false;
1989 }
1990 return !this->getRasterizer();
1991 }
1992
doComputeFastBounds(const SkRect & origSrc,SkRect * storage,Style style) const1993 const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc,
1994 SkRect* storage,
1995 Style style) const {
1996 SkASSERT(storage);
1997
1998 const SkRect* src = &origSrc;
1999
2000 if (this->getLooper()) {
2001 SkASSERT(this->getLooper()->canComputeFastBounds(*this));
2002 this->getLooper()->computeFastBounds(*this, *src, storage);
2003 return *storage;
2004 }
2005
2006 SkRect tmpSrc;
2007 if (this->getPathEffect()) {
2008 this->getPathEffect()->computeFastBounds(&tmpSrc, origSrc);
2009 src = &tmpSrc;
2010 }
2011
2012 SkScalar radius = SkStrokeRec::GetInflationRadius(*this, style);
2013 *storage = src->makeOutset(radius, radius);
2014
2015 if (this->getMaskFilter()) {
2016 this->getMaskFilter()->computeFastBounds(*storage, storage);
2017 }
2018
2019 if (this->getImageFilter()) {
2020 *storage = this->getImageFilter()->computeFastBounds(*storage);
2021 }
2022
2023 return *storage;
2024 }
2025
2026 #ifndef SK_IGNORE_TO_STRING
2027
toString(SkString * str) const2028 void SkPaint::toString(SkString* str) const {
2029 str->append("<dl><dt>SkPaint:</dt><dd><dl>");
2030
2031 SkTypeface* typeface = this->getTypeface();
2032 if (typeface) {
2033 SkDynamicMemoryWStream ostream;
2034 typeface->serialize(&ostream);
2035 std::unique_ptr<SkStreamAsset> istream(ostream.detachAsStream());
2036
2037 SkFontDescriptor descriptor;
2038 if (!SkFontDescriptor::Deserialize(istream.get(), &descriptor)) {
2039 str->append("<dt>FontDescriptor deserialization failed</dt>");
2040 } else {
2041 str->append("<dt>Font Family Name:</dt><dd>");
2042 str->append(descriptor.getFamilyName());
2043 str->append("</dd><dt>Font Full Name:</dt><dd>");
2044 str->append(descriptor.getFullName());
2045 str->append("</dd><dt>Font PS Name:</dt><dd>");
2046 str->append(descriptor.getPostscriptName());
2047 str->append("</dd>");
2048 }
2049 }
2050
2051 str->append("<dt>TextSize:</dt><dd>");
2052 str->appendScalar(this->getTextSize());
2053 str->append("</dd>");
2054
2055 str->append("<dt>TextScaleX:</dt><dd>");
2056 str->appendScalar(this->getTextScaleX());
2057 str->append("</dd>");
2058
2059 str->append("<dt>TextSkewX:</dt><dd>");
2060 str->appendScalar(this->getTextSkewX());
2061 str->append("</dd>");
2062
2063 SkPathEffect* pathEffect = this->getPathEffect();
2064 if (pathEffect) {
2065 str->append("<dt>PathEffect:</dt><dd>");
2066 pathEffect->toString(str);
2067 str->append("</dd>");
2068 }
2069
2070 if (const auto* shader = as_SB(this->getShader())) {
2071 str->append("<dt>Shader:</dt><dd>");
2072 shader->toString(str);
2073 str->append("</dd>");
2074 }
2075
2076 if (!this->isSrcOver()) {
2077 str->appendf("<dt>Xfermode:</dt><dd>%d</dd>", fBlendMode);
2078 }
2079
2080 SkMaskFilter* maskFilter = this->getMaskFilter();
2081 if (maskFilter) {
2082 str->append("<dt>MaskFilter:</dt><dd>");
2083 maskFilter->toString(str);
2084 str->append("</dd>");
2085 }
2086
2087 SkColorFilter* colorFilter = this->getColorFilter();
2088 if (colorFilter) {
2089 str->append("<dt>ColorFilter:</dt><dd>");
2090 colorFilter->toString(str);
2091 str->append("</dd>");
2092 }
2093
2094 SkRasterizer* rasterizer = this->getRasterizer();
2095 if (rasterizer) {
2096 str->append("<dt>Rasterizer:</dt><dd>");
2097 str->append("</dd>");
2098 }
2099
2100 SkDrawLooper* looper = this->getLooper();
2101 if (looper) {
2102 str->append("<dt>DrawLooper:</dt><dd>");
2103 looper->toString(str);
2104 str->append("</dd>");
2105 }
2106
2107 SkImageFilter* imageFilter = this->getImageFilter();
2108 if (imageFilter) {
2109 str->append("<dt>ImageFilter:</dt><dd>");
2110 imageFilter->toString(str);
2111 str->append("</dd>");
2112 }
2113
2114 str->append("<dt>Color:</dt><dd>0x");
2115 SkColor color = this->getColor();
2116 str->appendHex(color);
2117 str->append("</dd>");
2118
2119 str->append("<dt>Stroke Width:</dt><dd>");
2120 str->appendScalar(this->getStrokeWidth());
2121 str->append("</dd>");
2122
2123 str->append("<dt>Stroke Miter:</dt><dd>");
2124 str->appendScalar(this->getStrokeMiter());
2125 str->append("</dd>");
2126
2127 str->append("<dt>Flags:</dt><dd>(");
2128 if (this->getFlags()) {
2129 bool needSeparator = false;
2130 SkAddFlagToString(str, this->isAntiAlias(), "AntiAlias", &needSeparator);
2131 SkAddFlagToString(str, this->isDither(), "Dither", &needSeparator);
2132 SkAddFlagToString(str, this->isFakeBoldText(), "FakeBoldText", &needSeparator);
2133 SkAddFlagToString(str, this->isLinearText(), "LinearText", &needSeparator);
2134 SkAddFlagToString(str, this->isSubpixelText(), "SubpixelText", &needSeparator);
2135 SkAddFlagToString(str, this->isDevKernText(), "DevKernText", &needSeparator);
2136 SkAddFlagToString(str, this->isLCDRenderText(), "LCDRenderText", &needSeparator);
2137 SkAddFlagToString(str, this->isEmbeddedBitmapText(),
2138 "EmbeddedBitmapText", &needSeparator);
2139 SkAddFlagToString(str, this->isAutohinted(), "Autohinted", &needSeparator);
2140 SkAddFlagToString(str, this->isVerticalText(), "VerticalText", &needSeparator);
2141 SkAddFlagToString(str, SkToBool(this->getFlags() & SkPaint::kGenA8FromLCD_Flag),
2142 "GenA8FromLCD", &needSeparator);
2143 } else {
2144 str->append("None");
2145 }
2146 str->append(")</dd>");
2147
2148 str->append("<dt>FilterLevel:</dt><dd>");
2149 static const char* gFilterQualityStrings[] = { "None", "Low", "Medium", "High" };
2150 str->append(gFilterQualityStrings[this->getFilterQuality()]);
2151 str->append("</dd>");
2152
2153 str->append("<dt>TextAlign:</dt><dd>");
2154 static const char* gTextAlignStrings[SkPaint::kAlignCount] = { "Left", "Center", "Right" };
2155 str->append(gTextAlignStrings[this->getTextAlign()]);
2156 str->append("</dd>");
2157
2158 str->append("<dt>CapType:</dt><dd>");
2159 static const char* gStrokeCapStrings[SkPaint::kCapCount] = { "Butt", "Round", "Square" };
2160 str->append(gStrokeCapStrings[this->getStrokeCap()]);
2161 str->append("</dd>");
2162
2163 str->append("<dt>JoinType:</dt><dd>");
2164 static const char* gJoinStrings[SkPaint::kJoinCount] = { "Miter", "Round", "Bevel" };
2165 str->append(gJoinStrings[this->getStrokeJoin()]);
2166 str->append("</dd>");
2167
2168 str->append("<dt>Style:</dt><dd>");
2169 static const char* gStyleStrings[SkPaint::kStyleCount] = { "Fill", "Stroke", "StrokeAndFill" };
2170 str->append(gStyleStrings[this->getStyle()]);
2171 str->append("</dd>");
2172
2173 str->append("<dt>TextEncoding:</dt><dd>");
2174 static const char* gTextEncodingStrings[] = { "UTF8", "UTF16", "UTF32", "GlyphID" };
2175 str->append(gTextEncodingStrings[this->getTextEncoding()]);
2176 str->append("</dd>");
2177
2178 str->append("<dt>Hinting:</dt><dd>");
2179 static const char* gHintingStrings[] = { "None", "Slight", "Normal", "Full" };
2180 str->append(gHintingStrings[this->getHinting()]);
2181 str->append("</dd>");
2182
2183 str->append("</dd></dl></dl>");
2184 }
2185 #endif
2186
2187 ///////////////////////////////////////////////////////////////////////////////
2188
has_thick_frame(const SkPaint & paint)2189 static bool has_thick_frame(const SkPaint& paint) {
2190 return paint.getStrokeWidth() > 0 &&
2191 paint.getStyle() != SkPaint::kFill_Style;
2192 }
2193
SkTextBaseIter(const char text[],size_t length,const SkPaint & paint,bool applyStrokeAndPathEffects)2194 SkTextBaseIter::SkTextBaseIter(const char text[], size_t length,
2195 const SkPaint& paint,
2196 bool applyStrokeAndPathEffects)
2197 : fPaint(paint) {
2198 fGlyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
2199 paint.isDevKernText(),
2200 true);
2201
2202 fPaint.setLinearText(true);
2203 fPaint.setMaskFilter(nullptr); // don't want this affecting our path-cache lookup
2204
2205 if (fPaint.getPathEffect() == nullptr && !has_thick_frame(fPaint)) {
2206 applyStrokeAndPathEffects = false;
2207 }
2208
2209 // can't use our canonical size if we need to apply patheffects
2210 if (fPaint.getPathEffect() == nullptr) {
2211 fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
2212 fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
2213 if (has_thick_frame(fPaint)) {
2214 fPaint.setStrokeWidth(fPaint.getStrokeWidth() / fScale);
2215 }
2216 } else {
2217 fScale = SK_Scalar1;
2218 }
2219
2220 if (!applyStrokeAndPathEffects) {
2221 fPaint.setStyle(SkPaint::kFill_Style);
2222 fPaint.setPathEffect(nullptr);
2223 }
2224
2225 // SRGBTODO: Is this correct?
2226 fCache = fPaint.detachCache(nullptr, SkPaint::kFakeGammaAndBoostContrast_ScalerContextFlags,
2227 nullptr);
2228
2229 SkPaint::Style style = SkPaint::kFill_Style;
2230 sk_sp<SkPathEffect> pe;
2231
2232 if (!applyStrokeAndPathEffects) {
2233 style = paint.getStyle(); // restore
2234 pe = paint.refPathEffect(); // restore
2235 }
2236 fPaint.setStyle(style);
2237 fPaint.setPathEffect(pe);
2238 fPaint.setMaskFilter(paint.refMaskFilter()); // restore
2239
2240 // now compute fXOffset if needed
2241
2242 SkScalar xOffset = 0;
2243 if (paint.getTextAlign() != SkPaint::kLeft_Align) { // need to measure first
2244 int count;
2245 SkScalar width = fPaint.measure_text(fCache, text, length, &count, nullptr) * fScale;
2246 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2247 width = SkScalarHalf(width);
2248 }
2249 xOffset = -width;
2250 }
2251 fXPos = xOffset;
2252 fPrevAdvance = 0;
2253
2254 fText = text;
2255 fStop = text + length;
2256
2257 fXYIndex = paint.isVerticalText() ? 1 : 0;
2258 }
2259
~SkTextBaseIter()2260 SkTextBaseIter::~SkTextBaseIter() {
2261 SkGlyphCache::AttachCache(fCache);
2262 }
2263
next(const SkPath ** path,SkScalar * xpos)2264 bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) {
2265 if (fText < fStop) {
2266 const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText);
2267
2268 fXPos += (fPrevAdvance + fAutoKern.adjust(glyph)) * fScale;
2269 fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking();
2270
2271 if (glyph.fWidth) {
2272 if (path) {
2273 *path = fCache->findPath(glyph);
2274 }
2275 } else {
2276 if (path) {
2277 *path = nullptr;
2278 }
2279 }
2280 if (xpos) {
2281 *xpos = fXPos;
2282 }
2283 return true;
2284 }
2285 return false;
2286 }
2287
next(SkScalar * array,int * count)2288 bool SkTextInterceptsIter::next(SkScalar* array, int* count) {
2289 const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText);
2290 fXPos += (fPrevAdvance + fAutoKern.adjust(glyph)) * fScale;
2291 fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking();
2292 if (fCache->findPath(glyph)) {
2293 fCache->findIntercepts(fBounds, fScale, fXPos, SkToBool(fXYIndex),
2294 const_cast<SkGlyph*>(&glyph), array, count);
2295 }
2296 return fText < fStop;
2297 }
2298
2299 ///////////////////////////////////////////////////////////////////////////////
2300
2301 // return true if the filter exists, and may affect alpha
affects_alpha(const SkColorFilter * cf)2302 static bool affects_alpha(const SkColorFilter* cf) {
2303 return cf && !(cf->getFlags() & SkColorFilter::kAlphaUnchanged_Flag);
2304 }
2305
2306 // return true if the filter exists, and may affect alpha
affects_alpha(const SkImageFilter * imf)2307 static bool affects_alpha(const SkImageFilter* imf) {
2308 // TODO: check if we should allow imagefilters to broadcast that they don't affect alpha
2309 // ala colorfilters
2310 return imf != nullptr;
2311 }
2312
nothingToDraw() const2313 bool SkPaint::nothingToDraw() const {
2314 if (fDrawLooper) {
2315 return false;
2316 }
2317 switch ((SkBlendMode)fBlendMode) {
2318 case SkBlendMode::kSrcOver:
2319 case SkBlendMode::kSrcATop:
2320 case SkBlendMode::kDstOut:
2321 case SkBlendMode::kDstOver:
2322 case SkBlendMode::kPlus:
2323 if (0 == this->getAlpha()) {
2324 return !affects_alpha(fColorFilter.get()) && !affects_alpha(fImageFilter.get());
2325 }
2326 break;
2327 case SkBlendMode::kDst:
2328 return true;
2329 default:
2330 break;
2331 }
2332 return false;
2333 }
2334
getHash() const2335 uint32_t SkPaint::getHash() const {
2336 // We're going to hash 10 pointers and 7 32-bit values, finishing up with fBitfields,
2337 // so fBitfields should be 10 pointers and 6 32-bit values from the start.
2338 static_assert(offsetof(SkPaint, fBitfields) == 8 * sizeof(void*) + 7 * sizeof(uint32_t),
2339 "SkPaint_notPackedTightly");
2340 return SkOpts::hash(reinterpret_cast<const uint32_t*>(this),
2341 offsetof(SkPaint, fBitfields) + sizeof(fBitfields));
2342 }
2343