3 * Copyright 2006 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "SkAnnotation.h"
11 #include "SkAutoKern.h"
12 #include "SkColorFilter.h"
14 #include "SkDeviceProperties.h"
15 #include "SkFontDescriptor.h"
16 #include "SkFontHost.h"
17 #include "SkGlyphCache.h"
18 #include "SkImageFilter.h"
19 #include "SkMaskFilter.h"
20 #include "SkMaskGamma.h"
21 #include "SkReadBuffer.h"
22 #include "SkWriteBuffer.h"
23 #include "SkPaintDefaults.h"
24 #include "SkPaintOptionsAndroid.h"
25 #include "SkPathEffect.h"
26 #include "SkRasterizer.h"
28 #include "SkScalerContext.h"
30 #include "SkStringUtils.h"
32 #include "SkTextFormatParams.h"
33 #include "SkTextToPathIter.h"
35 #include "SkTypeface.h"
36 #include "SkXfermode.h"
39 // define this to get a printf for out-of-range parameter in setters
40 // e.g. setTextSize(-1)
41 //#define SK_REPORT_API_RANGE_CHECK
43 #ifdef SK_BUILD_FOR_ANDROID
44 #define GEN_ID_INC fGenerationID++
45 #define GEN_ID_INC_EVAL(expression) if (expression) { fGenerationID++; }
48 #define GEN_ID_INC_EVAL(expression)
52 // since we may have padding, we zero everything so that our memcmp() call
53 // in operator== will work correctly.
54 // with this, we can skip 0 and null individual initializations
55 sk_bzero(this, sizeof(*this));
57 #if 0 // not needed with the bzero call above
72 fTextSize = SkPaintDefaults_TextSize;
73 fTextScaleX = SK_Scalar1;
74 fColor = SK_ColorBLACK;
75 fMiterLimit = SkPaintDefaults_MiterLimit;
76 fFlags = SkPaintDefaults_Flags;
77 fCapType = kDefault_Cap;
78 fJoinType = kDefault_Join;
79 fTextAlign = kLeft_Align;
81 fTextEncoding = kUTF8_TextEncoding;
82 fHinting = SkPaintDefaults_Hinting;
83 #ifdef SK_BUILD_FOR_ANDROID
84 new (&fPaintOptionsAndroid) SkPaintOptionsAndroid;
89 SkPaint::SkPaint(const SkPaint& src) {
90 memcpy(this, &src, sizeof(src));
93 SkSafeRef(fPathEffect);
96 SkSafeRef(fMaskFilter);
97 SkSafeRef(fColorFilter);
98 SkSafeRef(fRasterizer);
100 SkSafeRef(fImageFilter);
101 SkSafeRef(fAnnotation);
103 #ifdef SK_BUILD_FOR_ANDROID
104 new (&fPaintOptionsAndroid) SkPaintOptionsAndroid(src.fPaintOptionsAndroid);
108 SkPaint::~SkPaint() {
109 SkSafeUnref(fTypeface);
110 SkSafeUnref(fPathEffect);
111 SkSafeUnref(fShader);
112 SkSafeUnref(fXfermode);
113 SkSafeUnref(fMaskFilter);
114 SkSafeUnref(fColorFilter);
115 SkSafeUnref(fRasterizer);
116 SkSafeUnref(fLooper);
117 SkSafeUnref(fImageFilter);
118 SkSafeUnref(fAnnotation);
121 SkPaint& SkPaint::operator=(const SkPaint& src) {
124 SkSafeRef(src.fTypeface);
125 SkSafeRef(src.fPathEffect);
126 SkSafeRef(src.fShader);
127 SkSafeRef(src.fXfermode);
128 SkSafeRef(src.fMaskFilter);
129 SkSafeRef(src.fColorFilter);
130 SkSafeRef(src.fRasterizer);
131 SkSafeRef(src.fLooper);
132 SkSafeRef(src.fImageFilter);
133 SkSafeRef(src.fAnnotation);
135 SkSafeUnref(fTypeface);
136 SkSafeUnref(fPathEffect);
137 SkSafeUnref(fShader);
138 SkSafeUnref(fXfermode);
139 SkSafeUnref(fMaskFilter);
140 SkSafeUnref(fColorFilter);
141 SkSafeUnref(fRasterizer);
142 SkSafeUnref(fLooper);
143 SkSafeUnref(fImageFilter);
144 SkSafeUnref(fAnnotation);
146 #ifdef SK_BUILD_FOR_ANDROID
147 fPaintOptionsAndroid.~SkPaintOptionsAndroid();
149 uint32_t oldGenerationID = fGenerationID;
151 memcpy(this, &src, sizeof(src));
152 #ifdef SK_BUILD_FOR_ANDROID
153 fGenerationID = oldGenerationID + 1;
155 new (&fPaintOptionsAndroid) SkPaintOptionsAndroid(src.fPaintOptionsAndroid);
161 bool operator==(const SkPaint& a, const SkPaint& b) {
162 #ifdef SK_BUILD_FOR_ANDROID
163 //assumes that fGenerationID is the last field in the struct
164 return !memcmp(&a, &b, SK_OFFSETOF(SkPaint, fGenerationID));
166 return !memcmp(&a, &b, sizeof(a));
170 void SkPaint::reset() {
173 #ifdef SK_BUILD_FOR_ANDROID
174 uint32_t oldGenerationID = fGenerationID;
177 #ifdef SK_BUILD_FOR_ANDROID
178 fGenerationID = oldGenerationID + 1;
182 #ifdef SK_BUILD_FOR_ANDROID
183 uint32_t SkPaint::getGenerationID() const {
184 return fGenerationID;
187 void SkPaint::setGenerationID(uint32_t generationID) {
188 fGenerationID = generationID;
191 unsigned SkPaint::getBaseGlyphCount(SkUnichar text) const {
192 SkAutoGlyphCache autoCache(*this, NULL, NULL);
193 SkGlyphCache* cache = autoCache.getCache();
194 return cache->getBaseGlyphCount(text);
197 void SkPaint::setPaintOptionsAndroid(const SkPaintOptionsAndroid& options) {
198 if (options != fPaintOptionsAndroid) {
199 fPaintOptionsAndroid = options;
205 SkPaint::FilterLevel SkPaint::getFilterLevel() const {
207 if (fFlags & kFilterBitmap_Flag) {
210 if (fFlags & kHighQualityFilterBitmap_Flag) {
213 return (FilterLevel)level;
216 void SkPaint::setFilterLevel(FilterLevel level) {
217 unsigned mask = kFilterBitmap_Flag | kHighQualityFilterBitmap_Flag;
220 flags |= kFilterBitmap_Flag;
223 flags |= kHighQualityFilterBitmap_Flag;
225 this->setFlags((fFlags & ~mask) | flags);
228 void SkPaint::setHinting(Hinting hintingLevel) {
229 GEN_ID_INC_EVAL((unsigned) hintingLevel != fHinting);
230 fHinting = hintingLevel;
233 void SkPaint::setFlags(uint32_t flags) {
234 GEN_ID_INC_EVAL(fFlags != flags);
238 void SkPaint::setAntiAlias(bool doAA) {
239 this->setFlags(SkSetClearMask(fFlags, doAA, kAntiAlias_Flag));
242 void SkPaint::setDither(bool doDither) {
243 this->setFlags(SkSetClearMask(fFlags, doDither, kDither_Flag));
246 void SkPaint::setSubpixelText(bool doSubpixel) {
247 this->setFlags(SkSetClearMask(fFlags, doSubpixel, kSubpixelText_Flag));
250 void SkPaint::setLCDRenderText(bool doLCDRender) {
251 this->setFlags(SkSetClearMask(fFlags, doLCDRender, kLCDRenderText_Flag));
254 void SkPaint::setEmbeddedBitmapText(bool doEmbeddedBitmapText) {
255 this->setFlags(SkSetClearMask(fFlags, doEmbeddedBitmapText, kEmbeddedBitmapText_Flag));
258 void SkPaint::setAutohinted(bool useAutohinter) {
259 this->setFlags(SkSetClearMask(fFlags, useAutohinter, kAutoHinting_Flag));
262 void SkPaint::setLinearText(bool doLinearText) {
263 this->setFlags(SkSetClearMask(fFlags, doLinearText, kLinearText_Flag));
266 void SkPaint::setVerticalText(bool doVertical) {
267 this->setFlags(SkSetClearMask(fFlags, doVertical, kVerticalText_Flag));
270 void SkPaint::setUnderlineText(bool doUnderline) {
271 this->setFlags(SkSetClearMask(fFlags, doUnderline, kUnderlineText_Flag));
274 void SkPaint::setStrikeThruText(bool doStrikeThru) {
275 this->setFlags(SkSetClearMask(fFlags, doStrikeThru, kStrikeThruText_Flag));
278 void SkPaint::setFakeBoldText(bool doFakeBold) {
279 this->setFlags(SkSetClearMask(fFlags, doFakeBold, kFakeBoldText_Flag));
282 void SkPaint::setDevKernText(bool doDevKern) {
283 this->setFlags(SkSetClearMask(fFlags, doDevKern, kDevKernText_Flag));
286 void SkPaint::setStyle(Style style) {
287 if ((unsigned)style < kStyleCount) {
288 GEN_ID_INC_EVAL((unsigned)style != fStyle);
291 #ifdef SK_REPORT_API_RANGE_CHECK
292 SkDebugf("SkPaint::setStyle(%d) out of range\n", style);
297 void SkPaint::setColor(SkColor color) {
298 GEN_ID_INC_EVAL(color != fColor);
302 void SkPaint::setAlpha(U8CPU a) {
303 this->setColor(SkColorSetARGB(a, SkColorGetR(fColor),
304 SkColorGetG(fColor), SkColorGetB(fColor)));
307 void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
308 this->setColor(SkColorSetARGB(a, r, g, b));
311 void SkPaint::setStrokeWidth(SkScalar width) {
313 GEN_ID_INC_EVAL(width != fWidth);
316 #ifdef SK_REPORT_API_RANGE_CHECK
317 SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");
322 void SkPaint::setStrokeMiter(SkScalar limit) {
324 GEN_ID_INC_EVAL(limit != fMiterLimit);
327 #ifdef SK_REPORT_API_RANGE_CHECK
328 SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");
333 void SkPaint::setStrokeCap(Cap ct) {
334 if ((unsigned)ct < kCapCount) {
335 GEN_ID_INC_EVAL((unsigned)ct != fCapType);
336 fCapType = SkToU8(ct);
338 #ifdef SK_REPORT_API_RANGE_CHECK
339 SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);
344 void SkPaint::setStrokeJoin(Join jt) {
345 if ((unsigned)jt < kJoinCount) {
346 GEN_ID_INC_EVAL((unsigned)jt != fJoinType);
347 fJoinType = SkToU8(jt);
349 #ifdef SK_REPORT_API_RANGE_CHECK
350 SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);
355 ///////////////////////////////////////////////////////////////////////////////
357 void SkPaint::setTextAlign(Align align) {
358 if ((unsigned)align < kAlignCount) {
359 GEN_ID_INC_EVAL((unsigned)align != fTextAlign);
360 fTextAlign = SkToU8(align);
362 #ifdef SK_REPORT_API_RANGE_CHECK
363 SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align);
368 void SkPaint::setTextSize(SkScalar ts) {
370 GEN_ID_INC_EVAL(ts != fTextSize);
373 #ifdef SK_REPORT_API_RANGE_CHECK
374 SkDebugf("SkPaint::setTextSize() called with negative value\n");
379 void SkPaint::setTextScaleX(SkScalar scaleX) {
380 GEN_ID_INC_EVAL(scaleX != fTextScaleX);
381 fTextScaleX = scaleX;
384 void SkPaint::setTextSkewX(SkScalar skewX) {
385 GEN_ID_INC_EVAL(skewX != fTextSkewX);
389 void SkPaint::setTextEncoding(TextEncoding encoding) {
390 if ((unsigned)encoding <= kGlyphID_TextEncoding) {
391 GEN_ID_INC_EVAL((unsigned)encoding != fTextEncoding);
392 fTextEncoding = encoding;
394 #ifdef SK_REPORT_API_RANGE_CHECK
395 SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding);
400 ///////////////////////////////////////////////////////////////////////////////
402 SkTypeface* SkPaint::setTypeface(SkTypeface* font) {
403 SkRefCnt_SafeAssign(fTypeface, font);
408 SkRasterizer* SkPaint::setRasterizer(SkRasterizer* r) {
409 SkRefCnt_SafeAssign(fRasterizer, r);
414 SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) {
415 SkRefCnt_SafeAssign(fLooper, looper);
420 SkImageFilter* SkPaint::setImageFilter(SkImageFilter* imageFilter) {
421 SkRefCnt_SafeAssign(fImageFilter, imageFilter);
426 SkAnnotation* SkPaint::setAnnotation(SkAnnotation* annotation) {
427 SkRefCnt_SafeAssign(fAnnotation, annotation);
432 ///////////////////////////////////////////////////////////////////////////////
434 static SkScalar mag2(SkScalar x, SkScalar y) {
435 return x * x + y * y;
438 static bool tooBig(const SkMatrix& m, SkScalar ma2max) {
439 return mag2(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewY]) > ma2max
441 mag2(m[SkMatrix::kMSkewX], m[SkMatrix::kMScaleY]) > ma2max;
444 bool SkPaint::TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM) {
445 SkASSERT(!ctm.hasPerspective());
446 SkASSERT(!textM.hasPerspective());
449 matrix.setConcat(ctm, textM);
450 return tooBig(matrix, MaxCacheSize2());
453 bool SkPaint::tooBigToUseCache(const SkMatrix& ctm) const {
455 return TooBigToUseCache(ctm, *this->setTextMatrix(&textM));
458 bool SkPaint::tooBigToUseCache() const {
460 return tooBig(*this->setTextMatrix(&textM), MaxCacheSize2());
463 ///////////////////////////////////////////////////////////////////////////////
465 #include "SkGlyphCache.h"
468 static void DetachDescProc(SkTypeface* typeface, const SkDescriptor* desc,
470 *((SkGlyphCache**)context) = SkGlyphCache::DetachCache(typeface, desc);
473 #ifdef SK_BUILD_FOR_ANDROID
474 const SkGlyph& SkPaint::getUnicharMetrics(SkUnichar text,
475 const SkMatrix* deviceMatrix) {
477 descriptorProc(NULL, deviceMatrix, DetachDescProc, &cache, true);
479 const SkGlyph& glyph = cache->getUnicharMetrics(text);
481 SkGlyphCache::AttachCache(cache);
485 const SkGlyph& SkPaint::getGlyphMetrics(uint16_t glyphId,
486 const SkMatrix* deviceMatrix) {
488 descriptorProc(NULL, deviceMatrix, DetachDescProc, &cache, true);
490 const SkGlyph& glyph = cache->getGlyphIDMetrics(glyphId);
492 SkGlyphCache::AttachCache(cache);
496 const void* SkPaint::findImage(const SkGlyph& glyph,
497 const SkMatrix* deviceMatrix) {
498 // See ::detachCache()
500 descriptorProc(NULL, deviceMatrix, DetachDescProc, &cache, true);
502 const void* image = cache->findImage(glyph);
504 SkGlyphCache::AttachCache(cache);
509 int SkPaint::textToGlyphs(const void* textData, size_t byteLength,
510 uint16_t glyphs[]) const {
511 if (byteLength == 0) {
515 SkASSERT(textData != NULL);
517 if (NULL == glyphs) {
518 switch (this->getTextEncoding()) {
519 case kUTF8_TextEncoding:
520 return SkUTF8_CountUnichars((const char*)textData, byteLength);
521 case kUTF16_TextEncoding:
522 return SkUTF16_CountUnichars((const uint16_t*)textData,
524 case kUTF32_TextEncoding:
525 return byteLength >> 2;
526 case kGlyphID_TextEncoding:
527 return byteLength >> 1;
529 SkDEBUGFAIL("unknown text encoding");
534 // if we get here, we have a valid glyphs[] array, so time to fill it in
536 // handle this encoding before the setup for the glyphcache
537 if (this->getTextEncoding() == kGlyphID_TextEncoding) {
538 // we want to ignore the low bit of byteLength
539 memcpy(glyphs, textData, byteLength >> 1 << 1);
540 return byteLength >> 1;
543 SkAutoGlyphCache autoCache(*this, NULL, NULL);
544 SkGlyphCache* cache = autoCache.getCache();
546 const char* text = (const char*)textData;
547 const char* stop = text + byteLength;
548 uint16_t* gptr = glyphs;
550 switch (this->getTextEncoding()) {
551 case SkPaint::kUTF8_TextEncoding:
552 while (text < stop) {
553 *gptr++ = cache->unicharToGlyph(SkUTF8_NextUnichar(&text));
556 case SkPaint::kUTF16_TextEncoding: {
557 const uint16_t* text16 = (const uint16_t*)text;
558 const uint16_t* stop16 = (const uint16_t*)stop;
559 while (text16 < stop16) {
560 *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16));
564 case kUTF32_TextEncoding: {
565 const int32_t* text32 = (const int32_t*)text;
566 const int32_t* stop32 = (const int32_t*)stop;
567 while (text32 < stop32) {
568 *gptr++ = cache->unicharToGlyph(*text32++);
573 SkDEBUGFAIL("unknown text encoding");
575 return gptr - glyphs;
578 bool SkPaint::containsText(const void* textData, size_t byteLength) const {
579 if (0 == byteLength) {
583 SkASSERT(textData != NULL);
585 // handle this encoding before the setup for the glyphcache
586 if (this->getTextEncoding() == kGlyphID_TextEncoding) {
587 const uint16_t* glyphID = static_cast<const uint16_t*>(textData);
588 size_t count = byteLength >> 1;
589 for (size_t i = 0; i < count; i++) {
590 if (0 == glyphID[i]) {
597 SkAutoGlyphCache autoCache(*this, NULL, NULL);
598 SkGlyphCache* cache = autoCache.getCache();
600 switch (this->getTextEncoding()) {
601 case SkPaint::kUTF8_TextEncoding: {
602 const char* text = static_cast<const char*>(textData);
603 const char* stop = text + byteLength;
604 while (text < stop) {
605 if (0 == cache->unicharToGlyph(SkUTF8_NextUnichar(&text))) {
611 case SkPaint::kUTF16_TextEncoding: {
612 const uint16_t* text = static_cast<const uint16_t*>(textData);
613 const uint16_t* stop = text + (byteLength >> 1);
614 while (text < stop) {
615 if (0 == cache->unicharToGlyph(SkUTF16_NextUnichar(&text))) {
621 case SkPaint::kUTF32_TextEncoding: {
622 const int32_t* text = static_cast<const int32_t*>(textData);
623 const int32_t* stop = text + (byteLength >> 2);
624 while (text < stop) {
625 if (0 == cache->unicharToGlyph(*text++)) {
632 SkDEBUGFAIL("unknown text encoding");
638 void SkPaint::glyphsToUnichars(const uint16_t glyphs[], int count,
639 SkUnichar textData[]) const {
644 SkASSERT(glyphs != NULL);
645 SkASSERT(textData != NULL);
647 SkAutoGlyphCache autoCache(*this, NULL, NULL);
648 SkGlyphCache* cache = autoCache.getCache();
650 for (int index = 0; index < count; index++) {
651 textData[index] = cache->glyphToUnichar(glyphs[index]);
655 ///////////////////////////////////////////////////////////////////////////////
657 static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache,
659 SkASSERT(cache != NULL);
660 SkASSERT(text != NULL);
662 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text));
665 static const SkGlyph& sk_getMetrics_utf8_prev(SkGlyphCache* cache,
667 SkASSERT(cache != NULL);
668 SkASSERT(text != NULL);
670 return cache->getUnicharMetrics(SkUTF8_PrevUnichar(text));
673 static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache,
675 SkASSERT(cache != NULL);
676 SkASSERT(text != NULL);
678 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text));
681 static const SkGlyph& sk_getMetrics_utf16_prev(SkGlyphCache* cache,
683 SkASSERT(cache != NULL);
684 SkASSERT(text != NULL);
686 return cache->getUnicharMetrics(SkUTF16_PrevUnichar((const uint16_t**)text));
689 static const SkGlyph& sk_getMetrics_utf32_next(SkGlyphCache* cache,
691 SkASSERT(cache != NULL);
692 SkASSERT(text != NULL);
694 const int32_t* ptr = *(const int32_t**)text;
695 SkUnichar uni = *ptr++;
696 *text = (const char*)ptr;
697 return cache->getUnicharMetrics(uni);
700 static const SkGlyph& sk_getMetrics_utf32_prev(SkGlyphCache* cache,
702 SkASSERT(cache != NULL);
703 SkASSERT(text != NULL);
705 const int32_t* ptr = *(const int32_t**)text;
706 SkUnichar uni = *--ptr;
707 *text = (const char*)ptr;
708 return cache->getUnicharMetrics(uni);
711 static const SkGlyph& sk_getMetrics_glyph_next(SkGlyphCache* cache,
713 SkASSERT(cache != NULL);
714 SkASSERT(text != NULL);
716 const uint16_t* ptr = *(const uint16_t**)text;
717 unsigned glyphID = *ptr;
719 *text = (const char*)ptr;
720 return cache->getGlyphIDMetrics(glyphID);
723 static const SkGlyph& sk_getMetrics_glyph_prev(SkGlyphCache* cache,
725 SkASSERT(cache != NULL);
726 SkASSERT(text != NULL);
728 const uint16_t* ptr = *(const uint16_t**)text;
730 unsigned glyphID = *ptr;
731 *text = (const char*)ptr;
732 return cache->getGlyphIDMetrics(glyphID);
735 static const SkGlyph& sk_getAdvance_utf8_next(SkGlyphCache* cache,
737 SkASSERT(cache != NULL);
738 SkASSERT(text != NULL);
740 return cache->getUnicharAdvance(SkUTF8_NextUnichar(text));
743 static const SkGlyph& sk_getAdvance_utf8_prev(SkGlyphCache* cache,
745 SkASSERT(cache != NULL);
746 SkASSERT(text != NULL);
748 return cache->getUnicharAdvance(SkUTF8_PrevUnichar(text));
751 static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache,
753 SkASSERT(cache != NULL);
754 SkASSERT(text != NULL);
756 return cache->getUnicharAdvance(SkUTF16_NextUnichar((const uint16_t**)text));
759 static const SkGlyph& sk_getAdvance_utf16_prev(SkGlyphCache* cache,
761 SkASSERT(cache != NULL);
762 SkASSERT(text != NULL);
764 return cache->getUnicharAdvance(SkUTF16_PrevUnichar((const uint16_t**)text));
767 static const SkGlyph& sk_getAdvance_utf32_next(SkGlyphCache* cache,
769 SkASSERT(cache != NULL);
770 SkASSERT(text != NULL);
772 const int32_t* ptr = *(const int32_t**)text;
773 SkUnichar uni = *ptr++;
774 *text = (const char*)ptr;
775 return cache->getUnicharAdvance(uni);
778 static const SkGlyph& sk_getAdvance_utf32_prev(SkGlyphCache* cache,
780 SkASSERT(cache != NULL);
781 SkASSERT(text != NULL);
783 const int32_t* ptr = *(const int32_t**)text;
784 SkUnichar uni = *--ptr;
785 *text = (const char*)ptr;
786 return cache->getUnicharAdvance(uni);
789 static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache,
791 SkASSERT(cache != NULL);
792 SkASSERT(text != NULL);
794 const uint16_t* ptr = *(const uint16_t**)text;
795 unsigned glyphID = *ptr;
797 *text = (const char*)ptr;
798 return cache->getGlyphIDAdvance(glyphID);
801 static const SkGlyph& sk_getAdvance_glyph_prev(SkGlyphCache* cache,
803 SkASSERT(cache != NULL);
804 SkASSERT(text != NULL);
806 const uint16_t* ptr = *(const uint16_t**)text;
808 unsigned glyphID = *ptr;
809 *text = (const char*)ptr;
810 return cache->getGlyphIDAdvance(glyphID);
813 SkMeasureCacheProc SkPaint::getMeasureCacheProc(TextBufferDirection tbd,
814 bool needFullMetrics) const {
815 static const SkMeasureCacheProc gMeasureCacheProcs[] = {
816 sk_getMetrics_utf8_next,
817 sk_getMetrics_utf16_next,
818 sk_getMetrics_utf32_next,
819 sk_getMetrics_glyph_next,
821 sk_getMetrics_utf8_prev,
822 sk_getMetrics_utf16_prev,
823 sk_getMetrics_utf32_prev,
824 sk_getMetrics_glyph_prev,
826 sk_getAdvance_utf8_next,
827 sk_getAdvance_utf16_next,
828 sk_getAdvance_utf32_next,
829 sk_getAdvance_glyph_next,
831 sk_getAdvance_utf8_prev,
832 sk_getAdvance_utf16_prev,
833 sk_getAdvance_utf32_prev,
834 sk_getAdvance_glyph_prev
837 unsigned index = this->getTextEncoding();
839 if (kBackward_TextBufferDirection == tbd) {
842 if (!needFullMetrics && !this->isDevKernText()) {
846 SkASSERT(index < SK_ARRAY_COUNT(gMeasureCacheProcs));
847 return gMeasureCacheProcs[index];
850 ///////////////////////////////////////////////////////////////////////////////
852 static const SkGlyph& sk_getMetrics_utf8_00(SkGlyphCache* cache,
853 const char** text, SkFixed, SkFixed) {
854 SkASSERT(cache != NULL);
855 SkASSERT(text != NULL);
857 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text));
860 static const SkGlyph& sk_getMetrics_utf8_xy(SkGlyphCache* cache,
861 const char** text, SkFixed x, SkFixed y) {
862 SkASSERT(cache != NULL);
863 SkASSERT(text != NULL);
865 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text), x, y);
868 static const SkGlyph& sk_getMetrics_utf16_00(SkGlyphCache* cache,
869 const char** text, SkFixed, SkFixed) {
870 SkASSERT(cache != NULL);
871 SkASSERT(text != NULL);
873 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text));
876 static const SkGlyph& sk_getMetrics_utf16_xy(SkGlyphCache* cache,
877 const char** text, SkFixed x, SkFixed y) {
878 SkASSERT(cache != NULL);
879 SkASSERT(text != NULL);
881 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text),
885 static const SkGlyph& sk_getMetrics_utf32_00(SkGlyphCache* cache,
886 const char** text, SkFixed, SkFixed) {
887 SkASSERT(cache != NULL);
888 SkASSERT(text != NULL);
890 const int32_t* ptr = *(const int32_t**)text;
891 SkUnichar uni = *ptr++;
892 *text = (const char*)ptr;
893 return cache->getUnicharMetrics(uni);
896 static const SkGlyph& sk_getMetrics_utf32_xy(SkGlyphCache* cache,
897 const char** text, SkFixed x, SkFixed y) {
898 SkASSERT(cache != NULL);
899 SkASSERT(text != NULL);
901 const int32_t* ptr = *(const int32_t**)text;
902 SkUnichar uni = *--ptr;
903 *text = (const char*)ptr;
904 return cache->getUnicharMetrics(uni, x, y);
907 static const SkGlyph& sk_getMetrics_glyph_00(SkGlyphCache* cache,
908 const char** text, SkFixed, SkFixed) {
909 SkASSERT(cache != NULL);
910 SkASSERT(text != NULL);
912 const uint16_t* ptr = *(const uint16_t**)text;
913 unsigned glyphID = *ptr;
915 *text = (const char*)ptr;
916 return cache->getGlyphIDMetrics(glyphID);
919 static const SkGlyph& sk_getMetrics_glyph_xy(SkGlyphCache* cache,
920 const char** text, SkFixed x, SkFixed y) {
921 SkASSERT(cache != NULL);
922 SkASSERT(text != NULL);
924 const uint16_t* ptr = *(const uint16_t**)text;
925 unsigned glyphID = *ptr;
927 *text = (const char*)ptr;
928 return cache->getGlyphIDMetrics(glyphID, x, y);
931 SkDrawCacheProc SkPaint::getDrawCacheProc() const {
932 static const SkDrawCacheProc gDrawCacheProcs[] = {
933 sk_getMetrics_utf8_00,
934 sk_getMetrics_utf16_00,
935 sk_getMetrics_utf32_00,
936 sk_getMetrics_glyph_00,
938 sk_getMetrics_utf8_xy,
939 sk_getMetrics_utf16_xy,
940 sk_getMetrics_utf32_xy,
941 sk_getMetrics_glyph_xy
944 unsigned index = this->getTextEncoding();
945 if (fFlags & kSubpixelText_Flag) {
949 SkASSERT(index < SK_ARRAY_COUNT(gDrawCacheProcs));
950 return gDrawCacheProcs[index];
953 ///////////////////////////////////////////////////////////////////////////////
955 #define TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE ( \
956 SkPaint::kDevKernText_Flag | \
957 SkPaint::kLinearText_Flag | \
958 SkPaint::kLCDRenderText_Flag | \
959 SkPaint::kEmbeddedBitmapText_Flag | \
960 SkPaint::kAutoHinting_Flag | \
961 SkPaint::kGenA8FromLCD_Flag )
963 SkScalar SkPaint::setupForAsPaths() {
964 uint32_t flags = this->getFlags();
965 // clear the flags we don't care about
966 flags &= ~TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE;
967 // set the flags we do care about
968 flags |= SkPaint::kSubpixelText_Flag;
970 this->setFlags(flags);
971 this->setHinting(SkPaint::kNo_Hinting);
973 SkScalar textSize = fTextSize;
974 this->setTextSize(kCanonicalTextSizeForPaths);
975 return textSize / kCanonicalTextSizeForPaths;
978 class SkCanonicalizePaint {
980 SkCanonicalizePaint(const SkPaint& paint) : fPaint(&paint), fScale(0) {
981 if (paint.isLinearText() || paint.tooBigToUseCache()) {
982 SkPaint* p = fLazy.set(paint);
983 fScale = p->setupForAsPaths();
988 const SkPaint& getPaint() const { return *fPaint; }
991 * Returns 0 if the paint was unmodified, or the scale factor need to
992 * the original textSize
994 SkScalar getScale() const { return fScale; }
997 const SkPaint* fPaint;
999 SkTLazy<SkPaint> fLazy;
1002 static void set_bounds(const SkGlyph& g, SkRect* bounds) {
1003 bounds->set(SkIntToScalar(g.fLeft),
1004 SkIntToScalar(g.fTop),
1005 SkIntToScalar(g.fLeft + g.fWidth),
1006 SkIntToScalar(g.fTop + g.fHeight));
1009 // 64bits wide, with a 16bit bias. Useful when accumulating lots of 16.16 so
1010 // we don't overflow along the way
1011 typedef int64_t Sk48Dot16;
1013 static inline float Sk48Dot16ToScalar(Sk48Dot16 x) {
1014 return (float) (x * 1.5258789e-5); // x * (1 / 65536.0f)
1017 static void join_bounds_x(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) {
1018 SkScalar sx = Sk48Dot16ToScalar(dx);
1019 bounds->join(SkIntToScalar(g.fLeft) + sx,
1020 SkIntToScalar(g.fTop),
1021 SkIntToScalar(g.fLeft + g.fWidth) + sx,
1022 SkIntToScalar(g.fTop + g.fHeight));
1025 static void join_bounds_y(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dy) {
1026 SkScalar sy = Sk48Dot16ToScalar(dy);
1027 bounds->join(SkIntToScalar(g.fLeft),
1028 SkIntToScalar(g.fTop) + sy,
1029 SkIntToScalar(g.fLeft + g.fWidth),
1030 SkIntToScalar(g.fTop + g.fHeight) + sy);
1033 typedef void (*JoinBoundsProc)(const SkGlyph&, SkRect*, Sk48Dot16);
1035 // xyIndex is 0 for fAdvanceX or 1 for fAdvanceY
1036 static SkFixed advance(const SkGlyph& glyph, int xyIndex) {
1037 SkASSERT(0 == xyIndex || 1 == xyIndex);
1038 return (&glyph.fAdvanceX)[xyIndex];
1041 SkScalar SkPaint::measure_text(SkGlyphCache* cache,
1042 const char* text, size_t byteLength,
1043 int* count, SkRect* bounds) const {
1045 if (byteLength == 0) {
1053 SkMeasureCacheProc glyphCacheProc;
1054 glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection,
1058 JoinBoundsProc joinBoundsProc;
1059 if (this->isVerticalText()) {
1061 joinBoundsProc = join_bounds_y;
1064 joinBoundsProc = join_bounds_x;
1068 const char* stop = (const char*)text + byteLength;
1069 const SkGlyph* g = &glyphCacheProc(cache, &text);
1070 // our accumulated fixed-point advances might overflow 16.16, so we use
1071 // a 48.16 (64bit) accumulator, and then convert that to scalar at the
1073 Sk48Dot16 x = advance(*g, xyIndex);
1075 SkAutoKern autokern;
1077 if (NULL == bounds) {
1078 if (this->isDevKernText()) {
1080 for (; text < stop; n++) {
1082 g = &glyphCacheProc(cache, &text);
1083 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + advance(*g, xyIndex);
1086 for (; text < stop; n++) {
1087 x += advance(glyphCacheProc(cache, &text), xyIndex);
1091 set_bounds(*g, bounds);
1092 if (this->isDevKernText()) {
1094 for (; text < stop; n++) {
1096 g = &glyphCacheProc(cache, &text);
1097 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta);
1098 joinBoundsProc(*g, bounds, x);
1099 x += advance(*g, xyIndex);
1102 for (; text < stop; n++) {
1103 g = &glyphCacheProc(cache, &text);
1104 joinBoundsProc(*g, bounds, x);
1105 x += advance(*g, xyIndex);
1109 SkASSERT(text == stop);
1112 return Sk48Dot16ToScalar(x);
1115 SkScalar SkPaint::measureText(const void* textData, size_t length,
1116 SkRect* bounds, SkScalar zoom) const {
1117 const char* text = (const char*)textData;
1118 SkASSERT(text != NULL || length == 0);
1120 SkCanonicalizePaint canon(*this);
1121 const SkPaint& paint = canon.getPaint();
1122 SkScalar scale = canon.getScale();
1124 SkMatrix zoomMatrix, *zoomPtr = NULL;
1126 zoomMatrix.setScale(zoom, zoom);
1127 zoomPtr = &zoomMatrix;
1130 SkAutoGlyphCache autoCache(paint, NULL, zoomPtr);
1131 SkGlyphCache* cache = autoCache.getCache();
1138 width = paint.measure_text(cache, text, length, &tempCount, bounds);
1140 width = SkScalarMul(width, scale);
1142 bounds->fLeft = SkScalarMul(bounds->fLeft, scale);
1143 bounds->fTop = SkScalarMul(bounds->fTop, scale);
1144 bounds->fRight = SkScalarMul(bounds->fRight, scale);
1145 bounds->fBottom = SkScalarMul(bounds->fBottom, scale);
1148 } else if (bounds) {
1149 // ensure that even if we don't measure_text we still update the bounds
1155 typedef bool (*SkTextBufferPred)(const char* text, const char* stop);
1157 static bool forward_textBufferPred(const char* text, const char* stop) {
1161 static bool backward_textBufferPred(const char* text, const char* stop) {
1165 static SkTextBufferPred chooseTextBufferPred(SkPaint::TextBufferDirection tbd,
1166 const char** text, size_t length,
1167 const char** stop) {
1168 if (SkPaint::kForward_TextBufferDirection == tbd) {
1169 *stop = *text + length;
1170 return forward_textBufferPred;
1172 // text should point to the end of the buffer, and stop to the beginning
1175 return backward_textBufferPred;
1179 size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
1180 SkScalar* measuredWidth,
1181 TextBufferDirection tbd) const {
1182 if (0 == length || 0 >= maxWidth) {
1183 if (measuredWidth) {
1189 if (0 == fTextSize) {
1190 if (measuredWidth) {
1196 SkASSERT(textD != NULL);
1197 const char* text = (const char*)textD;
1199 SkCanonicalizePaint canon(*this);
1200 const SkPaint& paint = canon.getPaint();
1201 SkScalar scale = canon.getScale();
1203 // adjust max in case we changed the textSize in paint
1208 SkAutoGlyphCache autoCache(paint, NULL, NULL);
1209 SkGlyphCache* cache = autoCache.getCache();
1211 SkMeasureCacheProc glyphCacheProc = paint.getMeasureCacheProc(tbd, false);
1213 SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &stop);
1214 const int xyIndex = paint.isVerticalText() ? 1 : 0;
1215 // use 64bits for our accumulator, to avoid overflowing 16.16
1216 Sk48Dot16 max = SkScalarToFixed(maxWidth);
1217 Sk48Dot16 width = 0;
1219 SkAutoKern autokern;
1221 if (this->isDevKernText()) {
1223 while (pred(text, stop)) {
1224 const char* curr = text;
1225 const SkGlyph& g = glyphCacheProc(cache, &text);
1226 SkFixed x = SkAutoKern_AdjustF(rsb, g.fLsbDelta) + advance(g, xyIndex);
1227 if ((width += x) > max) {
1235 while (pred(text, stop)) {
1236 const char* curr = text;
1237 SkFixed x = advance(glyphCacheProc(cache, &text), xyIndex);
1238 if ((width += x) > max) {
1246 if (measuredWidth) {
1247 SkScalar scalarWidth = Sk48Dot16ToScalar(width);
1249 scalarWidth = SkScalarMul(scalarWidth, scale);
1251 *measuredWidth = scalarWidth;
1254 // return the number of bytes measured
1255 return (kForward_TextBufferDirection == tbd) ?
1256 text - stop + length : stop - text + length;
1259 ///////////////////////////////////////////////////////////////////////////////
1261 static bool FontMetricsCacheProc(const SkGlyphCache* cache, void* context) {
1262 *(SkPaint::FontMetrics*)context = cache->getFontMetrics();
1263 return false; // don't detach the cache
1266 static void FontMetricsDescProc(SkTypeface* typeface, const SkDescriptor* desc,
1268 SkGlyphCache::VisitCache(typeface, desc, FontMetricsCacheProc, context);
1271 SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const {
1272 SkCanonicalizePaint canon(*this);
1273 const SkPaint& paint = canon.getPaint();
1274 SkScalar scale = canon.getScale();
1276 SkMatrix zoomMatrix, *zoomPtr = NULL;
1278 zoomMatrix.setScale(zoom, zoom);
1279 zoomPtr = &zoomMatrix;
1282 FontMetrics storage;
1283 if (NULL == metrics) {
1287 paint.descriptorProc(NULL, zoomPtr, FontMetricsDescProc, metrics, true);
1290 metrics->fTop = SkScalarMul(metrics->fTop, scale);
1291 metrics->fAscent = SkScalarMul(metrics->fAscent, scale);
1292 metrics->fDescent = SkScalarMul(metrics->fDescent, scale);
1293 metrics->fBottom = SkScalarMul(metrics->fBottom, scale);
1294 metrics->fLeading = SkScalarMul(metrics->fLeading, scale);
1295 metrics->fAvgCharWidth = SkScalarMul(metrics->fAvgCharWidth, scale);
1296 metrics->fXMin = SkScalarMul(metrics->fXMin, scale);
1297 metrics->fXMax = SkScalarMul(metrics->fXMax, scale);
1298 metrics->fXHeight = SkScalarMul(metrics->fXHeight, scale);
1300 return metrics->fDescent - metrics->fAscent + metrics->fLeading;
1303 ///////////////////////////////////////////////////////////////////////////////
1305 static void set_bounds(const SkGlyph& g, SkRect* bounds, SkScalar scale) {
1306 bounds->set(g.fLeft * scale,
1308 (g.fLeft + g.fWidth) * scale,
1309 (g.fTop + g.fHeight) * scale);
1312 int SkPaint::getTextWidths(const void* textData, size_t byteLength,
1313 SkScalar widths[], SkRect bounds[]) const {
1314 if (0 == byteLength) {
1318 SkASSERT(NULL != textData);
1320 if (NULL == widths && NULL == bounds) {
1321 return this->countText(textData, byteLength);
1324 SkCanonicalizePaint canon(*this);
1325 const SkPaint& paint = canon.getPaint();
1326 SkScalar scale = canon.getScale();
1328 SkAutoGlyphCache autoCache(paint, NULL, NULL);
1329 SkGlyphCache* cache = autoCache.getCache();
1330 SkMeasureCacheProc glyphCacheProc;
1331 glyphCacheProc = paint.getMeasureCacheProc(kForward_TextBufferDirection,
1334 const char* text = (const char*)textData;
1335 const char* stop = text + byteLength;
1337 const int xyIndex = paint.isVerticalText() ? 1 : 0;
1339 if (this->isDevKernText()) {
1340 // we adjust the widths returned here through auto-kerning
1341 SkAutoKern autokern;
1342 SkFixed prevWidth = 0;
1345 while (text < stop) {
1346 const SkGlyph& g = glyphCacheProc(cache, &text);
1348 SkFixed adjust = autokern.adjust(g);
1351 SkScalar w = SkFixedToScalar(prevWidth + adjust);
1352 *widths++ = SkScalarMul(w, scale);
1354 prevWidth = advance(g, xyIndex);
1357 set_bounds(g, bounds++, scale);
1361 if (count > 0 && widths) {
1362 *widths = SkScalarMul(SkFixedToScalar(prevWidth), scale);
1365 while (text < stop) {
1366 const SkGlyph& g = glyphCacheProc(cache, &text);
1368 SkFixed adjust = autokern.adjust(g);
1371 *widths++ = SkFixedToScalar(prevWidth + adjust);
1373 prevWidth = advance(g, xyIndex);
1376 set_bounds(g, bounds++);
1380 if (count > 0 && widths) {
1381 *widths = SkFixedToScalar(prevWidth);
1384 } else { // no devkern
1386 while (text < stop) {
1387 const SkGlyph& g = glyphCacheProc(cache, &text);
1389 *widths++ = SkScalarMul(SkFixedToScalar(advance(g, xyIndex)),
1393 set_bounds(g, bounds++, scale);
1398 while (text < stop) {
1399 const SkGlyph& g = glyphCacheProc(cache, &text);
1401 *widths++ = SkFixedToScalar(advance(g, xyIndex));
1404 set_bounds(g, bounds++);
1411 SkASSERT(text == stop);
1415 ///////////////////////////////////////////////////////////////////////////////
1419 void SkPaint::getTextPath(const void* textData, size_t length,
1420 SkScalar x, SkScalar y, SkPath* path) const {
1421 SkASSERT(length == 0 || textData != NULL);
1423 const char* text = (const char*)textData;
1424 if (text == NULL || length == 0 || path == NULL) {
1428 SkTextToPathIter iter(text, length, *this, false);
1430 SkScalar prevXPos = 0;
1432 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1433 matrix.postTranslate(x, y);
1437 const SkPath* iterPath;
1438 while (iter.next(&iterPath, &xpos)) {
1439 matrix.postTranslate(xpos - prevXPos, 0);
1441 path->addPath(*iterPath, matrix);
1447 void SkPaint::getPosTextPath(const void* textData, size_t length,
1448 const SkPoint pos[], SkPath* path) const {
1449 SkASSERT(length == 0 || textData != NULL);
1451 const char* text = (const char*)textData;
1452 if (text == NULL || length == 0 || path == NULL) {
1456 SkTextToPathIter iter(text, length, *this, false);
1461 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1465 const SkPath* iterPath;
1466 while (iter.next(&iterPath, NULL)) {
1467 matrix.postTranslate(pos[i].fX - prevPos.fX, pos[i].fY - prevPos.fY);
1469 path->addPath(*iterPath, matrix);
1476 static void add_flattenable(SkDescriptor* desc, uint32_t tag,
1477 SkWriteBuffer* buffer) {
1478 buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), NULL));
1481 // SkFontHost can override this choice in FilterRec()
1482 static SkMask::Format computeMaskFormat(const SkPaint& paint) {
1483 uint32_t flags = paint.getFlags();
1485 // Antialiasing being disabled trumps all other settings.
1486 if (!(flags & SkPaint::kAntiAlias_Flag)) {
1487 return SkMask::kBW_Format;
1490 if (flags & SkPaint::kLCDRenderText_Flag) {
1491 return SkMask::kLCD16_Format;
1494 return SkMask::kA8_Format;
1497 // if linear-text is on, then we force hinting to be off (since that's sort of
1498 // the point of linear-text.
1499 static SkPaint::Hinting computeHinting(const SkPaint& paint) {
1500 SkPaint::Hinting h = paint.getHinting();
1501 if (paint.isLinearText()) {
1502 h = SkPaint::kNo_Hinting;
1507 // return true if the paint is just a single color (i.e. not a shader). If its
1508 // a shader, then we can't compute a const luminance for it :(
1509 static bool justAColor(const SkPaint& paint, SkColor* color) {
1510 if (paint.getShader()) {
1513 SkColor c = paint.getColor();
1514 if (paint.getColorFilter()) {
1515 c = paint.getColorFilter()->filterColor(c);
1523 static SkColor computeLuminanceColor(const SkPaint& paint) {
1525 if (!justAColor(paint, &c)) {
1526 c = SkColorSetRGB(0x7F, 0x80, 0x7F);
1531 #define assert_byte(x) SkASSERT(0 == ((x) >> 8))
1533 // Beyond this size, LCD doesn't appreciably improve quality, but it always
1534 // cost more RAM and draws slower, so we set a cap.
1535 #ifndef SK_MAX_SIZE_FOR_LCDTEXT
1536 #define SK_MAX_SIZE_FOR_LCDTEXT 48
1539 static bool tooBigForLCD(const SkScalerContext::Rec& rec) {
1540 SkScalar area = SkScalarMul(rec.fPost2x2[0][0], rec.fPost2x2[1][1]) -
1541 SkScalarMul(rec.fPost2x2[1][0], rec.fPost2x2[0][1]);
1542 SkScalar size = SkScalarMul(area, rec.fTextSize);
1543 return SkScalarAbs(size) > SkIntToScalar(SK_MAX_SIZE_FOR_LCDTEXT);
1547 * Return the scalar with only limited fractional precision. Used to consolidate matrices
1548 * that vary only slightly when we create our key into the font cache, since the font scaler
1549 * typically returns the same looking resuts for tiny changes in the matrix.
1551 static SkScalar sk_relax(SkScalar x) {
1552 int n = sk_float_round2int(x * 1024);
1556 void SkScalerContext::MakeRec(const SkPaint& paint,
1557 const SkDeviceProperties* deviceProperties,
1558 const SkMatrix* deviceMatrix,
1560 SkASSERT(deviceMatrix == NULL || !deviceMatrix->hasPerspective());
1562 SkTypeface* typeface = paint.getTypeface();
1563 if (NULL == typeface) {
1564 typeface = SkTypeface::GetDefaultTypeface();
1566 rec->fOrigFontID = typeface->uniqueID();
1567 rec->fFontID = rec->fOrigFontID;
1568 rec->fTextSize = paint.getTextSize();
1569 rec->fPreScaleX = paint.getTextScaleX();
1570 rec->fPreSkewX = paint.getTextSkewX();
1573 rec->fPost2x2[0][0] = sk_relax(deviceMatrix->getScaleX());
1574 rec->fPost2x2[0][1] = sk_relax(deviceMatrix->getSkewX());
1575 rec->fPost2x2[1][0] = sk_relax(deviceMatrix->getSkewY());
1576 rec->fPost2x2[1][1] = sk_relax(deviceMatrix->getScaleY());
1578 rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1;
1579 rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0;
1582 SkPaint::Style style = paint.getStyle();
1583 SkScalar strokeWidth = paint.getStrokeWidth();
1587 if (paint.isFakeBoldText()) {
1588 #ifdef SK_USE_FREETYPE_EMBOLDEN
1589 flags |= SkScalerContext::kEmbolden_Flag;
1591 SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(),
1592 kStdFakeBoldInterpKeys,
1593 kStdFakeBoldInterpValues,
1594 kStdFakeBoldInterpLength);
1595 SkScalar extra = SkScalarMul(paint.getTextSize(), fakeBoldScale);
1597 if (style == SkPaint::kFill_Style) {
1598 style = SkPaint::kStrokeAndFill_Style;
1599 strokeWidth = extra; // ignore paint's strokeWidth if it was "fill"
1601 strokeWidth += extra;
1606 if (paint.isDevKernText()) {
1607 flags |= SkScalerContext::kDevKernText_Flag;
1610 if (style != SkPaint::kFill_Style && strokeWidth > 0) {
1611 rec->fFrameWidth = strokeWidth;
1612 rec->fMiterLimit = paint.getStrokeMiter();
1613 rec->fStrokeJoin = SkToU8(paint.getStrokeJoin());
1615 if (style == SkPaint::kStrokeAndFill_Style) {
1616 flags |= SkScalerContext::kFrameAndFill_Flag;
1619 rec->fFrameWidth = 0;
1620 rec->fMiterLimit = 0;
1621 rec->fStrokeJoin = 0;
1624 rec->fMaskFormat = SkToU8(computeMaskFormat(paint));
1626 SkDeviceProperties::Geometry geometry = deviceProperties
1627 ? deviceProperties->fGeometry
1628 : SkDeviceProperties::Geometry::MakeDefault();
1629 if (SkMask::kLCD16_Format == rec->fMaskFormat || SkMask::kLCD32_Format == rec->fMaskFormat) {
1630 if (!geometry.isOrientationKnown() || !geometry.isLayoutKnown() || tooBigForLCD(*rec)) {
1631 // eeek, can't support LCD
1632 rec->fMaskFormat = SkMask::kA8_Format;
1634 if (SkDeviceProperties::Geometry::kVertical_Orientation == geometry.getOrientation()) {
1635 flags |= SkScalerContext::kLCD_Vertical_Flag;
1637 if (SkDeviceProperties::Geometry::kBGR_Layout == geometry.getLayout()) {
1638 flags |= SkScalerContext::kLCD_BGROrder_Flag;
1643 if (paint.isEmbeddedBitmapText()) {
1644 flags |= SkScalerContext::kEmbeddedBitmapText_Flag;
1646 if (paint.isSubpixelText()) {
1647 flags |= SkScalerContext::kSubpixelPositioning_Flag;
1649 if (paint.isAutohinted()) {
1650 flags |= SkScalerContext::kForceAutohinting_Flag;
1652 if (paint.isVerticalText()) {
1653 flags |= SkScalerContext::kVertical_Flag;
1655 if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) {
1656 flags |= SkScalerContext::kGenA8FromLCD_Flag;
1658 rec->fFlags = SkToU16(flags);
1660 // these modify fFlags, so do them after assigning fFlags
1661 rec->setHinting(computeHinting(paint));
1663 rec->setLuminanceColor(computeLuminanceColor(paint));
1665 if (NULL == deviceProperties) {
1666 rec->setDeviceGamma(SK_GAMMA_EXPONENT);
1667 rec->setPaintGamma(SK_GAMMA_EXPONENT);
1669 rec->setDeviceGamma(deviceProperties->fGamma);
1671 //For now always set the paint gamma equal to the device gamma.
1672 //The math in SkMaskGamma can handle them being different,
1673 //but it requires superluminous masks when
1674 //Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large.
1675 rec->setPaintGamma(deviceProperties->fGamma);
1678 #ifdef SK_GAMMA_CONTRAST
1679 rec->setContrast(SK_GAMMA_CONTRAST);
1682 * A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise.
1683 * With lower values small text appears washed out (though correctly so).
1684 * With higher values lcd fringing is worse and the smoothing effect of
1685 * partial coverage is diminished.
1687 rec->setContrast(0.5f);
1690 rec->fReservedAlign = 0;
1692 /* Allow the fonthost to modify our rec before we use it as a key into the
1693 cache. This way if we're asking for something that they will ignore,
1694 they can modify our rec up front, so we don't create duplicate cache
1697 typeface->onFilterRec(rec);
1699 // be sure to call PostMakeRec(rec) before you actually use it!
1703 * In order to call cachedDeviceLuminance, cachedPaintLuminance, or
1704 * cachedMaskGamma the caller must hold the gMaskGammaCacheMutex and continue
1705 * to hold it until the returned pointer is refed or forgotten.
1707 SK_DECLARE_STATIC_MUTEX(gMaskGammaCacheMutex);
1709 static SkMaskGamma* gLinearMaskGamma = NULL;
1710 static SkMaskGamma* gMaskGamma = NULL;
1711 static SkScalar gContrast = SK_ScalarMin;
1712 static SkScalar gPaintGamma = SK_ScalarMin;
1713 static SkScalar gDeviceGamma = SK_ScalarMin;
1715 * The caller must hold the gMaskGammaCacheMutex and continue to hold it until
1716 * the returned SkMaskGamma pointer is refed or forgotten.
1718 static const SkMaskGamma& cachedMaskGamma(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma) {
1719 if (0 == contrast && SK_Scalar1 == paintGamma && SK_Scalar1 == deviceGamma) {
1720 if (NULL == gLinearMaskGamma) {
1721 gLinearMaskGamma = SkNEW(SkMaskGamma);
1723 return *gLinearMaskGamma;
1725 if (gContrast != contrast || gPaintGamma != paintGamma || gDeviceGamma != deviceGamma) {
1726 SkSafeUnref(gMaskGamma);
1727 gMaskGamma = SkNEW_ARGS(SkMaskGamma, (contrast, paintGamma, deviceGamma));
1728 gContrast = contrast;
1729 gPaintGamma = paintGamma;
1730 gDeviceGamma = deviceGamma;
1735 /*static*/ void SkPaint::Term() {
1736 SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
1738 SkSafeUnref(gLinearMaskGamma);
1739 gLinearMaskGamma = NULL;
1740 SkSafeUnref(gMaskGamma);
1742 SkDEBUGCODE(gContrast = SK_ScalarMin;)
1743 SkDEBUGCODE(gPaintGamma = SK_ScalarMin;)
1744 SkDEBUGCODE(gDeviceGamma = SK_ScalarMin;)
1748 * We ensure that the rec is self-consistent and efficient (where possible)
1750 void SkScalerContext::PostMakeRec(const SkPaint&, SkScalerContext::Rec* rec) {
1752 * If we're asking for A8, we force the colorlum to be gray, since that
1753 * limits the number of unique entries, and the scaler will only look at
1754 * the lum of one of them.
1756 switch (rec->fMaskFormat) {
1757 case SkMask::kLCD16_Format:
1758 case SkMask::kLCD32_Format: {
1759 // filter down the luminance color to a finite number of bits
1760 SkColor color = rec->getLuminanceColor();
1761 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color));
1764 case SkMask::kA8_Format: {
1765 // filter down the luminance to a single component, since A8 can't
1766 // use per-component information
1768 SkColor color = rec->getLuminanceColor();
1769 U8CPU lum = SkColorSpaceLuminance::computeLuminance(rec->getPaintGamma(), color);
1770 //If we are asked to look like LCD, look like LCD.
1771 if (!(rec->fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1772 // HACK: Prevents green from being pre-blended as white.
1773 lum -= ((255 - lum) * lum) / 255;
1776 // reduce to our finite number of bits
1777 color = SkColorSetRGB(lum, lum, lum);
1778 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color));
1781 case SkMask::kBW_Format:
1782 // No need to differentiate gamma if we're BW
1783 rec->ignorePreBlend();
1788 #define MIN_SIZE_FOR_EFFECT_BUFFER 1024
1795 * ignoreGamma tells us that the caller just wants metrics that are unaffected
1796 * by gamma correction, so we jam the luminance field to 0 (most common value
1797 * for black text) in hopes that we get a cache hit easier. A better solution
1798 * would be for the fontcache lookup to know to ignore the luminance field
1799 * entirely, but not sure how to do that and keep it fast.
1801 void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties,
1802 const SkMatrix* deviceMatrix,
1803 void (*proc)(SkTypeface*, const SkDescriptor*, void*),
1804 void* context, bool ignoreGamma) const {
1805 SkScalerContext::Rec rec;
1807 SkScalerContext::MakeRec(*this, deviceProperties, deviceMatrix, &rec);
1809 rec.setLuminanceColor(0);
1812 size_t descSize = sizeof(rec);
1814 SkPathEffect* pe = this->getPathEffect();
1815 SkMaskFilter* mf = this->getMaskFilter();
1816 SkRasterizer* ra = this->getRasterizer();
1818 SkWriteBuffer peBuffer, mfBuffer, raBuffer;
1821 peBuffer.writeFlattenable(pe);
1822 descSize += peBuffer.bytesWritten();
1824 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion
1825 // seems like we could support kLCD as well at this point...
1828 mfBuffer.writeFlattenable(mf);
1829 descSize += mfBuffer.bytesWritten();
1831 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing with maskfilters
1832 /* Pre-blend is not currently applied to filtered text.
1833 The primary filter is blur, for which contrast makes no sense,
1834 and for which the destination guess error is more visible.
1835 Also, all existing users of blur have calibrated for linear. */
1836 rec.ignorePreBlend();
1839 raBuffer.writeFlattenable(ra);
1840 descSize += raBuffer.bytesWritten();
1842 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion
1845 #ifdef SK_BUILD_FOR_ANDROID
1846 SkWriteBuffer androidBuffer;
1847 fPaintOptionsAndroid.flatten(androidBuffer);
1848 descSize += androidBuffer.bytesWritten();
1852 ///////////////////////////////////////////////////////////////////////////
1853 // Now that we're done tweaking the rec, call the PostMakeRec cleanup
1854 SkScalerContext::PostMakeRec(*this, &rec);
1856 descSize += SkDescriptor::ComputeOverhead(entryCount);
1858 SkAutoDescriptor ad(descSize);
1859 SkDescriptor* desc = ad.getDesc();
1862 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
1864 #ifdef SK_BUILD_FOR_ANDROID
1865 add_flattenable(desc, kAndroidOpts_SkDescriptorTag, &androidBuffer);
1869 add_flattenable(desc, kPathEffect_SkDescriptorTag, &peBuffer);
1872 add_flattenable(desc, kMaskFilter_SkDescriptorTag, &mfBuffer);
1875 add_flattenable(desc, kRasterizer_SkDescriptorTag, &raBuffer);
1878 SkASSERT(descSize == desc->getLength());
1879 desc->computeChecksum();
1883 // Check that we completely write the bytes in desc (our key), and that
1884 // there are no uninitialized bytes. If there were, then we would get
1885 // false-misses (or worse, false-hits) in our fontcache.
1887 // We do this buy filling 2 others, one with 0s and the other with 1s
1888 // and create those, and then check that all 3 are identical.
1889 SkAutoDescriptor ad1(descSize);
1890 SkAutoDescriptor ad2(descSize);
1891 SkDescriptor* desc1 = ad1.getDesc();
1892 SkDescriptor* desc2 = ad2.getDesc();
1894 memset(desc1, 0x00, descSize);
1895 memset(desc2, 0xFF, descSize);
1899 desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
1900 desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
1902 #ifdef SK_BUILD_FOR_ANDROID
1903 add_flattenable(desc1, kAndroidOpts_SkDescriptorTag, &androidBuffer);
1904 add_flattenable(desc2, kAndroidOpts_SkDescriptorTag, &androidBuffer);
1908 add_flattenable(desc1, kPathEffect_SkDescriptorTag, &peBuffer);
1909 add_flattenable(desc2, kPathEffect_SkDescriptorTag, &peBuffer);
1912 add_flattenable(desc1, kMaskFilter_SkDescriptorTag, &mfBuffer);
1913 add_flattenable(desc2, kMaskFilter_SkDescriptorTag, &mfBuffer);
1916 add_flattenable(desc1, kRasterizer_SkDescriptorTag, &raBuffer);
1917 add_flattenable(desc2, kRasterizer_SkDescriptorTag, &raBuffer);
1920 SkASSERT(descSize == desc1->getLength());
1921 SkASSERT(descSize == desc2->getLength());
1922 desc1->computeChecksum();
1923 desc2->computeChecksum();
1924 SkASSERT(!memcmp(desc, desc1, descSize));
1925 SkASSERT(!memcmp(desc, desc2, descSize));
1929 proc(fTypeface, desc, context);
1932 SkGlyphCache* SkPaint::detachCache(const SkDeviceProperties* deviceProperties,
1933 const SkMatrix* deviceMatrix) const {
1934 SkGlyphCache* cache;
1935 this->descriptorProc(deviceProperties, deviceMatrix, DetachDescProc, &cache, false);
1940 * Expands fDeviceGamma, fPaintGamma, fContrast, and fLumBits into a mask pre-blend.
1943 SkMaskGamma::PreBlend SkScalerContext::GetMaskPreBlend(const SkScalerContext::Rec& rec) {
1944 SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
1945 const SkMaskGamma& maskGamma = cachedMaskGamma(rec.getContrast(),
1946 rec.getPaintGamma(),
1947 rec.getDeviceGamma());
1948 return maskGamma.preBlend(rec.getLuminanceColor());
1951 ///////////////////////////////////////////////////////////////////////////////
1953 #include "SkStream.h"
1955 static uintptr_t asint(const void* p) {
1956 return reinterpret_cast<uintptr_t>(p);
1964 static uint32_t* write_scalar(uint32_t* ptr, SkScalar value) {
1965 SkASSERT(sizeof(SkScalar) == sizeof(uint32_t));
1967 tmp.fScalar = value;
1972 static SkScalar read_scalar(const uint32_t*& ptr) {
1973 SkASSERT(sizeof(SkScalar) == sizeof(uint32_t));
1979 static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) {
1980 SkASSERT(a == (uint8_t)a);
1981 SkASSERT(b == (uint8_t)b);
1982 SkASSERT(c == (uint8_t)c);
1983 SkASSERT(d == (uint8_t)d);
1984 return (a << 24) | (b << 16) | (c << 8) | d;
1988 kHasTypeface_FlatFlag = 0x01,
1989 kHasEffects_FlatFlag = 0x02,
1990 kHasNonDefaultPaintOptionsAndroid_FlatFlag = 0x04,
1993 // The size of a flat paint's POD fields
1994 static const uint32_t kPODPaintSize = 5 * sizeof(SkScalar) +
1995 1 * sizeof(SkColor) +
1996 1 * sizeof(uint16_t) +
1997 6 * sizeof(uint8_t);
1999 /* To save space/time, we analyze the paint, and write a truncated version of
2000 it if there are not tricky elements like shaders, etc.
2002 void SkPaint::flatten(SkWriteBuffer& buffer) const {
2003 uint8_t flatFlags = 0;
2004 if (this->getTypeface()) {
2005 flatFlags |= kHasTypeface_FlatFlag;
2007 if (asint(this->getPathEffect()) |
2008 asint(this->getShader()) |
2009 asint(this->getXfermode()) |
2010 asint(this->getMaskFilter()) |
2011 asint(this->getColorFilter()) |
2012 asint(this->getRasterizer()) |
2013 asint(this->getLooper()) |
2014 asint(this->getAnnotation()) |
2015 asint(this->getImageFilter())) {
2016 flatFlags |= kHasEffects_FlatFlag;
2018 #ifdef SK_BUILD_FOR_ANDROID
2019 if (this->getPaintOptionsAndroid() != SkPaintOptionsAndroid()) {
2020 flatFlags |= kHasNonDefaultPaintOptionsAndroid_FlatFlag;
2024 SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize);
2025 uint32_t* ptr = buffer.reserve(kPODPaintSize);
2027 ptr = write_scalar(ptr, this->getTextSize());
2028 ptr = write_scalar(ptr, this->getTextScaleX());
2029 ptr = write_scalar(ptr, this->getTextSkewX());
2030 ptr = write_scalar(ptr, this->getStrokeWidth());
2031 ptr = write_scalar(ptr, this->getStrokeMiter());
2032 *ptr++ = this->getColor();
2033 // previously flags:16, textAlign:8, flatFlags:8
2034 // now flags:16, hinting:4, textAlign:4, flatFlags:8
2035 *ptr++ = (this->getFlags() << 16) |
2036 // hinting added later. 0 in this nibble means use the default.
2037 ((this->getHinting()+1) << 12) |
2038 (this->getTextAlign() << 8) |
2040 *ptr++ = pack_4(this->getStrokeCap(), this->getStrokeJoin(),
2041 this->getStyle(), this->getTextEncoding());
2043 // now we're done with ptr and the (pre)reserved space. If we need to write
2044 // additional fields, use the buffer directly
2045 if (flatFlags & kHasTypeface_FlatFlag) {
2046 buffer.writeTypeface(this->getTypeface());
2048 if (flatFlags & kHasEffects_FlatFlag) {
2049 buffer.writeFlattenable(this->getPathEffect());
2050 buffer.writeFlattenable(this->getShader());
2051 buffer.writeFlattenable(this->getXfermode());
2052 buffer.writeFlattenable(this->getMaskFilter());
2053 buffer.writeFlattenable(this->getColorFilter());
2054 buffer.writeFlattenable(this->getRasterizer());
2055 buffer.writeFlattenable(this->getLooper());
2056 buffer.writeFlattenable(this->getImageFilter());
2059 buffer.writeBool(true);
2060 fAnnotation->writeToBuffer(buffer);
2062 buffer.writeBool(false);
2065 #ifdef SK_BUILD_FOR_ANDROID
2066 if (flatFlags & kHasNonDefaultPaintOptionsAndroid_FlatFlag) {
2067 this->getPaintOptionsAndroid().flatten(buffer);
2072 void SkPaint::unflatten(SkReadBuffer& buffer) {
2073 uint8_t flatFlags = 0;
2074 SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize);
2075 const void* podData = buffer.skip(kPODPaintSize);
2076 const uint32_t* pod = reinterpret_cast<const uint32_t*>(podData);
2078 // the order we read must match the order we wrote in flatten()
2079 this->setTextSize(read_scalar(pod));
2080 this->setTextScaleX(read_scalar(pod));
2081 this->setTextSkewX(read_scalar(pod));
2082 this->setStrokeWidth(read_scalar(pod));
2083 this->setStrokeMiter(read_scalar(pod));
2084 this->setColor(*pod++);
2086 // previously flags:16, textAlign:8, flatFlags:8
2087 // now flags:16, hinting:4, textAlign:4, flatFlags:8
2088 uint32_t tmp = *pod++;
2089 this->setFlags(tmp >> 16);
2091 // hinting added later. 0 in this nibble means use the default.
2092 uint32_t hinting = (tmp >> 12) & 0xF;
2093 this->setHinting(0 == hinting ? kNormal_Hinting : static_cast<Hinting>(hinting-1));
2095 this->setTextAlign(static_cast<Align>((tmp >> 8) & 0xF));
2097 flatFlags = tmp & 0xFF;
2100 this->setStrokeCap(static_cast<Cap>((tmp >> 24) & 0xFF));
2101 this->setStrokeJoin(static_cast<Join>((tmp >> 16) & 0xFF));
2102 this->setStyle(static_cast<Style>((tmp >> 8) & 0xFF));
2103 this->setTextEncoding(static_cast<TextEncoding>((tmp >> 0) & 0xFF));
2105 if (flatFlags & kHasTypeface_FlatFlag) {
2106 this->setTypeface(buffer.readTypeface());
2108 this->setTypeface(NULL);
2111 if (flatFlags & kHasEffects_FlatFlag) {
2112 SkSafeUnref(this->setPathEffect(buffer.readPathEffect()));
2113 SkSafeUnref(this->setShader(buffer.readShader()));
2114 SkSafeUnref(this->setXfermode(buffer.readXfermode()));
2115 SkSafeUnref(this->setMaskFilter(buffer.readMaskFilter()));
2116 SkSafeUnref(this->setColorFilter(buffer.readColorFilter()));
2117 SkSafeUnref(this->setRasterizer(buffer.readRasterizer()));
2118 SkSafeUnref(this->setLooper(buffer.readDrawLooper()));
2119 SkSafeUnref(this->setImageFilter(buffer.readImageFilter()));
2121 if (buffer.readBool()) {
2122 this->setAnnotation(SkNEW_ARGS(SkAnnotation, (buffer)))->unref();
2125 this->setPathEffect(NULL);
2126 this->setShader(NULL);
2127 this->setXfermode(NULL);
2128 this->setMaskFilter(NULL);
2129 this->setColorFilter(NULL);
2130 this->setRasterizer(NULL);
2131 this->setLooper(NULL);
2132 this->setImageFilter(NULL);
2135 #ifdef SK_BUILD_FOR_ANDROID
2136 this->setPaintOptionsAndroid(SkPaintOptionsAndroid());
2138 if (flatFlags & kHasNonDefaultPaintOptionsAndroid_FlatFlag) {
2139 SkPaintOptionsAndroid options;
2140 options.unflatten(buffer);
2141 #ifdef SK_BUILD_FOR_ANDROID
2142 this->setPaintOptionsAndroid(options);
2147 ///////////////////////////////////////////////////////////////////////////////
2149 SkShader* SkPaint::setShader(SkShader* shader) {
2150 GEN_ID_INC_EVAL(shader != fShader);
2151 SkRefCnt_SafeAssign(fShader, shader);
2155 SkColorFilter* SkPaint::setColorFilter(SkColorFilter* filter) {
2156 GEN_ID_INC_EVAL(filter != fColorFilter);
2157 SkRefCnt_SafeAssign(fColorFilter, filter);
2161 SkXfermode* SkPaint::setXfermode(SkXfermode* mode) {
2162 GEN_ID_INC_EVAL(mode != fXfermode);
2163 SkRefCnt_SafeAssign(fXfermode, mode);
2167 SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) {
2168 SkSafeUnref(fXfermode);
2169 fXfermode = SkXfermode::Create(mode);
2174 SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect) {
2175 GEN_ID_INC_EVAL(effect != fPathEffect);
2176 SkRefCnt_SafeAssign(fPathEffect, effect);
2180 SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter) {
2181 GEN_ID_INC_EVAL(filter != fMaskFilter);
2182 SkRefCnt_SafeAssign(fMaskFilter, filter);
2186 ///////////////////////////////////////////////////////////////////////////////
2188 bool SkPaint::getFillPath(const SkPath& src, SkPath* dst,
2189 const SkRect* cullRect) const {
2190 SkStrokeRec rec(*this);
2192 const SkPath* srcPtr = &src;
2195 if (fPathEffect && fPathEffect->filterPath(&tmpPath, src, &rec, cullRect)) {
2199 if (!rec.applyToPath(dst, *srcPtr)) {
2200 if (srcPtr == &tmpPath) {
2201 // If path's were copy-on-write, this trick would not be needed.
2202 // As it is, we want to save making a deep-copy from tmpPath -> dst
2203 // since we know we're just going to delete tmpPath when we return,
2204 // so the swap saves that copy.
2210 return !rec.isHairlineStyle();
2213 const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc,
2215 Style style) const {
2218 const SkRect* src = &origSrc;
2220 if (this->getLooper()) {
2221 SkASSERT(this->getLooper()->canComputeFastBounds(*this));
2222 this->getLooper()->computeFastBounds(*this, *src, storage);
2227 if (this->getPathEffect()) {
2228 this->getPathEffect()->computeFastBounds(&tmpSrc, origSrc);
2232 if (kFill_Style != style) {
2233 // since we're stroked, outset the rect by the radius (and join type)
2234 SkScalar radius = SkScalarHalf(this->getStrokeWidth());
2235 if (0 == radius) { // hairline
2236 radius = SK_Scalar1;
2237 } else if (this->getStrokeJoin() == SkPaint::kMiter_Join) {
2238 SkScalar scale = this->getStrokeMiter();
2239 if (scale > SK_Scalar1) {
2240 radius = SkScalarMul(radius, scale);
2243 storage->set(src->fLeft - radius, src->fTop - radius,
2244 src->fRight + radius, src->fBottom + radius);
2249 if (this->getMaskFilter()) {
2250 this->getMaskFilter()->computeFastBounds(*storage, storage);
2253 if (this->getImageFilter()) {
2254 this->getImageFilter()->computeFastBounds(*storage, storage);
2261 void SkPaint::toString(SkString* str) const {
2262 str->append("<dl><dt>SkPaint:</dt><dd><dl>");
2264 SkTypeface* typeface = this->getTypeface();
2265 if (NULL != typeface) {
2266 SkDynamicMemoryWStream ostream;
2267 typeface->serialize(&ostream);
2268 SkAutoTUnref<SkData> data(ostream.copyToData());
2270 SkMemoryStream stream(data);
2271 SkFontDescriptor descriptor(&stream);
2273 str->append("<dt>Font Family Name:</dt><dd>");
2274 str->append(descriptor.getFamilyName());
2275 str->append("</dd><dt>Font Full Name:</dt><dd>");
2276 str->append(descriptor.getFullName());
2277 str->append("</dd><dt>Font PS Name:</dt><dd>");
2278 str->append(descriptor.getPostscriptName());
2279 str->append("</dd><dt>Font File Name:</dt><dd>");
2280 str->append(descriptor.getFontFileName());
2281 str->append("</dd>");
2284 str->append("<dt>TextSize:</dt><dd>");
2285 str->appendScalar(this->getTextSize());
2286 str->append("</dd>");
2288 str->append("<dt>TextScaleX:</dt><dd>");
2289 str->appendScalar(this->getTextScaleX());
2290 str->append("</dd>");
2292 str->append("<dt>TextSkewX:</dt><dd>");
2293 str->appendScalar(this->getTextSkewX());
2294 str->append("</dd>");
2296 SkPathEffect* pathEffect = this->getPathEffect();
2297 if (NULL != pathEffect) {
2298 str->append("<dt>PathEffect:</dt><dd>");
2299 str->append("</dd>");
2302 SkShader* shader = this->getShader();
2303 if (NULL != shader) {
2304 str->append("<dt>Shader:</dt><dd>");
2305 shader->toString(str);
2306 str->append("</dd>");
2309 SkXfermode* xfer = this->getXfermode();
2311 str->append("<dt>Xfermode:</dt><dd>");
2312 xfer->toString(str);
2313 str->append("</dd>");
2316 SkMaskFilter* maskFilter = this->getMaskFilter();
2317 if (NULL != maskFilter) {
2318 str->append("<dt>MaskFilter:</dt><dd>");
2319 maskFilter->toString(str);
2320 str->append("</dd>");
2323 SkColorFilter* colorFilter = this->getColorFilter();
2324 if (NULL != colorFilter) {
2325 str->append("<dt>ColorFilter:</dt><dd>");
2326 colorFilter->toString(str);
2327 str->append("</dd>");
2330 SkRasterizer* rasterizer = this->getRasterizer();
2331 if (NULL != rasterizer) {
2332 str->append("<dt>Rasterizer:</dt><dd>");
2333 str->append("</dd>");
2336 SkDrawLooper* looper = this->getLooper();
2337 if (NULL != looper) {
2338 str->append("<dt>DrawLooper:</dt><dd>");
2339 looper->toString(str);
2340 str->append("</dd>");
2343 SkImageFilter* imageFilter = this->getImageFilter();
2344 if (NULL != imageFilter) {
2345 str->append("<dt>ImageFilter:</dt><dd>");
2346 str->append("</dd>");
2349 SkAnnotation* annotation = this->getAnnotation();
2350 if (NULL != annotation) {
2351 str->append("<dt>Annotation:</dt><dd>");
2352 str->append("</dd>");
2355 str->append("<dt>Color:</dt><dd>0x");
2356 SkColor color = this->getColor();
2357 str->appendHex(color);
2358 str->append("</dd>");
2360 str->append("<dt>Stroke Width:</dt><dd>");
2361 str->appendScalar(this->getStrokeWidth());
2362 str->append("</dd>");
2364 str->append("<dt>Stroke Miter:</dt><dd>");
2365 str->appendScalar(this->getStrokeMiter());
2366 str->append("</dd>");
2368 str->append("<dt>Flags:</dt><dd>(");
2369 if (this->getFlags()) {
2370 bool needSeparator = false;
2371 SkAddFlagToString(str, this->isAntiAlias(), "AntiAlias", &needSeparator);
2372 SkAddFlagToString(str, this->isDither(), "Dither", &needSeparator);
2373 SkAddFlagToString(str, this->isUnderlineText(), "UnderlineText", &needSeparator);
2374 SkAddFlagToString(str, this->isStrikeThruText(), "StrikeThruText", &needSeparator);
2375 SkAddFlagToString(str, this->isFakeBoldText(), "FakeBoldText", &needSeparator);
2376 SkAddFlagToString(str, this->isLinearText(), "LinearText", &needSeparator);
2377 SkAddFlagToString(str, this->isSubpixelText(), "SubpixelText", &needSeparator);
2378 SkAddFlagToString(str, this->isDevKernText(), "DevKernText", &needSeparator);
2379 SkAddFlagToString(str, this->isLCDRenderText(), "LCDRenderText", &needSeparator);
2380 SkAddFlagToString(str, this->isEmbeddedBitmapText(),
2381 "EmbeddedBitmapText", &needSeparator);
2382 SkAddFlagToString(str, this->isAutohinted(), "Autohinted", &needSeparator);
2383 SkAddFlagToString(str, this->isVerticalText(), "VerticalText", &needSeparator);
2384 SkAddFlagToString(str, SkToBool(this->getFlags() & SkPaint::kGenA8FromLCD_Flag),
2385 "GenA8FromLCD", &needSeparator);
2387 str->append("None");
2389 str->append(")</dd>");
2391 str->append("<dt>FilterLevel:</dt><dd>");
2392 static const char* gFilterLevelStrings[] = { "None", "Low", "Medium", "High" };
2393 str->append(gFilterLevelStrings[this->getFilterLevel()]);
2394 str->append("</dd>");
2396 str->append("<dt>TextAlign:</dt><dd>");
2397 static const char* gTextAlignStrings[SkPaint::kAlignCount] = { "Left", "Center", "Right" };
2398 str->append(gTextAlignStrings[this->getTextAlign()]);
2399 str->append("</dd>");
2401 str->append("<dt>CapType:</dt><dd>");
2402 static const char* gStrokeCapStrings[SkPaint::kCapCount] = { "Butt", "Round", "Square" };
2403 str->append(gStrokeCapStrings[this->getStrokeCap()]);
2404 str->append("</dd>");
2406 str->append("<dt>JoinType:</dt><dd>");
2407 static const char* gJoinStrings[SkPaint::kJoinCount] = { "Miter", "Round", "Bevel" };
2408 str->append(gJoinStrings[this->getStrokeJoin()]);
2409 str->append("</dd>");
2411 str->append("<dt>Style:</dt><dd>");
2412 static const char* gStyleStrings[SkPaint::kStyleCount] = { "Fill", "Stroke", "StrokeAndFill" };
2413 str->append(gStyleStrings[this->getStyle()]);
2414 str->append("</dd>");
2416 str->append("<dt>TextEncoding:</dt><dd>");
2417 static const char* gTextEncodingStrings[] = { "UTF8", "UTF16", "UTF32", "GlyphID" };
2418 str->append(gTextEncodingStrings[this->getTextEncoding()]);
2419 str->append("</dd>");
2421 str->append("<dt>Hinting:</dt><dd>");
2422 static const char* gHintingStrings[] = { "None", "Slight", "Normal", "Full" };
2423 str->append(gHintingStrings[this->getHinting()]);
2424 str->append("</dd>");
2426 str->append("</dd></dl></dl>");
2431 ///////////////////////////////////////////////////////////////////////////////
2433 static bool has_thick_frame(const SkPaint& paint) {
2434 return paint.getStrokeWidth() > 0 &&
2435 paint.getStyle() != SkPaint::kFill_Style;
2438 SkTextToPathIter::SkTextToPathIter( const char text[], size_t length,
2439 const SkPaint& paint,
2440 bool applyStrokeAndPathEffects)
2442 fGlyphCacheProc = paint.getMeasureCacheProc(SkPaint::kForward_TextBufferDirection,
2445 fPaint.setLinearText(true);
2446 fPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup
2448 if (fPaint.getPathEffect() == NULL && !has_thick_frame(fPaint)) {
2449 applyStrokeAndPathEffects = false;
2452 // can't use our canonical size if we need to apply patheffects
2453 if (fPaint.getPathEffect() == NULL) {
2454 fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
2455 fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
2456 if (has_thick_frame(fPaint)) {
2457 fPaint.setStrokeWidth(SkScalarDiv(fPaint.getStrokeWidth(), fScale));
2460 fScale = SK_Scalar1;
2463 if (!applyStrokeAndPathEffects) {
2464 fPaint.setStyle(SkPaint::kFill_Style);
2465 fPaint.setPathEffect(NULL);
2468 fCache = fPaint.detachCache(NULL, NULL);
2470 SkPaint::Style style = SkPaint::kFill_Style;
2471 SkPathEffect* pe = NULL;
2473 if (!applyStrokeAndPathEffects) {
2474 style = paint.getStyle(); // restore
2475 pe = paint.getPathEffect(); // restore
2477 fPaint.setStyle(style);
2478 fPaint.setPathEffect(pe);
2479 fPaint.setMaskFilter(paint.getMaskFilter()); // restore
2481 // now compute fXOffset if needed
2483 SkScalar xOffset = 0;
2484 if (paint.getTextAlign() != SkPaint::kLeft_Align) { // need to measure first
2486 SkScalar width = SkScalarMul(fPaint.measure_text(fCache, text, length,
2487 &count, NULL), fScale);
2488 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2489 width = SkScalarHalf(width);
2497 fStop = text + length;
2499 fXYIndex = paint.isVerticalText() ? 1 : 0;
2502 SkTextToPathIter::~SkTextToPathIter() {
2503 SkGlyphCache::AttachCache(fCache);
2506 bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) {
2507 if (fText < fStop) {
2508 const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText);
2510 fXPos += SkScalarMul(SkFixedToScalar(fPrevAdvance + fAutoKern.adjust(glyph)), fScale);
2511 fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking();
2515 *path = fCache->findPath(glyph);
2530 ///////////////////////////////////////////////////////////////////////////////
2532 bool SkPaint::nothingToDraw() const {
2536 SkXfermode::Mode mode;
2537 if (SkXfermode::AsMode(fXfermode, &mode)) {
2539 case SkXfermode::kSrcOver_Mode:
2540 case SkXfermode::kSrcATop_Mode:
2541 case SkXfermode::kDstOut_Mode:
2542 case SkXfermode::kDstOver_Mode:
2543 case SkXfermode::kPlus_Mode:
2544 return 0 == this->getAlpha();
2545 case SkXfermode::kDst_Mode: