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