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