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