LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkPaint.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 274 1297 21.1 %
Date: 2017-07-14 16:53:18 Functions: 44 138 31.9 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.13