LCOV - code coverage report
Current view: directory - gfx/skia/src/core - SkPaint.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1033 1 0.1 %
Date: 2012-06-02 Functions: 119 2 1.7 %

       1                 : 
       2                 : /*
       3                 :  * Copyright 2006 The Android Open Source Project
       4                 :  *
       5                 :  * Use of this source code is governed by a BSD-style license that can be
       6                 :  * found in the LICENSE file.
       7                 :  */
       8                 : 
       9                 : 
      10                 : #include "SkPaint.h"
      11                 : #include "SkColorFilter.h"
      12                 : #include "SkDrawLooper.h"
      13                 : #include "SkFontHost.h"
      14                 : #include "SkImageFilter.h"
      15                 : #include "SkMaskFilter.h"
      16                 : #include "SkPathEffect.h"
      17                 : #include "SkRasterizer.h"
      18                 : #include "SkShader.h"
      19                 : #include "SkScalar.h"
      20                 : #include "SkScalerContext.h"
      21                 : #include "SkStroke.h"
      22                 : #include "SkTextFormatParams.h"
      23                 : #include "SkTypeface.h"
      24                 : #include "SkXfermode.h"
      25                 : #include "SkAutoKern.h"
      26                 : 
      27                 : // define this to get a printf for out-of-range parameter in setters
      28                 : // e.g. setTextSize(-1)
      29                 : //#define SK_REPORT_API_RANGE_CHECK
      30                 : 
      31                 : #define SK_DefaultTextSize      SkIntToScalar(12)
      32                 : 
      33                 : #define SK_DefaultFlags         0   //(kNativeHintsText_Flag)
      34                 : 
      35                 : #ifdef SK_BUILD_FOR_ANDROID
      36                 : #define GEN_ID_INC                  fGenerationID++
      37                 : #define GEN_ID_INC_EVAL(expression) if (expression) { fGenerationID++; }
      38                 : #else
      39                 : #define GEN_ID_INC
      40                 : #define GEN_ID_INC_EVAL(expression)
      41                 : #endif
      42                 : 
      43               0 : SkPaint::SkPaint() {
      44                 :     // since we may have padding, we zero everything so that our memcmp() call
      45                 :     // in operator== will work correctly.
      46                 :     // with this, we can skip 0 and null individual initializations
      47               0 :     sk_bzero(this, sizeof(*this));
      48                 : 
      49                 : #if 0   // not needed with the bzero call above
      50                 :     fTypeface   = NULL;
      51                 :     fTextSkewX  = 0;
      52                 :     fPathEffect  = NULL;
      53                 :     fShader      = NULL;
      54                 :     fXfermode    = NULL;
      55                 :     fMaskFilter  = NULL;
      56                 :     fColorFilter = NULL;
      57                 :     fRasterizer  = NULL;
      58                 :     fLooper      = NULL;
      59                 :     fImageFilter = NULL;
      60                 :     fWidth      = 0;
      61                 : #endif
      62                 : 
      63               0 :     fTextSize   = SK_DefaultTextSize;
      64               0 :     fTextScaleX = SK_Scalar1;
      65               0 :     fColor      = SK_ColorBLACK;
      66               0 :     fMiterLimit = SK_DefaultMiterLimit;
      67               0 :     fFlags      = SK_DefaultFlags;
      68               0 :     fCapType    = kDefault_Cap;
      69               0 :     fJoinType   = kDefault_Join;
      70               0 :     fTextAlign  = kLeft_Align;
      71               0 :     fStyle      = kFill_Style;
      72               0 :     fTextEncoding = kUTF8_TextEncoding;
      73               0 :     fHinting    = kNormal_Hinting;
      74                 : #ifdef SK_BUILD_FOR_ANDROID
      75                 :     fGenerationID = 0;
      76                 : #endif
      77               0 : }
      78                 : 
      79               0 : SkPaint::SkPaint(const SkPaint& src) {
      80               0 :     memcpy(this, &src, sizeof(src));
      81                 : 
      82               0 :     SkSafeRef(fTypeface);
      83               0 :     SkSafeRef(fPathEffect);
      84               0 :     SkSafeRef(fShader);
      85               0 :     SkSafeRef(fXfermode);
      86               0 :     SkSafeRef(fMaskFilter);
      87               0 :     SkSafeRef(fColorFilter);
      88               0 :     SkSafeRef(fRasterizer);
      89               0 :     SkSafeRef(fLooper);
      90               0 :     SkSafeRef(fImageFilter);
      91               0 : }
      92                 : 
      93               0 : SkPaint::~SkPaint() {
      94               0 :     SkSafeUnref(fTypeface);
      95               0 :     SkSafeUnref(fPathEffect);
      96               0 :     SkSafeUnref(fShader);
      97               0 :     SkSafeUnref(fXfermode);
      98               0 :     SkSafeUnref(fMaskFilter);
      99               0 :     SkSafeUnref(fColorFilter);
     100               0 :     SkSafeUnref(fRasterizer);
     101               0 :     SkSafeUnref(fLooper);
     102               0 :     SkSafeUnref(fImageFilter);
     103               0 : }
     104                 : 
     105               0 : SkPaint& SkPaint::operator=(const SkPaint& src) {
     106               0 :     SkASSERT(&src);
     107                 : 
     108               0 :     SkSafeRef(src.fTypeface);
     109               0 :     SkSafeRef(src.fPathEffect);
     110               0 :     SkSafeRef(src.fShader);
     111               0 :     SkSafeRef(src.fXfermode);
     112               0 :     SkSafeRef(src.fMaskFilter);
     113               0 :     SkSafeRef(src.fColorFilter);
     114               0 :     SkSafeRef(src.fRasterizer);
     115               0 :     SkSafeRef(src.fLooper);
     116               0 :     SkSafeRef(src.fImageFilter);
     117                 : 
     118               0 :     SkSafeUnref(fTypeface);
     119               0 :     SkSafeUnref(fPathEffect);
     120               0 :     SkSafeUnref(fShader);
     121               0 :     SkSafeUnref(fXfermode);
     122               0 :     SkSafeUnref(fMaskFilter);
     123               0 :     SkSafeUnref(fColorFilter);
     124               0 :     SkSafeUnref(fRasterizer);
     125               0 :     SkSafeUnref(fLooper);
     126               0 :     SkSafeUnref(fImageFilter);
     127                 : 
     128                 : #ifdef SK_BUILD_FOR_ANDROID
     129                 :     uint32_t oldGenerationID = fGenerationID;
     130                 : #endif
     131               0 :     memcpy(this, &src, sizeof(src));
     132                 : #ifdef SK_BUILD_FOR_ANDROID
     133                 :     fGenerationID = oldGenerationID + 1;
     134                 : #endif
     135                 : 
     136               0 :     return *this;
     137                 : }
     138                 : 
     139               0 : bool operator==(const SkPaint& a, const SkPaint& b) {
     140                 : #ifdef SK_BUILD_FOR_ANDROID
     141                 :     //assumes that fGenerationID is the last field in the struct
     142                 :     return !memcmp(&a, &b, SK_OFFSETOF(SkPaint, fGenerationID));
     143                 : #else
     144               0 :     return !memcmp(&a, &b, sizeof(a));
     145                 : #endif
     146                 : }
     147                 : 
     148               0 : void SkPaint::reset() {
     149               0 :     SkPaint init;
     150                 : 
     151                 : #ifdef SK_BUILD_FOR_ANDROID
     152                 :     uint32_t oldGenerationID = fGenerationID;
     153                 : #endif
     154               0 :     *this = init;
     155                 : #ifdef SK_BUILD_FOR_ANDROID
     156                 :     fGenerationID = oldGenerationID + 1;
     157                 : #endif
     158               0 : }
     159                 : 
     160                 : #ifdef SK_BUILD_FOR_ANDROID
     161                 : uint32_t SkPaint::getGenerationID() const {
     162                 :     return fGenerationID;
     163                 : }
     164                 : #endif
     165                 : 
     166               0 : void SkPaint::setHinting(Hinting hintingLevel) {
     167                 :     GEN_ID_INC_EVAL((unsigned) hintingLevel != fHinting);
     168               0 :     fHinting = hintingLevel;
     169               0 : }
     170                 : 
     171               0 : void SkPaint::setFlags(uint32_t flags) {
     172                 :     GEN_ID_INC_EVAL(fFlags != flags);
     173               0 :     fFlags = flags;
     174               0 : }
     175                 : 
     176               0 : void SkPaint::setAntiAlias(bool doAA) {
     177                 :     GEN_ID_INC_EVAL(doAA != isAntiAlias());
     178               0 :     this->setFlags(SkSetClearMask(fFlags, doAA, kAntiAlias_Flag));
     179               0 : }
     180                 : 
     181               0 : void SkPaint::setDither(bool doDither) {
     182                 :     GEN_ID_INC_EVAL(doDither != isDither());
     183               0 :     this->setFlags(SkSetClearMask(fFlags, doDither, kDither_Flag));
     184               0 : }
     185                 : 
     186               0 : void SkPaint::setSubpixelText(bool doSubpixel) {
     187                 :     GEN_ID_INC_EVAL(doSubpixel != isSubpixelText());
     188               0 :     this->setFlags(SkSetClearMask(fFlags, doSubpixel, kSubpixelText_Flag));
     189               0 : }
     190                 : 
     191               0 : void SkPaint::setLCDRenderText(bool doLCDRender) {
     192                 :     GEN_ID_INC_EVAL(doLCDRender != isLCDRenderText());
     193               0 :     this->setFlags(SkSetClearMask(fFlags, doLCDRender, kLCDRenderText_Flag));
     194               0 : }
     195                 : 
     196               0 : void SkPaint::setEmbeddedBitmapText(bool doEmbeddedBitmapText) {
     197                 :     GEN_ID_INC_EVAL(doEmbeddedBitmapText != isEmbeddedBitmapText());
     198               0 :     this->setFlags(SkSetClearMask(fFlags, doEmbeddedBitmapText, kEmbeddedBitmapText_Flag));
     199               0 : }
     200                 : 
     201               0 : void SkPaint::setAutohinted(bool useAutohinter) {
     202                 :     GEN_ID_INC_EVAL(useAutohinter != isAutohinted());
     203               0 :     this->setFlags(SkSetClearMask(fFlags, useAutohinter, kAutoHinting_Flag));
     204               0 : }
     205                 : 
     206               0 : void SkPaint::setLinearText(bool doLinearText) {
     207                 :     GEN_ID_INC_EVAL(doLinearText != isLinearText());
     208               0 :     this->setFlags(SkSetClearMask(fFlags, doLinearText, kLinearText_Flag));
     209               0 : }
     210                 : 
     211               0 : void SkPaint::setVerticalText(bool doVertical) {
     212                 :     GEN_ID_INC_EVAL(doVertical != isVerticalText());
     213               0 :     this->setFlags(SkSetClearMask(fFlags, doVertical, kVerticalText_Flag));
     214               0 : }
     215                 : 
     216               0 : void SkPaint::setUnderlineText(bool doUnderline) {
     217                 :     GEN_ID_INC_EVAL(doUnderline != isUnderlineText());
     218               0 :     this->setFlags(SkSetClearMask(fFlags, doUnderline, kUnderlineText_Flag));
     219               0 : }
     220                 : 
     221               0 : void SkPaint::setStrikeThruText(bool doStrikeThru) {
     222                 :     GEN_ID_INC_EVAL(doStrikeThru != isStrikeThruText());
     223               0 :     this->setFlags(SkSetClearMask(fFlags, doStrikeThru, kStrikeThruText_Flag));
     224               0 : }
     225                 : 
     226               0 : void SkPaint::setFakeBoldText(bool doFakeBold) {
     227                 :     GEN_ID_INC_EVAL(doFakeBold != isFakeBoldText());
     228               0 :     this->setFlags(SkSetClearMask(fFlags, doFakeBold, kFakeBoldText_Flag));
     229               0 : }
     230                 : 
     231               0 : void SkPaint::setDevKernText(bool doDevKern) {
     232                 :     GEN_ID_INC_EVAL(doDevKern != isDevKernText());
     233               0 :     this->setFlags(SkSetClearMask(fFlags, doDevKern, kDevKernText_Flag));
     234               0 : }
     235                 : 
     236               0 : void SkPaint::setFilterBitmap(bool doFilter) {
     237                 :     GEN_ID_INC_EVAL(doFilter != isFilterBitmap());
     238               0 :     this->setFlags(SkSetClearMask(fFlags, doFilter, kFilterBitmap_Flag));
     239               0 : }
     240                 : 
     241               0 : void SkPaint::setStyle(Style style) {
     242               0 :     if ((unsigned)style < kStyleCount) {
     243                 :         GEN_ID_INC_EVAL((unsigned)style != fStyle);
     244               0 :         fStyle = style;
     245                 :     } else {
     246                 : #ifdef SK_REPORT_API_RANGE_CHECK
     247                 :         SkDebugf("SkPaint::setStyle(%d) out of range\n", style);
     248                 : #endif
     249                 :     }
     250               0 : }
     251                 : 
     252               0 : void SkPaint::setColor(SkColor color) {
     253                 :     GEN_ID_INC_EVAL(color != fColor);
     254               0 :     fColor = color;
     255               0 : }
     256                 : 
     257               0 : void SkPaint::setAlpha(U8CPU a) {
     258                 :     this->setColor(SkColorSetARGB(a, SkColorGetR(fColor),
     259               0 :                                   SkColorGetG(fColor), SkColorGetB(fColor)));
     260               0 : }
     261                 : 
     262               0 : void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
     263               0 :     this->setColor(SkColorSetARGB(a, r, g, b));
     264               0 : }
     265                 : 
     266               0 : void SkPaint::setStrokeWidth(SkScalar width) {
     267               0 :     if (width >= 0) {
     268                 :         GEN_ID_INC_EVAL(width != fWidth);
     269               0 :         fWidth = width;
     270                 :     } else {
     271                 : #ifdef SK_REPORT_API_RANGE_CHECK
     272                 :         SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");
     273                 : #endif
     274                 :     }
     275               0 : }
     276                 : 
     277               0 : void SkPaint::setStrokeMiter(SkScalar limit) {
     278               0 :     if (limit >= 0) {
     279                 :         GEN_ID_INC_EVAL(limit != fMiterLimit);
     280               0 :         fMiterLimit = limit;
     281                 :     } else {
     282                 : #ifdef SK_REPORT_API_RANGE_CHECK
     283                 :         SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");
     284                 : #endif
     285                 :     }
     286               0 : }
     287                 : 
     288               0 : void SkPaint::setStrokeCap(Cap ct) {
     289               0 :     if ((unsigned)ct < kCapCount) {
     290                 :         GEN_ID_INC_EVAL((unsigned)ct != fCapType);
     291               0 :         fCapType = SkToU8(ct);
     292                 :     } else {
     293                 : #ifdef SK_REPORT_API_RANGE_CHECK
     294                 :         SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);
     295                 : #endif
     296                 :     }
     297               0 : }
     298                 : 
     299               0 : void SkPaint::setStrokeJoin(Join jt) {
     300               0 :     if ((unsigned)jt < kJoinCount) {
     301                 :         GEN_ID_INC_EVAL((unsigned)jt != fJoinType);
     302               0 :         fJoinType = SkToU8(jt);
     303                 :     } else {
     304                 : #ifdef SK_REPORT_API_RANGE_CHECK
     305                 :         SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);
     306                 : #endif
     307                 :     }
     308               0 : }
     309                 : 
     310                 : ///////////////////////////////////////////////////////////////////////////////
     311                 : 
     312               0 : void SkPaint::setTextAlign(Align align) {
     313               0 :     if ((unsigned)align < kAlignCount) {
     314                 :         GEN_ID_INC_EVAL((unsigned)align != fTextAlign);
     315               0 :         fTextAlign = SkToU8(align);
     316                 :     } else {
     317                 : #ifdef SK_REPORT_API_RANGE_CHECK
     318                 :         SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align);
     319                 : #endif
     320                 :     }
     321               0 : }
     322                 : 
     323               0 : void SkPaint::setTextSize(SkScalar ts) {
     324               0 :     if (ts >= 0) {
     325                 :         GEN_ID_INC_EVAL(ts != fTextSize);
     326               0 :         fTextSize = ts;
     327                 :     } else {
     328                 : #ifdef SK_REPORT_API_RANGE_CHECK
     329                 :         SkDebugf("SkPaint::setTextSize() called with negative value\n");
     330                 : #endif
     331                 :     }
     332               0 : }
     333                 : 
     334               0 : void SkPaint::setTextScaleX(SkScalar scaleX) {
     335                 :     GEN_ID_INC_EVAL(scaleX != fTextScaleX);
     336               0 :     fTextScaleX = scaleX;
     337               0 : }
     338                 : 
     339               0 : void SkPaint::setTextSkewX(SkScalar skewX) {
     340                 :     GEN_ID_INC_EVAL(skewX != fTextSkewX);
     341               0 :     fTextSkewX = skewX;
     342               0 : }
     343                 : 
     344               0 : void SkPaint::setTextEncoding(TextEncoding encoding) {
     345               0 :     if ((unsigned)encoding <= kGlyphID_TextEncoding) {
     346                 :         GEN_ID_INC_EVAL((unsigned)encoding != fTextEncoding);
     347               0 :         fTextEncoding = encoding;
     348                 :     } else {
     349                 : #ifdef SK_REPORT_API_RANGE_CHECK
     350                 :         SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding);
     351                 : #endif
     352                 :     }
     353               0 : }
     354                 : 
     355                 : ///////////////////////////////////////////////////////////////////////////////
     356                 : 
     357               0 : SkTypeface* SkPaint::setTypeface(SkTypeface* font) {
     358               0 :     SkRefCnt_SafeAssign(fTypeface, font);
     359                 :     GEN_ID_INC;
     360               0 :     return font;
     361                 : }
     362                 : 
     363               0 : SkRasterizer* SkPaint::setRasterizer(SkRasterizer* r) {
     364               0 :     SkRefCnt_SafeAssign(fRasterizer, r);
     365                 :     GEN_ID_INC;
     366               0 :     return r;
     367                 : }
     368                 : 
     369               0 : SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) {
     370               0 :     SkRefCnt_SafeAssign(fLooper, looper);
     371                 :     GEN_ID_INC;
     372               0 :     return looper;
     373                 : }
     374                 : 
     375               0 : SkImageFilter* SkPaint::setImageFilter(SkImageFilter* imageFilter) {
     376               0 :     SkRefCnt_SafeAssign(fImageFilter, imageFilter);
     377                 :     GEN_ID_INC;
     378               0 :     return imageFilter;
     379                 : }
     380                 : 
     381                 : ///////////////////////////////////////////////////////////////////////////////
     382                 : 
     383                 : #include "SkGlyphCache.h"
     384                 : #include "SkUtils.h"
     385                 : 
     386               0 : static void DetachDescProc(const SkDescriptor* desc, void* context) {
     387               0 :     *((SkGlyphCache**)context) = SkGlyphCache::DetachCache(desc);
     388               0 : }
     389                 : 
     390                 : #ifdef SK_BUILD_FOR_ANDROID
     391                 : const SkGlyph& SkPaint::getUnicharMetrics(SkUnichar text) {
     392                 :     SkGlyphCache* cache;
     393                 :     descriptorProc(NULL, DetachDescProc, &cache, true);
     394                 : 
     395                 :     const SkGlyph& glyph = cache->getUnicharMetrics(text);
     396                 : 
     397                 :     SkGlyphCache::AttachCache(cache);
     398                 :     return glyph;
     399                 : }
     400                 : 
     401                 : const void* SkPaint::findImage(const SkGlyph& glyph) {
     402                 :     // See ::detachCache()
     403                 :     SkGlyphCache* cache;
     404                 :     descriptorProc(NULL, DetachDescProc, &cache, true);
     405                 : 
     406                 :     const void* image = cache->findImage(glyph);
     407                 : 
     408                 :     SkGlyphCache::AttachCache(cache);
     409                 :     return image;
     410                 : }
     411                 : #endif
     412                 : 
     413               0 : int SkPaint::textToGlyphs(const void* textData, size_t byteLength,
     414                 :                           uint16_t glyphs[]) const {
     415               0 :     if (byteLength == 0) {
     416               0 :         return 0;
     417                 :     }
     418                 : 
     419               0 :     SkASSERT(textData != NULL);
     420                 : 
     421               0 :     if (NULL == glyphs) {
     422               0 :         switch (this->getTextEncoding()) {
     423                 :         case kUTF8_TextEncoding:
     424               0 :             return SkUTF8_CountUnichars((const char*)textData, byteLength);
     425                 :         case kUTF16_TextEncoding:
     426                 :             return SkUTF16_CountUnichars((const uint16_t*)textData,
     427               0 :                                          byteLength >> 1);
     428                 :         case kGlyphID_TextEncoding:
     429               0 :             return byteLength >> 1;
     430                 :         default:
     431               0 :             SkDEBUGFAIL("unknown text encoding");
     432                 :         }
     433               0 :         return 0;
     434                 :     }
     435                 : 
     436                 :     // if we get here, we have a valid glyphs[] array, so time to fill it in
     437                 : 
     438                 :     // handle this encoding before the setup for the glyphcache
     439               0 :     if (this->getTextEncoding() == kGlyphID_TextEncoding) {
     440                 :         // we want to ignore the low bit of byteLength
     441               0 :         memcpy(glyphs, textData, byteLength >> 1 << 1);
     442               0 :         return byteLength >> 1;
     443                 :     }
     444                 : 
     445               0 :     SkAutoGlyphCache autoCache(*this, NULL);
     446               0 :     SkGlyphCache*    cache = autoCache.getCache();
     447                 : 
     448               0 :     const char* text = (const char*)textData;
     449               0 :     const char* stop = text + byteLength;
     450               0 :     uint16_t*   gptr = glyphs;
     451                 : 
     452               0 :     switch (this->getTextEncoding()) {
     453                 :         case SkPaint::kUTF8_TextEncoding:
     454               0 :             while (text < stop) {
     455               0 :                 *gptr++ = cache->unicharToGlyph(SkUTF8_NextUnichar(&text));
     456                 :             }
     457               0 :             break;
     458                 :         case SkPaint::kUTF16_TextEncoding: {
     459               0 :             const uint16_t* text16 = (const uint16_t*)text;
     460               0 :             const uint16_t* stop16 = (const uint16_t*)stop;
     461               0 :             while (text16 < stop16) {
     462               0 :                 *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16));
     463                 :             }
     464               0 :             break;
     465                 :         }
     466                 :         default:
     467               0 :             SkDEBUGFAIL("unknown text encoding");
     468                 :     }
     469               0 :     return gptr - glyphs;
     470                 : }
     471                 : 
     472               0 : bool SkPaint::containsText(const void* textData, size_t byteLength) const {
     473               0 :     if (0 == byteLength) {
     474               0 :         return true;
     475                 :     }
     476                 : 
     477               0 :     SkASSERT(textData != NULL);
     478                 : 
     479                 :     // handle this encoding before the setup for the glyphcache
     480               0 :     if (this->getTextEncoding() == kGlyphID_TextEncoding) {
     481               0 :         const uint16_t* glyphID = static_cast<const uint16_t*>(textData);
     482               0 :         size_t count = byteLength >> 1;
     483               0 :         for (size_t i = 0; i < count; i++) {
     484               0 :             if (0 == glyphID[i]) {
     485               0 :                 return false;
     486                 :             }
     487                 :         }
     488               0 :         return true;
     489                 :     }
     490                 : 
     491               0 :     SkAutoGlyphCache autoCache(*this, NULL);
     492               0 :     SkGlyphCache*    cache = autoCache.getCache();
     493                 : 
     494               0 :     switch (this->getTextEncoding()) {
     495                 :         case SkPaint::kUTF8_TextEncoding: {
     496               0 :             const char* text = static_cast<const char*>(textData);
     497               0 :             const char* stop = text + byteLength;
     498               0 :             while (text < stop) {
     499               0 :                 if (0 == cache->unicharToGlyph(SkUTF8_NextUnichar(&text))) {
     500               0 :                     return false;
     501                 :                 }
     502                 :             }
     503               0 :             break;
     504                 :         }
     505                 :         case SkPaint::kUTF16_TextEncoding: {
     506               0 :             const uint16_t* text = static_cast<const uint16_t*>(textData);
     507               0 :             const uint16_t* stop = text + (byteLength >> 1);
     508               0 :             while (text < stop) {
     509               0 :                 if (0 == cache->unicharToGlyph(SkUTF16_NextUnichar(&text))) {
     510               0 :                     return false;
     511                 :                 }
     512                 :             }
     513               0 :             break;
     514                 :         }
     515                 :         default:
     516               0 :             SkDEBUGFAIL("unknown text encoding");
     517               0 :             return false;
     518                 :     }
     519               0 :     return true;
     520                 : }
     521                 : 
     522               0 : void SkPaint::glyphsToUnichars(const uint16_t glyphs[], int count,
     523                 :                                SkUnichar textData[]) const {
     524               0 :     if (count <= 0) {
     525               0 :         return;
     526                 :     }
     527                 : 
     528               0 :     SkASSERT(glyphs != NULL);
     529               0 :     SkASSERT(textData != NULL);
     530                 : 
     531               0 :     SkAutoGlyphCache autoCache(*this, NULL);
     532               0 :     SkGlyphCache*    cache = autoCache.getCache();
     533                 : 
     534               0 :     for (int index = 0; index < count; index++) {
     535               0 :         textData[index] = cache->glyphToUnichar(glyphs[index]);
     536                 :     }
     537                 : }
     538                 : 
     539                 : ///////////////////////////////////////////////////////////////////////////////
     540                 : 
     541               0 : static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache,
     542                 :                                               const char** text) {
     543               0 :     SkASSERT(cache != NULL);
     544               0 :     SkASSERT(text != NULL);
     545                 : 
     546               0 :     return cache->getUnicharMetrics(SkUTF8_NextUnichar(text));
     547                 : }
     548                 : 
     549               0 : static const SkGlyph& sk_getMetrics_utf8_prev(SkGlyphCache* cache,
     550                 :                                               const char** text) {
     551               0 :     SkASSERT(cache != NULL);
     552               0 :     SkASSERT(text != NULL);
     553                 : 
     554               0 :     return cache->getUnicharMetrics(SkUTF8_PrevUnichar(text));
     555                 : }
     556                 : 
     557               0 : static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache,
     558                 :                                                const char** text) {
     559               0 :     SkASSERT(cache != NULL);
     560               0 :     SkASSERT(text != NULL);
     561                 : 
     562               0 :     return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text));
     563                 : }
     564                 : 
     565               0 : static const SkGlyph& sk_getMetrics_utf16_prev(SkGlyphCache* cache,
     566                 :                                                const char** text) {
     567               0 :     SkASSERT(cache != NULL);
     568               0 :     SkASSERT(text != NULL);
     569                 : 
     570               0 :     return cache->getUnicharMetrics(SkUTF16_PrevUnichar((const uint16_t**)text));
     571                 : }
     572                 : 
     573               0 : static const SkGlyph& sk_getMetrics_glyph_next(SkGlyphCache* cache,
     574                 :                                                const char** text) {
     575               0 :     SkASSERT(cache != NULL);
     576               0 :     SkASSERT(text != NULL);
     577                 : 
     578               0 :     const uint16_t* ptr = *(const uint16_t**)text;
     579               0 :     unsigned glyphID = *ptr;
     580               0 :     ptr += 1;
     581               0 :     *text = (const char*)ptr;
     582               0 :     return cache->getGlyphIDMetrics(glyphID);
     583                 : }
     584                 : 
     585               0 : static const SkGlyph& sk_getMetrics_glyph_prev(SkGlyphCache* cache,
     586                 :                                                const char** text) {
     587               0 :     SkASSERT(cache != NULL);
     588               0 :     SkASSERT(text != NULL);
     589                 : 
     590               0 :     const uint16_t* ptr = *(const uint16_t**)text;
     591               0 :     ptr -= 1;
     592               0 :     unsigned glyphID = *ptr;
     593               0 :     *text = (const char*)ptr;
     594               0 :     return cache->getGlyphIDMetrics(glyphID);
     595                 : }
     596                 : 
     597               0 : static const SkGlyph& sk_getAdvance_utf8_next(SkGlyphCache* cache,
     598                 :                                               const char** text) {
     599               0 :     SkASSERT(cache != NULL);
     600               0 :     SkASSERT(text != NULL);
     601                 : 
     602               0 :     return cache->getUnicharAdvance(SkUTF8_NextUnichar(text));
     603                 : }
     604                 : 
     605               0 : static const SkGlyph& sk_getAdvance_utf8_prev(SkGlyphCache* cache,
     606                 :                                               const char** text) {
     607               0 :     SkASSERT(cache != NULL);
     608               0 :     SkASSERT(text != NULL);
     609                 : 
     610               0 :     return cache->getUnicharAdvance(SkUTF8_PrevUnichar(text));
     611                 : }
     612                 : 
     613               0 : static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache,
     614                 :                                                const char** text) {
     615               0 :     SkASSERT(cache != NULL);
     616               0 :     SkASSERT(text != NULL);
     617                 : 
     618               0 :     return cache->getUnicharAdvance(SkUTF16_NextUnichar((const uint16_t**)text));
     619                 : }
     620                 : 
     621               0 : static const SkGlyph& sk_getAdvance_utf16_prev(SkGlyphCache* cache,
     622                 :                                                const char** text) {
     623               0 :     SkASSERT(cache != NULL);
     624               0 :     SkASSERT(text != NULL);
     625                 : 
     626               0 :     return cache->getUnicharAdvance(SkUTF16_PrevUnichar((const uint16_t**)text));
     627                 : }
     628                 : 
     629               0 : static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache,
     630                 :                                                const char** text) {
     631               0 :     SkASSERT(cache != NULL);
     632               0 :     SkASSERT(text != NULL);
     633                 : 
     634               0 :     const uint16_t* ptr = *(const uint16_t**)text;
     635               0 :     unsigned glyphID = *ptr;
     636               0 :     ptr += 1;
     637               0 :     *text = (const char*)ptr;
     638               0 :     return cache->getGlyphIDAdvance(glyphID);
     639                 : }
     640                 : 
     641               0 : static const SkGlyph& sk_getAdvance_glyph_prev(SkGlyphCache* cache,
     642                 :                                                const char** text) {
     643               0 :     SkASSERT(cache != NULL);
     644               0 :     SkASSERT(text != NULL);
     645                 : 
     646               0 :     const uint16_t* ptr = *(const uint16_t**)text;
     647               0 :     ptr -= 1;
     648               0 :     unsigned glyphID = *ptr;
     649               0 :     *text = (const char*)ptr;
     650               0 :     return cache->getGlyphIDAdvance(glyphID);
     651                 : }
     652                 : 
     653               0 : SkMeasureCacheProc SkPaint::getMeasureCacheProc(TextBufferDirection tbd,
     654                 :                                                 bool needFullMetrics) const {
     655                 :     static const SkMeasureCacheProc gMeasureCacheProcs[] = {
     656                 :         sk_getMetrics_utf8_next,
     657                 :         sk_getMetrics_utf16_next,
     658                 :         sk_getMetrics_glyph_next,
     659                 : 
     660                 :         sk_getMetrics_utf8_prev,
     661                 :         sk_getMetrics_utf16_prev,
     662                 :         sk_getMetrics_glyph_prev,
     663                 : 
     664                 :         sk_getAdvance_utf8_next,
     665                 :         sk_getAdvance_utf16_next,
     666                 :         sk_getAdvance_glyph_next,
     667                 : 
     668                 :         sk_getAdvance_utf8_prev,
     669                 :         sk_getAdvance_utf16_prev,
     670                 :         sk_getAdvance_glyph_prev
     671                 :     };
     672                 : 
     673               0 :     unsigned index = this->getTextEncoding();
     674                 : 
     675               0 :     if (kBackward_TextBufferDirection == tbd) {
     676               0 :         index += 3;
     677                 :     }
     678               0 :     if (!needFullMetrics && !this->isDevKernText()) {
     679               0 :         index += 6;
     680                 :     }
     681                 : 
     682               0 :     SkASSERT(index < SK_ARRAY_COUNT(gMeasureCacheProcs));
     683               0 :     return gMeasureCacheProcs[index];
     684                 : }
     685                 : 
     686                 : ///////////////////////////////////////////////////////////////////////////////
     687                 : 
     688               0 : static const SkGlyph& sk_getMetrics_utf8_00(SkGlyphCache* cache,
     689                 :                                         const char** text, SkFixed, SkFixed) {
     690               0 :     SkASSERT(cache != NULL);
     691               0 :     SkASSERT(text != NULL);
     692                 : 
     693               0 :     return cache->getUnicharMetrics(SkUTF8_NextUnichar(text));
     694                 : }
     695                 : 
     696               0 : static const SkGlyph& sk_getMetrics_utf8_xy(SkGlyphCache* cache,
     697                 :                                     const char** text, SkFixed x, SkFixed y) {
     698               0 :     SkASSERT(cache != NULL);
     699               0 :     SkASSERT(text != NULL);
     700                 : 
     701               0 :     return cache->getUnicharMetrics(SkUTF8_NextUnichar(text), x, y);
     702                 : }
     703                 : 
     704               0 : static const SkGlyph& sk_getMetrics_utf16_00(SkGlyphCache* cache,
     705                 :                                         const char** text, SkFixed, SkFixed) {
     706               0 :     SkASSERT(cache != NULL);
     707               0 :     SkASSERT(text != NULL);
     708                 : 
     709               0 :     return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text));
     710                 : }
     711                 : 
     712               0 : static const SkGlyph& sk_getMetrics_utf16_xy(SkGlyphCache* cache,
     713                 :                                      const char** text, SkFixed x, SkFixed y) {
     714               0 :     SkASSERT(cache != NULL);
     715               0 :     SkASSERT(text != NULL);
     716                 : 
     717                 :     return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text),
     718               0 :                                     x, y);
     719                 : }
     720                 : 
     721               0 : static const SkGlyph& sk_getMetrics_glyph_00(SkGlyphCache* cache,
     722                 :                                          const char** text, SkFixed, SkFixed) {
     723               0 :     SkASSERT(cache != NULL);
     724               0 :     SkASSERT(text != NULL);
     725                 : 
     726               0 :     const uint16_t* ptr = *(const uint16_t**)text;
     727               0 :     unsigned glyphID = *ptr;
     728               0 :     ptr += 1;
     729               0 :     *text = (const char*)ptr;
     730               0 :     return cache->getGlyphIDMetrics(glyphID);
     731                 : }
     732                 : 
     733               0 : static const SkGlyph& sk_getMetrics_glyph_xy(SkGlyphCache* cache,
     734                 :                                      const char** text, SkFixed x, SkFixed y) {
     735               0 :     SkASSERT(cache != NULL);
     736               0 :     SkASSERT(text != NULL);
     737                 : 
     738               0 :     const uint16_t* ptr = *(const uint16_t**)text;
     739               0 :     unsigned glyphID = *ptr;
     740               0 :     ptr += 1;
     741               0 :     *text = (const char*)ptr;
     742               0 :     return cache->getGlyphIDMetrics(glyphID, x, y);
     743                 : }
     744                 : 
     745               0 : SkDrawCacheProc SkPaint::getDrawCacheProc() const {
     746                 :     static const SkDrawCacheProc gDrawCacheProcs[] = {
     747                 :         sk_getMetrics_utf8_00,
     748                 :         sk_getMetrics_utf16_00,
     749                 :         sk_getMetrics_glyph_00,
     750                 : 
     751                 :         sk_getMetrics_utf8_xy,
     752                 :         sk_getMetrics_utf16_xy,
     753                 :         sk_getMetrics_glyph_xy
     754                 :     };
     755                 : 
     756               0 :     unsigned index = this->getTextEncoding();
     757               0 :     if (fFlags & kSubpixelText_Flag) {
     758               0 :         index += 3;
     759                 :     }
     760                 : 
     761               0 :     SkASSERT(index < SK_ARRAY_COUNT(gDrawCacheProcs));
     762               0 :     return gDrawCacheProcs[index];
     763                 : }
     764                 : 
     765                 : ///////////////////////////////////////////////////////////////////////////////
     766                 : 
     767                 : class SkAutoRestorePaintTextSizeAndFrame {
     768                 : public:
     769               0 :     SkAutoRestorePaintTextSizeAndFrame(const SkPaint* paint)
     770               0 :             : fPaint((SkPaint*)paint) {
     771               0 :         fTextSize = paint->getTextSize();
     772               0 :         fStyle = paint->getStyle();
     773               0 :         fPaint->setStyle(SkPaint::kFill_Style);
     774               0 :     }
     775                 : 
     776               0 :     ~SkAutoRestorePaintTextSizeAndFrame() {
     777               0 :         fPaint->setStyle(fStyle);
     778               0 :         fPaint->setTextSize(fTextSize);
     779               0 :     }
     780                 : 
     781                 : private:
     782                 :     SkPaint*        fPaint;
     783                 :     SkScalar        fTextSize;
     784                 :     SkPaint::Style  fStyle;
     785                 : };
     786                 : 
     787               0 : static void set_bounds(const SkGlyph& g, SkRect* bounds) {
     788                 :     bounds->set(SkIntToScalar(g.fLeft),
     789                 :                 SkIntToScalar(g.fTop),
     790                 :                 SkIntToScalar(g.fLeft + g.fWidth),
     791               0 :                 SkIntToScalar(g.fTop + g.fHeight));
     792               0 : }
     793                 : 
     794                 : // 64bits wide, with a 16bit bias. Useful when accumulating lots of 16.16 so
     795                 : // we don't overflow along the way
     796                 : typedef int64_t Sk48Dot16;
     797                 : 
     798                 : #ifdef SK_SCALAR_IS_FLOAT
     799               0 :     static inline float Sk48Dot16ToScalar(Sk48Dot16 x) {
     800               0 :         return (float) (x * 1.5258789e-5);   // x * (1 / 65536.0f)
     801                 :     }
     802                 : #else
     803                 :     static inline SkFixed Sk48Dot16ToScalar(Sk48Dot16 x) {
     804                 :         // just return the low 32bits
     805                 :         return static_cast<SkFixed>(x);
     806                 :     }
     807                 : #endif
     808                 : 
     809               0 : static void join_bounds_x(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) {
     810               0 :     SkScalar sx = Sk48Dot16ToScalar(dx);
     811               0 :     bounds->join(SkIntToScalar(g.fLeft) + sx,
     812                 :                  SkIntToScalar(g.fTop),
     813               0 :                  SkIntToScalar(g.fLeft + g.fWidth) + sx,
     814               0 :                  SkIntToScalar(g.fTop + g.fHeight));
     815               0 : }
     816                 : 
     817               0 : static void join_bounds_y(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dy) {
     818               0 :     SkScalar sy = Sk48Dot16ToScalar(dy);
     819                 :     bounds->join(SkIntToScalar(g.fLeft),
     820               0 :                  SkIntToScalar(g.fTop) + sy,
     821                 :                  SkIntToScalar(g.fLeft + g.fWidth),
     822               0 :                  SkIntToScalar(g.fTop + g.fHeight) + sy);
     823               0 : }
     824                 : 
     825                 : typedef void (*JoinBoundsProc)(const SkGlyph&, SkRect*, Sk48Dot16);
     826                 : 
     827                 : // xyIndex is 0 for fAdvanceX or 1 for fAdvanceY
     828               0 : static SkFixed advance(const SkGlyph& glyph, int xyIndex) {
     829               0 :     SkASSERT(0 == xyIndex || 1 == xyIndex);
     830               0 :     return (&glyph.fAdvanceX)[xyIndex];
     831                 : }
     832                 : 
     833               0 : SkScalar SkPaint::measure_text(SkGlyphCache* cache,
     834                 :                                const char* text, size_t byteLength,
     835                 :                                int* count, SkRect* bounds) const {
     836               0 :     SkASSERT(count);
     837               0 :     if (byteLength == 0) {
     838               0 :         *count = 0;
     839               0 :         if (bounds) {
     840               0 :             bounds->setEmpty();
     841                 :         }
     842               0 :         return 0;
     843                 :     }
     844                 : 
     845                 :     SkMeasureCacheProc glyphCacheProc;
     846                 :     glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection,
     847               0 :                                                NULL != bounds);
     848                 : 
     849                 :     int xyIndex;
     850                 :     JoinBoundsProc joinBoundsProc;
     851               0 :     if (this->isVerticalText()) {
     852               0 :         xyIndex = 1;
     853               0 :         joinBoundsProc = join_bounds_y;
     854                 :     } else {
     855               0 :         xyIndex = 0;
     856               0 :         joinBoundsProc = join_bounds_x;
     857                 :     }
     858                 : 
     859               0 :     int         n = 1;
     860               0 :     const char* stop = (const char*)text + byteLength;
     861               0 :     const SkGlyph* g = &glyphCacheProc(cache, &text);
     862                 :     // our accumulated fixed-point advances might overflow 16.16, so we use
     863                 :     // a 48.16 (64bit) accumulator, and then convert that to scalar at the
     864                 :     // very end.
     865               0 :     Sk48Dot16 x = advance(*g, xyIndex);
     866                 : 
     867               0 :     SkAutoKern  autokern;
     868                 : 
     869               0 :     if (NULL == bounds) {
     870               0 :         if (this->isDevKernText()) {
     871                 :             int rsb;
     872               0 :             for (; text < stop; n++) {
     873               0 :                 rsb = g->fRsbDelta;
     874               0 :                 g = &glyphCacheProc(cache, &text);
     875               0 :                 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + advance(*g, xyIndex);
     876                 :             }
     877                 :         } else {
     878               0 :             for (; text < stop; n++) {
     879               0 :                 x += advance(glyphCacheProc(cache, &text), xyIndex);
     880                 :             }
     881                 :         }
     882                 :     } else {
     883               0 :         set_bounds(*g, bounds);
     884               0 :         if (this->isDevKernText()) {
     885                 :             int rsb;
     886               0 :             for (; text < stop; n++) {
     887               0 :                 rsb = g->fRsbDelta;
     888               0 :                 g = &glyphCacheProc(cache, &text);
     889               0 :                 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta);
     890               0 :                 joinBoundsProc(*g, bounds, x);
     891               0 :                 x += advance(*g, xyIndex);
     892                 :             }
     893                 :         } else {
     894               0 :             for (; text < stop; n++) {
     895               0 :                 g = &glyphCacheProc(cache, &text);
     896               0 :                 joinBoundsProc(*g, bounds, x);
     897               0 :                 x += advance(*g, xyIndex);
     898                 :             }
     899                 :         }
     900                 :     }
     901               0 :     SkASSERT(text == stop);
     902                 : 
     903               0 :     *count = n;
     904               0 :     return Sk48Dot16ToScalar(x);
     905                 : }
     906                 : 
     907               0 : SkScalar SkPaint::measureText(const void* textData, size_t length,
     908                 :                               SkRect* bounds, SkScalar zoom) const {
     909               0 :     const char* text = (const char*)textData;
     910               0 :     SkASSERT(text != NULL || length == 0);
     911                 : 
     912               0 :     SkScalar                            scale = 0;
     913               0 :     SkAutoRestorePaintTextSizeAndFrame  restore(this);
     914                 : 
     915               0 :     if (this->isLinearText()) {
     916               0 :         scale = fTextSize / kCanonicalTextSizeForPaths;
     917                 :         // this gets restored by restore
     918               0 :         ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths));
     919                 :     }
     920                 : 
     921               0 :     SkMatrix zoomMatrix, *zoomPtr = NULL;
     922               0 :     if (zoom) {
     923               0 :         zoomMatrix.setScale(zoom, zoom);
     924               0 :         zoomPtr = &zoomMatrix;
     925                 :     }
     926                 : 
     927               0 :     SkAutoGlyphCache    autoCache(*this, zoomPtr);
     928               0 :     SkGlyphCache*       cache = autoCache.getCache();
     929                 : 
     930               0 :     SkScalar width = 0;
     931                 : 
     932               0 :     if (length > 0) {
     933                 :         int tempCount;
     934                 : 
     935               0 :         width = this->measure_text(cache, text, length, &tempCount, bounds);
     936               0 :         if (scale) {
     937               0 :             width = SkScalarMul(width, scale);
     938               0 :             if (bounds) {
     939               0 :                 bounds->fLeft = SkScalarMul(bounds->fLeft, scale);
     940               0 :                 bounds->fTop = SkScalarMul(bounds->fTop, scale);
     941               0 :                 bounds->fRight = SkScalarMul(bounds->fRight, scale);
     942               0 :                 bounds->fBottom = SkScalarMul(bounds->fBottom, scale);
     943                 :             }
     944                 :         }
     945                 :     }
     946               0 :     return width;
     947                 : }
     948                 : 
     949                 : typedef bool (*SkTextBufferPred)(const char* text, const char* stop);
     950                 : 
     951               0 : static bool forward_textBufferPred(const char* text, const char* stop) {
     952               0 :     return text < stop;
     953                 : }
     954                 : 
     955               0 : static bool backward_textBufferPred(const char* text, const char* stop) {
     956               0 :     return text > stop;
     957                 : }
     958                 : 
     959               0 : static SkTextBufferPred chooseTextBufferPred(SkPaint::TextBufferDirection tbd,
     960                 :                                              const char** text, size_t length,
     961                 :                                              const char** stop) {
     962               0 :     if (SkPaint::kForward_TextBufferDirection == tbd) {
     963               0 :         *stop = *text + length;
     964               0 :         return forward_textBufferPred;
     965                 :     } else {
     966                 :         // text should point to the end of the buffer, and stop to the beginning
     967               0 :         *stop = *text;
     968               0 :         *text += length;
     969               0 :         return backward_textBufferPred;
     970                 :     }
     971                 : }
     972                 : 
     973               0 : size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
     974                 :                           SkScalar* measuredWidth,
     975                 :                           TextBufferDirection tbd) const {
     976               0 :     if (0 == length || 0 >= maxWidth) {
     977               0 :         if (measuredWidth) {
     978               0 :             *measuredWidth = 0;
     979                 :         }
     980               0 :         return 0;
     981                 :     }
     982                 : 
     983               0 :     if (0 == fTextSize) {
     984               0 :         if (measuredWidth) {
     985               0 :             *measuredWidth = 0;
     986                 :         }
     987               0 :         return length;
     988                 :     }
     989                 : 
     990               0 :     SkASSERT(textD != NULL);
     991               0 :     const char* text = (const char*)textD;
     992                 : 
     993               0 :     SkScalar                            scale = 0;
     994               0 :     SkAutoRestorePaintTextSizeAndFrame  restore(this);
     995                 : 
     996               0 :     if (this->isLinearText()) {
     997               0 :         scale = fTextSize / kCanonicalTextSizeForPaths;
     998               0 :         maxWidth = SkScalarMulDiv(maxWidth, kCanonicalTextSizeForPaths, fTextSize);
     999                 :         // this gets restored by restore
    1000               0 :         ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths));
    1001                 :     }
    1002                 : 
    1003               0 :     SkAutoGlyphCache    autoCache(*this, NULL);
    1004               0 :     SkGlyphCache*       cache = autoCache.getCache();
    1005                 : 
    1006               0 :     SkMeasureCacheProc glyphCacheProc = this->getMeasureCacheProc(tbd, false);
    1007                 :     const char*      stop;
    1008               0 :     SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &stop);
    1009               0 :     const int        xyIndex = this->isVerticalText() ? 1 : 0;
    1010                 :     // use 64bits for our accumulator, to avoid overflowing 16.16
    1011               0 :     Sk48Dot16        max = SkScalarToFixed(maxWidth);
    1012               0 :     Sk48Dot16        width = 0;
    1013                 : 
    1014               0 :     SkAutoKern  autokern;
    1015                 : 
    1016               0 :     if (this->isDevKernText()) {
    1017               0 :         int rsb = 0;
    1018               0 :         while (pred(text, stop)) {
    1019               0 :             const char* curr = text;
    1020               0 :             const SkGlyph& g = glyphCacheProc(cache, &text);
    1021               0 :             SkFixed x = SkAutoKern_AdjustF(rsb, g.fLsbDelta) + advance(g, xyIndex);
    1022               0 :             if ((width += x) > max) {
    1023               0 :                 width -= x;
    1024               0 :                 text = curr;
    1025               0 :                 break;
    1026                 :             }
    1027               0 :             rsb = g.fRsbDelta;
    1028                 :         }
    1029                 :     } else {
    1030               0 :         while (pred(text, stop)) {
    1031               0 :             const char* curr = text;
    1032               0 :             SkFixed x = advance(glyphCacheProc(cache, &text), xyIndex);
    1033               0 :             if ((width += x) > max) {
    1034               0 :                 width -= x;
    1035               0 :                 text = curr;
    1036               0 :                 break;
    1037                 :             }
    1038                 :         }
    1039                 :     }
    1040                 : 
    1041               0 :     if (measuredWidth) {
    1042               0 :         SkScalar scalarWidth = Sk48Dot16ToScalar(width);
    1043               0 :         if (scale) {
    1044               0 :             scalarWidth = SkScalarMul(scalarWidth, scale);
    1045                 :         }
    1046               0 :         *measuredWidth = scalarWidth;
    1047                 :     }
    1048                 : 
    1049                 :     // return the number of bytes measured
    1050                 :     return (kForward_TextBufferDirection == tbd) ?
    1051               0 :                 text - stop + length : stop - text + length;
    1052                 : }
    1053                 : 
    1054                 : ///////////////////////////////////////////////////////////////////////////////
    1055                 : 
    1056               0 : static bool FontMetricsCacheProc(const SkGlyphCache* cache, void* context) {
    1057               0 :     *(SkPaint::FontMetrics*)context = cache->getFontMetricsY();
    1058               0 :     return false;   // don't detach the cache
    1059                 : }
    1060                 : 
    1061               0 : static void FontMetricsDescProc(const SkDescriptor* desc, void* context) {
    1062               0 :     SkGlyphCache::VisitCache(desc, FontMetricsCacheProc, context);
    1063               0 : }
    1064                 : 
    1065               0 : SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const {
    1066               0 :     SkScalar                            scale = 0;
    1067               0 :     SkAutoRestorePaintTextSizeAndFrame  restore(this);
    1068                 : 
    1069               0 :     if (this->isLinearText()) {
    1070               0 :         scale = fTextSize / kCanonicalTextSizeForPaths;
    1071                 :         // this gets restored by restore
    1072               0 :         ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths));
    1073                 :     }
    1074                 : 
    1075               0 :     SkMatrix zoomMatrix, *zoomPtr = NULL;
    1076               0 :     if (zoom) {
    1077               0 :         zoomMatrix.setScale(zoom, zoom);
    1078               0 :         zoomPtr = &zoomMatrix;
    1079                 :     }
    1080                 : 
    1081                 : #if 0
    1082                 :     SkAutoGlyphCache    autoCache(*this, zoomPtr);
    1083                 :     SkGlyphCache*       cache = autoCache.getCache();
    1084                 :     const FontMetrics&  my = cache->getFontMetricsY();
    1085                 : #endif
    1086                 :     FontMetrics storage;
    1087               0 :     if (NULL == metrics) {
    1088               0 :         metrics = &storage;
    1089                 :     }
    1090                 : 
    1091               0 :     this->descriptorProc(zoomPtr, FontMetricsDescProc, metrics, true);
    1092                 : 
    1093               0 :     if (scale) {
    1094               0 :         metrics->fTop = SkScalarMul(metrics->fTop, scale);
    1095               0 :         metrics->fAscent = SkScalarMul(metrics->fAscent, scale);
    1096               0 :         metrics->fDescent = SkScalarMul(metrics->fDescent, scale);
    1097               0 :         metrics->fBottom = SkScalarMul(metrics->fBottom, scale);
    1098               0 :         metrics->fLeading = SkScalarMul(metrics->fLeading, scale);
    1099                 :     }
    1100               0 :     return metrics->fDescent - metrics->fAscent + metrics->fLeading;
    1101                 : }
    1102                 : 
    1103                 : ///////////////////////////////////////////////////////////////////////////////
    1104                 : 
    1105               0 : static void set_bounds(const SkGlyph& g, SkRect* bounds, SkScalar scale) {
    1106                 :     bounds->set(g.fLeft * scale,
    1107                 :                 g.fTop * scale,
    1108                 :                 (g.fLeft + g.fWidth) * scale,
    1109               0 :                 (g.fTop + g.fHeight) * scale);
    1110               0 : }
    1111                 : 
    1112               0 : int SkPaint::getTextWidths(const void* textData, size_t byteLength,
    1113                 :                            SkScalar widths[], SkRect bounds[]) const {
    1114               0 :     if (0 == byteLength) {
    1115               0 :         return 0;
    1116                 :     }
    1117                 : 
    1118               0 :     SkASSERT(NULL != textData);
    1119                 : 
    1120               0 :     if (NULL == widths && NULL == bounds) {
    1121               0 :         return this->countText(textData, byteLength);
    1122                 :     }
    1123                 : 
    1124               0 :     SkAutoRestorePaintTextSizeAndFrame  restore(this);
    1125               0 :     SkScalar                            scale = 0;
    1126                 : 
    1127               0 :     if (this->isLinearText()) {
    1128               0 :         scale = fTextSize / kCanonicalTextSizeForPaths;
    1129                 :         // this gets restored by restore
    1130               0 :         ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths));
    1131                 :     }
    1132                 : 
    1133               0 :     SkAutoGlyphCache    autoCache(*this, NULL);
    1134               0 :     SkGlyphCache*       cache = autoCache.getCache();
    1135                 :     SkMeasureCacheProc  glyphCacheProc;
    1136                 :     glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection,
    1137               0 :                                                NULL != bounds);
    1138                 : 
    1139               0 :     const char* text = (const char*)textData;
    1140               0 :     const char* stop = text + byteLength;
    1141               0 :     int         count = 0;
    1142               0 :     const int   xyIndex = this->isVerticalText() ? 1 : 0;
    1143                 : 
    1144               0 :     if (this->isDevKernText()) {
    1145                 :         // we adjust the widths returned here through auto-kerning
    1146               0 :         SkAutoKern  autokern;
    1147               0 :         SkFixed     prevWidth = 0;
    1148                 : 
    1149               0 :         if (scale) {
    1150               0 :             while (text < stop) {
    1151               0 :                 const SkGlyph& g = glyphCacheProc(cache, &text);
    1152               0 :                 if (widths) {
    1153               0 :                     SkFixed  adjust = autokern.adjust(g);
    1154                 : 
    1155               0 :                     if (count > 0) {
    1156               0 :                         SkScalar w = SkFixedToScalar(prevWidth + adjust);
    1157               0 :                         *widths++ = SkScalarMul(w, scale);
    1158                 :                     }
    1159               0 :                     prevWidth = advance(g, xyIndex);
    1160                 :                 }
    1161               0 :                 if (bounds) {
    1162               0 :                     set_bounds(g, bounds++, scale);
    1163                 :                 }
    1164               0 :                 ++count;
    1165                 :             }
    1166               0 :             if (count > 0 && widths) {
    1167               0 :                 *widths = SkScalarMul(SkFixedToScalar(prevWidth), scale);
    1168                 :             }
    1169                 :         } else {
    1170               0 :             while (text < stop) {
    1171               0 :                 const SkGlyph& g = glyphCacheProc(cache, &text);
    1172               0 :                 if (widths) {
    1173               0 :                     SkFixed  adjust = autokern.adjust(g);
    1174                 : 
    1175               0 :                     if (count > 0) {
    1176               0 :                         *widths++ = SkFixedToScalar(prevWidth + adjust);
    1177                 :                     }
    1178               0 :                     prevWidth = advance(g, xyIndex);
    1179                 :                 }
    1180               0 :                 if (bounds) {
    1181               0 :                     set_bounds(g, bounds++);
    1182                 :                 }
    1183               0 :                 ++count;
    1184                 :             }
    1185               0 :             if (count > 0 && widths) {
    1186               0 :                 *widths = SkFixedToScalar(prevWidth);
    1187                 :             }
    1188                 :         }
    1189                 :     } else {    // no devkern
    1190               0 :         if (scale) {
    1191               0 :             while (text < stop) {
    1192               0 :                 const SkGlyph& g = glyphCacheProc(cache, &text);
    1193               0 :                 if (widths) {
    1194               0 :                     *widths++ = SkScalarMul(SkFixedToScalar(advance(g, xyIndex)),
    1195               0 :                                             scale);
    1196                 :                 }
    1197               0 :                 if (bounds) {
    1198               0 :                     set_bounds(g, bounds++, scale);
    1199                 :                 }
    1200               0 :                 ++count;
    1201                 :             }
    1202                 :         } else {
    1203               0 :             while (text < stop) {
    1204               0 :                 const SkGlyph& g = glyphCacheProc(cache, &text);
    1205               0 :                 if (widths) {
    1206               0 :                     *widths++ = SkFixedToScalar(advance(g, xyIndex));
    1207                 :                 }
    1208               0 :                 if (bounds) {
    1209               0 :                     set_bounds(g, bounds++);
    1210                 :                 }
    1211               0 :                 ++count;
    1212                 :             }
    1213                 :         }
    1214                 :     }
    1215                 : 
    1216               0 :     SkASSERT(text == stop);
    1217               0 :     return count;
    1218                 : }
    1219                 : 
    1220                 : ///////////////////////////////////////////////////////////////////////////////
    1221                 : 
    1222                 : #include "SkDraw.h"
    1223                 : 
    1224               0 : void SkPaint::getTextPath(const void* textData, size_t length,
    1225                 :                           SkScalar x, SkScalar y, SkPath* path) const {
    1226               0 :     SkASSERT(length == 0 || textData != NULL);
    1227                 : 
    1228               0 :     const char* text = (const char*)textData;
    1229               0 :     if (text == NULL || length == 0 || path == NULL) {
    1230               0 :         return;
    1231                 :     }
    1232                 : 
    1233               0 :     SkTextToPathIter    iter(text, length, *this, false, true);
    1234                 :     SkMatrix            matrix;
    1235               0 :     SkScalar            prevXPos = 0;
    1236                 : 
    1237               0 :     matrix.setScale(iter.getPathScale(), iter.getPathScale());
    1238               0 :     matrix.postTranslate(x, y);
    1239               0 :     path->reset();
    1240                 : 
    1241                 :     SkScalar        xpos;
    1242                 :     const SkPath*   iterPath;
    1243               0 :     while ((iterPath = iter.next(&xpos)) != NULL) {
    1244               0 :         matrix.postTranslate(xpos - prevXPos, 0);
    1245               0 :         path->addPath(*iterPath, matrix);
    1246               0 :         prevXPos = xpos;
    1247                 :     }
    1248                 : }
    1249                 : 
    1250               0 : void SkPaint::getPosTextPath(const void* textData, size_t length,
    1251                 :                              const SkPoint pos[], SkPath* path) const {
    1252               0 :     SkASSERT(length == 0 || textData != NULL);
    1253                 : 
    1254               0 :     const char* text = (const char*)textData;
    1255               0 :     if (text == NULL || length == 0 || path == NULL) {
    1256               0 :         return;
    1257                 :     }
    1258                 : 
    1259               0 :     SkTextToPathIter    iter(text, length, *this, false, true);
    1260                 :     SkMatrix            matrix;
    1261                 :     SkPoint             prevPos;
    1262               0 :     prevPos.set(0, 0);
    1263                 : 
    1264               0 :     matrix.setScale(iter.getPathScale(), iter.getPathScale());
    1265               0 :     path->reset();
    1266                 : 
    1267               0 :     unsigned int    i = 0;
    1268                 :     const SkPath*   iterPath;
    1269               0 :     while ((iterPath = iter.next(NULL)) != NULL) {
    1270               0 :         matrix.postTranslate(pos[i].fX - prevPos.fX, pos[i].fY - prevPos.fY);
    1271               0 :         path->addPath(*iterPath, matrix);
    1272               0 :         prevPos = pos[i];
    1273               0 :         i++;
    1274                 :     }
    1275                 : }
    1276                 : 
    1277               0 : static void add_flattenable(SkDescriptor* desc, uint32_t tag,
    1278                 :                             SkFlattenableWriteBuffer* buffer) {
    1279               0 :     buffer->flatten(desc->addEntry(tag, buffer->size(), NULL));
    1280               0 : }
    1281                 : 
    1282                 : // SkFontHost can override this choice in FilterRec()
    1283               0 : static SkMask::Format computeMaskFormat(const SkPaint& paint) {
    1284               0 :     uint32_t flags = paint.getFlags();
    1285                 : 
    1286                 :     // Antialiasing being disabled trumps all other settings.
    1287               0 :     if (!(flags & SkPaint::kAntiAlias_Flag)) {
    1288               0 :         return SkMask::kBW_Format;
    1289                 :     }
    1290                 : 
    1291               0 :     if (flags & SkPaint::kLCDRenderText_Flag) {
    1292               0 :         return SkMask::kLCD16_Format;
    1293                 :     }
    1294                 : 
    1295               0 :     return SkMask::kA8_Format;
    1296                 : }
    1297                 : 
    1298                 : // if linear-text is on, then we force hinting to be off (since that's sort of
    1299                 : // the point of linear-text.
    1300               0 : static SkPaint::Hinting computeHinting(const SkPaint& paint) {
    1301               0 :     SkPaint::Hinting h = paint.getHinting();
    1302               0 :     if (paint.isLinearText()) {
    1303               0 :         h = SkPaint::kNo_Hinting;
    1304                 :     }
    1305               0 :     return h;
    1306                 : }
    1307                 : 
    1308                 : // return true if the paint is just a single color (i.e. not a shader). If its
    1309                 : // a shader, then we can't compute a const luminance for it :(
    1310               0 : static bool justAColor(const SkPaint& paint, SkColor* color) {
    1311               0 :     if (paint.getShader()) {
    1312               0 :         return false;
    1313                 :     }
    1314               0 :     SkColor c = paint.getColor();
    1315               0 :     if (paint.getColorFilter()) {
    1316               0 :         c = paint.getColorFilter()->filterColor(c);
    1317                 :     }
    1318               0 :     if (color) {
    1319               0 :         *color = c;
    1320                 :     }
    1321               0 :     return true;
    1322                 : }
    1323                 : 
    1324                 : // returns 0..kLuminance_Max
    1325               0 : static unsigned computeLuminance(const SkPaint& paint) {
    1326                 :     SkColor c;
    1327               0 :     if (justAColor(paint, &c)) {
    1328               0 :         int r = SkColorGetR(c);
    1329               0 :         int g = SkColorGetG(c);
    1330               0 :         int b = SkColorGetB(c);
    1331                 :         // compute luminance
    1332                 :         // R=0.2126 G=0.7152 B=0.0722
    1333                 :         // scaling by 127 yields 27, 92, 9
    1334                 : #if 1
    1335               0 :         int luminance = r * 27 + g * 92 + b * 9;
    1336               0 :         luminance >>= 15 - SkScalerContext::kLuminance_Bits;
    1337                 : #else
    1338                 :         int luminance = r * 2 + g * 5 + b * 1;
    1339                 :         luminance >>= 11 - SkScalerContext::kLuminance_Bits;
    1340                 : #endif
    1341               0 :         SkASSERT(luminance <= SkScalerContext::kLuminance_Max);
    1342               0 :         return luminance;
    1343                 :     }
    1344                 :     // if we're not a single color, return the middle of the luminance range
    1345               0 :     return SkScalerContext::kLuminance_Max >> 1;
    1346                 : }
    1347                 : 
    1348                 : // Beyond this size, LCD doesn't appreciably improve quality, but it always
    1349                 : // cost more RAM and draws slower, so we set a cap.
    1350                 : #ifndef SK_MAX_SIZE_FOR_LCDTEXT
    1351                 :     #define SK_MAX_SIZE_FOR_LCDTEXT    48
    1352                 : #endif
    1353                 : 
    1354               0 : static bool tooBigForLCD(const SkScalerContext::Rec& rec) {
    1355               0 :     SkScalar area = SkScalarMul(rec.fPost2x2[0][0], rec.fPost2x2[1][1]) -
    1356               0 :                     SkScalarMul(rec.fPost2x2[1][0], rec.fPost2x2[0][1]);
    1357               0 :     SkScalar size = SkScalarMul(area, rec.fTextSize);
    1358               0 :     return SkScalarAbs(size) > SkIntToScalar(SK_MAX_SIZE_FOR_LCDTEXT);
    1359                 : }
    1360                 : 
    1361                 : /*
    1362                 :  *  Return the scalar with only limited fractional precision. Used to consolidate matrices
    1363                 :  *  that vary only slightly when we create our key into the font cache, since the font scaler
    1364                 :  *  typically returns the same looking resuts for tiny changes in the matrix.
    1365                 :  */
    1366               0 : static SkScalar sk_relax(SkScalar x) {
    1367                 : #ifdef SK_SCALAR_IS_FLOAT
    1368               0 :     int n = sk_float_round2int(x * 1024);
    1369               0 :     return n / 1024.0f;
    1370                 : #else
    1371                 :     // round to the nearest 10 fractional bits
    1372                 :     return (x + (1 << 5)) & ~(1024 - 1);
    1373                 : #endif
    1374                 : }
    1375                 : 
    1376               0 : void SkScalerContext::MakeRec(const SkPaint& paint,
    1377                 :                               const SkMatrix* deviceMatrix, Rec* rec) {
    1378               0 :     SkASSERT(deviceMatrix == NULL || !deviceMatrix->hasPerspective());
    1379                 : 
    1380               0 :     rec->fOrigFontID = SkTypeface::UniqueID(paint.getTypeface());
    1381               0 :     rec->fFontID = rec->fOrigFontID;
    1382               0 :     rec->fTextSize = paint.getTextSize();
    1383               0 :     rec->fPreScaleX = paint.getTextScaleX();
    1384               0 :     rec->fPreSkewX  = paint.getTextSkewX();
    1385                 : 
    1386               0 :     if (deviceMatrix) {
    1387               0 :         rec->fPost2x2[0][0] = sk_relax(deviceMatrix->getScaleX());
    1388               0 :         rec->fPost2x2[0][1] = sk_relax(deviceMatrix->getSkewX());
    1389               0 :         rec->fPost2x2[1][0] = sk_relax(deviceMatrix->getSkewY());
    1390               0 :         rec->fPost2x2[1][1] = sk_relax(deviceMatrix->getScaleY());
    1391                 :     } else {
    1392               0 :         rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1;
    1393               0 :         rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0;
    1394                 :     }
    1395                 : 
    1396               0 :     SkPaint::Style  style = paint.getStyle();
    1397               0 :     SkScalar        strokeWidth = paint.getStrokeWidth();
    1398                 : 
    1399               0 :     unsigned flags = 0;
    1400                 : 
    1401               0 :     if (paint.isFakeBoldText()) {
    1402                 : #ifdef SK_USE_FREETYPE_EMBOLDEN
    1403                 :         flags |= SkScalerContext::kEmbolden_Flag;
    1404                 : #else
    1405                 :         SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(),
    1406                 :                                                     kStdFakeBoldInterpKeys,
    1407                 :                                                     kStdFakeBoldInterpValues,
    1408               0 :                                                     kStdFakeBoldInterpLength);
    1409               0 :         SkScalar extra = SkScalarMul(paint.getTextSize(), fakeBoldScale);
    1410                 : 
    1411               0 :         if (style == SkPaint::kFill_Style) {
    1412               0 :             style = SkPaint::kStrokeAndFill_Style;
    1413               0 :             strokeWidth = extra;    // ignore paint's strokeWidth if it was "fill"
    1414                 :         } else {
    1415               0 :             strokeWidth += extra;
    1416                 :         }
    1417                 : #endif
    1418                 :     }
    1419                 : 
    1420               0 :     if (paint.isDevKernText()) {
    1421               0 :         flags |= SkScalerContext::kDevKernText_Flag;
    1422                 :     }
    1423                 : 
    1424               0 :     if (style != SkPaint::kFill_Style && strokeWidth > 0) {
    1425               0 :         rec->fFrameWidth = strokeWidth;
    1426               0 :         rec->fMiterLimit = paint.getStrokeMiter();
    1427               0 :         rec->fStrokeJoin = SkToU8(paint.getStrokeJoin());
    1428                 : 
    1429               0 :         if (style == SkPaint::kStrokeAndFill_Style) {
    1430               0 :             flags |= SkScalerContext::kFrameAndFill_Flag;
    1431                 :         }
    1432                 :     } else {
    1433               0 :         rec->fFrameWidth = 0;
    1434               0 :         rec->fMiterLimit = 0;
    1435               0 :         rec->fStrokeJoin = 0;
    1436                 :     }
    1437                 : 
    1438               0 :     rec->fMaskFormat = SkToU8(computeMaskFormat(paint));
    1439                 : 
    1440               0 :     if (SkMask::kLCD16_Format == rec->fMaskFormat ||
    1441                 :         SkMask::kLCD32_Format == rec->fMaskFormat)
    1442                 :     {
    1443               0 :         SkFontHost::LCDOrder order = SkFontHost::GetSubpixelOrder();
    1444               0 :         SkFontHost::LCDOrientation orient = SkFontHost::GetSubpixelOrientation();
    1445               0 :         if (SkFontHost::kNONE_LCDOrder == order || tooBigForLCD(*rec)) {
    1446                 :             // eeek, can't support LCD
    1447               0 :             rec->fMaskFormat = SkMask::kA8_Format;
    1448                 :         } else {
    1449               0 :             if (SkFontHost::kVertical_LCDOrientation == orient) {
    1450               0 :                 flags |= SkScalerContext::kLCD_Vertical_Flag;
    1451                 :             }
    1452               0 :             if (SkFontHost::kBGR_LCDOrder == order) {
    1453               0 :                 flags |= SkScalerContext::kLCD_BGROrder_Flag;
    1454                 :             }
    1455                 :         }
    1456                 :     }
    1457                 : 
    1458               0 :     if (paint.isEmbeddedBitmapText()) {
    1459               0 :         flags |= SkScalerContext::kEmbeddedBitmapText_Flag;
    1460                 :     }
    1461               0 :     if (paint.isSubpixelText()) {
    1462               0 :         flags |= SkScalerContext::kSubpixelPositioning_Flag;
    1463                 :     }
    1464               0 :     if (paint.isAutohinted()) {
    1465               0 :         flags |= SkScalerContext::kAutohinting_Flag;
    1466                 :     }
    1467               0 :     if (paint.isVerticalText()) {
    1468               0 :         flags |= SkScalerContext::kVertical_Flag;
    1469                 :     }
    1470               0 :     rec->fFlags = SkToU16(flags);
    1471                 : 
    1472                 :     // these modify fFlags, so do them after assigning fFlags
    1473               0 :     rec->setHinting(computeHinting(paint));
    1474               0 :     rec->setLuminanceBits(computeLuminance(paint));
    1475                 : 
    1476                 :     /*  Allow the fonthost to modify our rec before we use it as a key into the
    1477                 :         cache. This way if we're asking for something that they will ignore,
    1478                 :         they can modify our rec up front, so we don't create duplicate cache
    1479                 :         entries.
    1480                 :      */
    1481               0 :     SkFontHost::FilterRec(rec);
    1482                 : 
    1483                 :     // No need to differentiate gamma if we're BW
    1484               0 :     if (SkMask::kBW_Format == rec->fMaskFormat) {
    1485               0 :         rec->setLuminanceBits(0);
    1486                 :     }
    1487               0 : }
    1488                 : 
    1489                 : #define MIN_SIZE_FOR_EFFECT_BUFFER  1024
    1490                 : 
    1491                 : #ifdef SK_DEBUG
    1492                 :     #define TEST_DESC
    1493                 : #endif
    1494                 : 
    1495                 : /*
    1496                 :  *  ignoreGamma tells us that the caller just wants metrics that are unaffected
    1497                 :  *  by gamma correction, so we jam the luminance field to 0 (most common value
    1498                 :  *  for black text) in hopes that we get a cache hit easier. A better solution
    1499                 :  *  would be for the fontcache lookup to know to ignore the luminance field
    1500                 :  *  entirely, but not sure how to do that and keep it fast.
    1501                 :  */
    1502               0 : void SkPaint::descriptorProc(const SkMatrix* deviceMatrix,
    1503                 :                              void (*proc)(const SkDescriptor*, void*),
    1504                 :                              void* context, bool ignoreGamma) const {
    1505                 :     SkScalerContext::Rec    rec;
    1506                 : 
    1507               0 :     SkScalerContext::MakeRec(*this, deviceMatrix, &rec);
    1508               0 :     if (ignoreGamma) {
    1509               0 :         rec.setLuminanceBits(0);
    1510                 :     }
    1511                 : 
    1512               0 :     size_t          descSize = sizeof(rec);
    1513               0 :     int             entryCount = 1;
    1514               0 :     SkPathEffect*   pe = this->getPathEffect();
    1515               0 :     SkMaskFilter*   mf = this->getMaskFilter();
    1516               0 :     SkRasterizer*   ra = this->getRasterizer();
    1517                 : 
    1518               0 :     SkFlattenableWriteBuffer    peBuffer(MIN_SIZE_FOR_EFFECT_BUFFER);
    1519               0 :     SkFlattenableWriteBuffer    mfBuffer(MIN_SIZE_FOR_EFFECT_BUFFER);
    1520               0 :     SkFlattenableWriteBuffer    raBuffer(MIN_SIZE_FOR_EFFECT_BUFFER);
    1521                 : 
    1522               0 :     if (pe) {
    1523               0 :         peBuffer.writeFlattenable(pe);
    1524               0 :         descSize += peBuffer.size();
    1525               0 :         entryCount += 1;
    1526               0 :         rec.fMaskFormat = SkMask::kA8_Format;   // force antialiasing when we do the scan conversion
    1527                 :         // seems like we could support kLCD as well at this point...
    1528                 :     }
    1529               0 :     if (mf) {
    1530               0 :         mfBuffer.writeFlattenable(mf);
    1531               0 :         descSize += mfBuffer.size();
    1532               0 :         entryCount += 1;
    1533               0 :         rec.fMaskFormat = SkMask::kA8_Format;   // force antialiasing with maskfilters
    1534                 :     }
    1535               0 :     if (ra) {
    1536               0 :         raBuffer.writeFlattenable(ra);
    1537               0 :         descSize += raBuffer.size();
    1538               0 :         entryCount += 1;
    1539               0 :         rec.fMaskFormat = SkMask::kA8_Format;   // force antialiasing when we do the scan conversion
    1540                 :     }
    1541               0 :     descSize += SkDescriptor::ComputeOverhead(entryCount);
    1542                 : 
    1543               0 :     SkAutoDescriptor    ad(descSize);
    1544               0 :     SkDescriptor*       desc = ad.getDesc();
    1545                 : 
    1546               0 :     desc->init();
    1547               0 :     desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
    1548                 : 
    1549               0 :     if (pe) {
    1550               0 :         add_flattenable(desc, kPathEffect_SkDescriptorTag, &peBuffer);
    1551                 :     }
    1552               0 :     if (mf) {
    1553               0 :         add_flattenable(desc, kMaskFilter_SkDescriptorTag, &mfBuffer);
    1554                 :     }
    1555               0 :     if (ra) {
    1556               0 :         add_flattenable(desc, kRasterizer_SkDescriptorTag, &raBuffer);
    1557                 :     }
    1558                 : 
    1559               0 :     SkASSERT(descSize == desc->getLength());
    1560               0 :     desc->computeChecksum();
    1561                 : 
    1562                 : #ifdef TEST_DESC
    1563                 :     {
    1564                 :         // Check that we completely write the bytes in desc (our key), and that
    1565                 :         // there are no uninitialized bytes. If there were, then we would get
    1566                 :         // false-misses (or worse, false-hits) in our fontcache.
    1567                 :         //
    1568                 :         // We do this buy filling 2 others, one with 0s and the other with 1s
    1569                 :         // and create those, and then check that all 3 are identical.
    1570               0 :         SkAutoDescriptor    ad1(descSize);
    1571               0 :         SkAutoDescriptor    ad2(descSize);
    1572               0 :         SkDescriptor*       desc1 = ad1.getDesc();
    1573               0 :         SkDescriptor*       desc2 = ad2.getDesc();
    1574                 :         
    1575               0 :         memset(desc1, 0x00, descSize);
    1576               0 :         memset(desc2, 0xFF, descSize);
    1577                 :         
    1578               0 :         desc1->init();
    1579               0 :         desc2->init();
    1580               0 :         desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
    1581               0 :         desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
    1582                 :         
    1583               0 :         if (pe) {
    1584               0 :             add_flattenable(desc1, kPathEffect_SkDescriptorTag, &peBuffer);
    1585               0 :             add_flattenable(desc2, kPathEffect_SkDescriptorTag, &peBuffer);
    1586                 :         }
    1587               0 :         if (mf) {
    1588               0 :             add_flattenable(desc1, kMaskFilter_SkDescriptorTag, &mfBuffer);
    1589               0 :             add_flattenable(desc2, kMaskFilter_SkDescriptorTag, &mfBuffer);
    1590                 :         }
    1591               0 :         if (ra) {
    1592               0 :             add_flattenable(desc1, kRasterizer_SkDescriptorTag, &raBuffer);
    1593               0 :             add_flattenable(desc2, kRasterizer_SkDescriptorTag, &raBuffer);
    1594                 :         }
    1595                 :         
    1596               0 :         SkASSERT(descSize == desc1->getLength());
    1597               0 :         SkASSERT(descSize == desc2->getLength());
    1598               0 :         desc1->computeChecksum();
    1599               0 :         desc2->computeChecksum();
    1600               0 :         SkASSERT(!memcmp(desc, desc1, descSize));
    1601               0 :         SkASSERT(!memcmp(desc, desc2, descSize));
    1602                 :     }
    1603                 : #endif
    1604                 :     
    1605               0 :     proc(desc, context);
    1606               0 : }
    1607                 : 
    1608               0 : SkGlyphCache* SkPaint::detachCache(const SkMatrix* deviceMatrix) const {
    1609                 :     SkGlyphCache* cache;
    1610               0 :     this->descriptorProc(deviceMatrix, DetachDescProc, &cache);
    1611               0 :     return cache;
    1612                 : }
    1613                 : 
    1614                 : ///////////////////////////////////////////////////////////////////////////////
    1615                 : 
    1616                 : #include "SkStream.h"
    1617                 : 
    1618               0 : static uintptr_t asint(const void* p) {
    1619               0 :     return reinterpret_cast<uintptr_t>(p);
    1620                 : }
    1621                 : 
    1622                 : union Scalar32 {
    1623                 :     SkScalar    fScalar;
    1624                 :     uint32_t    f32;
    1625                 : };
    1626                 : 
    1627               0 : static uint32_t* write_scalar(uint32_t* ptr, SkScalar value) {
    1628                 :     SkASSERT(sizeof(SkScalar) == sizeof(uint32_t));
    1629                 :     Scalar32 tmp;
    1630               0 :     tmp.fScalar = value;
    1631               0 :     *ptr = tmp.f32;
    1632               0 :     return ptr + 1;
    1633                 : }
    1634                 : 
    1635               0 : static SkScalar read_scalar(const uint32_t*& ptr) {
    1636                 :     SkASSERT(sizeof(SkScalar) == sizeof(uint32_t));
    1637                 :     Scalar32 tmp;
    1638               0 :     tmp.f32 = *ptr++;
    1639               0 :     return tmp.fScalar;
    1640                 : }
    1641                 : 
    1642               0 : static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) {
    1643               0 :     SkASSERT(a == (uint8_t)a);
    1644               0 :     SkASSERT(b == (uint8_t)b);
    1645               0 :     SkASSERT(c == (uint8_t)c);
    1646               0 :     SkASSERT(d == (uint8_t)d);
    1647               0 :     return (a << 24) | (b << 16) | (c << 8) | d;
    1648                 : }
    1649                 : 
    1650                 : enum FlatFlags {
    1651                 :     kHasTypeface_FlatFlag   = 0x01,
    1652                 :     kHasEffects_FlatFlag    = 0x02
    1653                 : };
    1654                 : 
    1655                 : // The size of a flat paint's POD fields
    1656                 : static const uint32_t kPODPaintSize =   5 * sizeof(SkScalar) +
    1657                 :                                         1 * sizeof(SkColor) +
    1658                 :                                         1 * sizeof(uint16_t) +
    1659                 :                                         6 * sizeof(uint8_t);
    1660                 : 
    1661                 : /*  To save space/time, we analyze the paint, and write a truncated version of
    1662                 :     it if there are not tricky elements like shaders, etc.
    1663                 :  */
    1664               0 : void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const {
    1665               0 :     uint8_t flatFlags = 0;
    1666               0 :     if (this->getTypeface()) {
    1667               0 :         flatFlags |= kHasTypeface_FlatFlag;
    1668                 :     }
    1669               0 :     if (asint(this->getPathEffect()) |
    1670               0 :         asint(this->getShader()) |
    1671               0 :         asint(this->getXfermode()) |
    1672               0 :         asint(this->getMaskFilter()) |
    1673               0 :         asint(this->getColorFilter()) |
    1674               0 :         asint(this->getRasterizer()) |
    1675               0 :         asint(this->getLooper()) |
    1676               0 :         asint(this->getImageFilter())) {
    1677               0 :         flatFlags |= kHasEffects_FlatFlag;
    1678                 :     }
    1679                 : 
    1680                 :     SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize);
    1681               0 :     uint32_t* ptr = buffer.reserve(kPODPaintSize);
    1682                 : 
    1683               0 :     ptr = write_scalar(ptr, this->getTextSize());
    1684               0 :     ptr = write_scalar(ptr, this->getTextScaleX());
    1685               0 :     ptr = write_scalar(ptr, this->getTextSkewX());
    1686               0 :     ptr = write_scalar(ptr, this->getStrokeWidth());
    1687               0 :     ptr = write_scalar(ptr, this->getStrokeMiter());
    1688               0 :     *ptr++ = this->getColor();
    1689                 :     // previously flags:16, textAlign:8, flatFlags:8
    1690                 :     // now flags:16, hinting:4, textAlign:4, flatFlags:8
    1691               0 :     *ptr++ = (this->getFlags() << 16) |
    1692                 :              // hinting added later. 0 in this nibble means use the default.
    1693               0 :              ((this->getHinting()+1) << 12) |
    1694               0 :              (this->getTextAlign() << 8) |
    1695               0 :              flatFlags;
    1696               0 :     *ptr++ = pack_4(this->getStrokeCap(), this->getStrokeJoin(),
    1697               0 :                     this->getStyle(), this->getTextEncoding());
    1698                 : 
    1699                 :     // now we're done with ptr and the (pre)reserved space. If we need to write
    1700                 :     // additional fields, use the buffer directly
    1701               0 :     if (flatFlags & kHasTypeface_FlatFlag) {
    1702               0 :         buffer.writeTypeface(this->getTypeface());
    1703                 :     }
    1704               0 :     if (flatFlags & kHasEffects_FlatFlag) {
    1705               0 :         buffer.writeFlattenable(this->getPathEffect());
    1706               0 :         buffer.writeFlattenable(this->getShader());
    1707               0 :         buffer.writeFlattenable(this->getXfermode());
    1708               0 :         buffer.writeFlattenable(this->getMaskFilter());
    1709               0 :         buffer.writeFlattenable(this->getColorFilter());
    1710               0 :         buffer.writeFlattenable(this->getRasterizer());
    1711               0 :         buffer.writeFlattenable(this->getLooper());
    1712               0 :         buffer.writeFlattenable(this->getImageFilter());
    1713                 :     }
    1714               0 : }
    1715                 : 
    1716               0 : void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) {
    1717                 :     SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize);
    1718               0 :     const void* podData = buffer.skip(kPODPaintSize);
    1719               0 :     const uint32_t* pod = reinterpret_cast<const uint32_t*>(podData);
    1720                 : 
    1721                 :     // the order we read must match the order we wrote in flatten()
    1722               0 :     this->setTextSize(read_scalar(pod));
    1723               0 :     this->setTextScaleX(read_scalar(pod));
    1724               0 :     this->setTextSkewX(read_scalar(pod));
    1725               0 :     this->setStrokeWidth(read_scalar(pod));
    1726               0 :     this->setStrokeMiter(read_scalar(pod));
    1727               0 :     this->setColor(*pod++);
    1728                 : 
    1729                 :     // previously flags:16, textAlign:8, flatFlags:8
    1730                 :     // now flags:16, hinting:4, textAlign:4, flatFlags:8
    1731               0 :     uint32_t tmp = *pod++;
    1732               0 :     this->setFlags(tmp >> 16);
    1733                 : 
    1734                 :     // hinting added later. 0 in this nibble means use the default.
    1735               0 :     uint32_t hinting = (tmp >> 12) & 0xF;
    1736               0 :     this->setHinting(0 == hinting ? kNormal_Hinting : static_cast<Hinting>(hinting-1));
    1737                 : 
    1738               0 :     this->setTextAlign(static_cast<Align>((tmp >> 8) & 0xF));
    1739                 : 
    1740               0 :     uint8_t flatFlags = tmp & 0xFF;
    1741                 : 
    1742               0 :     tmp = *pod++;
    1743               0 :     this->setStrokeCap(static_cast<Cap>((tmp >> 24) & 0xFF));
    1744               0 :     this->setStrokeJoin(static_cast<Join>((tmp >> 16) & 0xFF));
    1745               0 :     this->setStyle(static_cast<Style>((tmp >> 8) & 0xFF));
    1746               0 :     this->setTextEncoding(static_cast<TextEncoding>((tmp >> 0) & 0xFF));
    1747                 : 
    1748               0 :     if (flatFlags & kHasTypeface_FlatFlag) {
    1749               0 :         this->setTypeface(buffer.readTypeface());
    1750                 :     } else {
    1751               0 :         this->setTypeface(NULL);
    1752                 :     }
    1753                 : 
    1754               0 :     if (flatFlags & kHasEffects_FlatFlag) {
    1755               0 :         SkSafeUnref(this->setPathEffect((SkPathEffect*) buffer.readFlattenable()));
    1756               0 :         SkSafeUnref(this->setShader((SkShader*) buffer.readFlattenable()));
    1757               0 :         SkSafeUnref(this->setXfermode((SkXfermode*) buffer.readFlattenable()));
    1758               0 :         SkSafeUnref(this->setMaskFilter((SkMaskFilter*) buffer.readFlattenable()));
    1759               0 :         SkSafeUnref(this->setColorFilter((SkColorFilter*) buffer.readFlattenable()));
    1760               0 :         SkSafeUnref(this->setRasterizer((SkRasterizer*) buffer.readFlattenable()));
    1761               0 :         SkSafeUnref(this->setLooper((SkDrawLooper*) buffer.readFlattenable()));
    1762               0 :         SkSafeUnref(this->setImageFilter((SkImageFilter*) buffer.readFlattenable()));
    1763                 :     } else {
    1764               0 :         this->setPathEffect(NULL);
    1765               0 :         this->setShader(NULL);
    1766               0 :         this->setXfermode(NULL);
    1767               0 :         this->setMaskFilter(NULL);
    1768               0 :         this->setColorFilter(NULL);
    1769               0 :         this->setRasterizer(NULL);
    1770               0 :         this->setLooper(NULL);
    1771               0 :         this->setImageFilter(NULL);
    1772                 :     }
    1773               0 : }
    1774                 : 
    1775                 : ///////////////////////////////////////////////////////////////////////////////
    1776                 : 
    1777               0 : SkShader* SkPaint::setShader(SkShader* shader) {
    1778                 :     GEN_ID_INC_EVAL(shader != fShader);
    1779               0 :     SkRefCnt_SafeAssign(fShader, shader);
    1780               0 :     return shader;
    1781                 : }
    1782                 : 
    1783               0 : SkColorFilter* SkPaint::setColorFilter(SkColorFilter* filter) {
    1784                 :     GEN_ID_INC_EVAL(filter != fColorFilter);
    1785               0 :     SkRefCnt_SafeAssign(fColorFilter, filter);
    1786               0 :     return filter;
    1787                 : }
    1788                 : 
    1789               0 : SkXfermode* SkPaint::setXfermode(SkXfermode* mode) {
    1790                 :     GEN_ID_INC_EVAL(mode != fXfermode);
    1791               0 :     SkRefCnt_SafeAssign(fXfermode, mode);
    1792               0 :     return mode;
    1793                 : }
    1794                 : 
    1795               0 : SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) {
    1796               0 :     SkSafeUnref(fXfermode);
    1797               0 :     fXfermode = SkXfermode::Create(mode);
    1798                 :     GEN_ID_INC;
    1799               0 :     return fXfermode;
    1800                 : }
    1801                 : 
    1802               0 : SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect) {
    1803                 :     GEN_ID_INC_EVAL(effect != fPathEffect);
    1804               0 :     SkRefCnt_SafeAssign(fPathEffect, effect);
    1805               0 :     return effect;
    1806                 : }
    1807                 : 
    1808               0 : SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter) {
    1809                 :     GEN_ID_INC_EVAL(filter != fMaskFilter);
    1810               0 :     SkRefCnt_SafeAssign(fMaskFilter, filter);
    1811               0 :     return filter;
    1812                 : }
    1813                 : 
    1814                 : ///////////////////////////////////////////////////////////////////////////////
    1815                 : 
    1816               0 : bool SkPaint::getFillPath(const SkPath& src, SkPath* dst) const {
    1817               0 :     SkPath          effectPath, strokePath;
    1818               0 :     const SkPath*   path = &src;
    1819                 : 
    1820               0 :     SkScalar width = this->getStrokeWidth();
    1821                 : 
    1822               0 :     switch (this->getStyle()) {
    1823                 :         case SkPaint::kFill_Style:
    1824               0 :             width = -1; // mark it as no-stroke
    1825               0 :             break;
    1826                 :         case SkPaint::kStrokeAndFill_Style:
    1827               0 :             if (width == 0) {
    1828               0 :                 width = -1; // mark it as no-stroke
    1829                 :             }
    1830               0 :             break;
    1831                 :         case SkPaint::kStroke_Style:
    1832               0 :             break;
    1833                 :         default:
    1834               0 :             SkDEBUGFAIL("unknown paint style");
    1835                 :     }
    1836                 : 
    1837               0 :     if (this->getPathEffect()) {
    1838                 :         // lie to the pathEffect if our style is strokeandfill, so that it treats us as just fill
    1839               0 :         if (this->getStyle() == SkPaint::kStrokeAndFill_Style) {
    1840               0 :             width = -1; // mark it as no-stroke
    1841                 :         }
    1842                 : 
    1843               0 :         if (this->getPathEffect()->filterPath(&effectPath, src, &width)) {
    1844               0 :             path = &effectPath;
    1845                 :         }
    1846                 : 
    1847                 :         // restore the width if we earlier had to lie, and if we're still set to no-stroke
    1848                 :         // note: if we're now stroke (width >= 0), then the pathEffect asked for that change
    1849                 :         // and we want to respect that (i.e. don't overwrite their setting for width)
    1850               0 :         if (this->getStyle() == SkPaint::kStrokeAndFill_Style && width < 0) {
    1851               0 :             width = this->getStrokeWidth();
    1852               0 :             if (width == 0) {
    1853               0 :                 width = -1;
    1854                 :             }
    1855                 :         }
    1856                 :     }
    1857                 : 
    1858               0 :     if (width > 0 && !path->isEmpty()) {
    1859               0 :         SkStroke stroker(*this, width);
    1860               0 :         stroker.strokePath(*path, &strokePath);
    1861               0 :         path = &strokePath;
    1862                 :     }
    1863                 : 
    1864               0 :     if (path == &src) {
    1865               0 :         *dst = src;
    1866                 :     } else {
    1867               0 :         SkASSERT(path == &effectPath || path == &strokePath);
    1868               0 :         dst->swap(*(SkPath*)path);
    1869                 :     }
    1870                 : 
    1871               0 :     return width != 0;  // return true if we're filled, or false if we're hairline (width == 0)
    1872                 : }
    1873                 : 
    1874               0 : const SkRect& SkPaint::computeStrokeFastBounds(const SkRect& src,
    1875                 :                                                SkRect* storage) const {
    1876               0 :     SkASSERT(storage);
    1877               0 :     SkASSERT(this->getStyle() != SkPaint::kFill_Style);
    1878                 : 
    1879                 :     // since we're stroked, outset the rect by the radius (and join type)
    1880               0 :     SkScalar radius = SkScalarHalf(this->getStrokeWidth());
    1881               0 :     if (0 == radius) {  // hairline
    1882               0 :         radius = SK_Scalar1;
    1883               0 :     } else if (this->getStrokeJoin() == SkPaint::kMiter_Join) {
    1884               0 :         SkScalar scale = this->getStrokeMiter();
    1885               0 :         if (scale > SK_Scalar1) {
    1886               0 :             radius = SkScalarMul(radius, scale);
    1887                 :         }
    1888                 :     }
    1889                 :     storage->set(src.fLeft - radius, src.fTop - radius,
    1890               0 :                  src.fRight + radius, src.fBottom + radius);
    1891               0 :     return *storage;
    1892                 : }
    1893                 : 
    1894                 : ///////////////////////////////////////////////////////////////////////////////
    1895                 : 
    1896               0 : static bool has_thick_frame(const SkPaint& paint) {
    1897               0 :     return  paint.getStrokeWidth() > 0 &&
    1898               0 :             paint.getStyle() != SkPaint::kFill_Style;
    1899                 : }
    1900                 : 
    1901               0 : SkTextToPathIter::SkTextToPathIter( const char text[], size_t length,
    1902                 :                                     const SkPaint& paint,
    1903                 :                                     bool applyStrokeAndPathEffects,
    1904               0 :                                     bool forceLinearTextOn) : fPaint(paint) {
    1905                 :     fGlyphCacheProc = paint.getMeasureCacheProc(SkPaint::kForward_TextBufferDirection,
    1906               0 :                                                 true);
    1907                 : 
    1908               0 :     if (forceLinearTextOn) {
    1909               0 :         fPaint.setLinearText(true);
    1910                 :     }
    1911               0 :     fPaint.setMaskFilter(NULL);   // don't want this affecting our path-cache lookup
    1912                 : 
    1913               0 :     if (fPaint.getPathEffect() == NULL && !has_thick_frame(fPaint)) {
    1914               0 :         applyStrokeAndPathEffects = false;
    1915                 :     }
    1916                 : 
    1917                 :     // can't use our canonical size if we need to apply patheffects/strokes
    1918               0 :     if (fPaint.isLinearText() && !applyStrokeAndPathEffects) {
    1919               0 :         fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
    1920               0 :         fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
    1921                 :     } else {
    1922               0 :         fScale = SK_Scalar1;
    1923                 :     }
    1924                 : 
    1925               0 :     if (!applyStrokeAndPathEffects) {
    1926               0 :         fPaint.setStyle(SkPaint::kFill_Style);
    1927               0 :         fPaint.setPathEffect(NULL);
    1928                 :     }
    1929                 : 
    1930               0 :     fCache = fPaint.detachCache(NULL);
    1931                 : 
    1932               0 :     SkPaint::Style  style = SkPaint::kFill_Style;
    1933               0 :     SkPathEffect*   pe = NULL;
    1934                 : 
    1935               0 :     if (!applyStrokeAndPathEffects) {
    1936               0 :         style = paint.getStyle();   // restore
    1937               0 :         pe = paint.getPathEffect();     // restore
    1938                 :     }
    1939               0 :     fPaint.setStyle(style);
    1940               0 :     fPaint.setPathEffect(pe);
    1941               0 :     fPaint.setMaskFilter(paint.getMaskFilter());    // restore
    1942                 : 
    1943                 :     // now compute fXOffset if needed
    1944                 : 
    1945               0 :     SkScalar xOffset = 0;
    1946               0 :     if (paint.getTextAlign() != SkPaint::kLeft_Align) { // need to measure first
    1947                 :         int      count;
    1948               0 :         SkScalar width = SkScalarMul(fPaint.measure_text(fCache, text, length,
    1949                 :                                                          &count, NULL), fScale);
    1950               0 :         if (paint.getTextAlign() == SkPaint::kCenter_Align) {
    1951               0 :             width = SkScalarHalf(width);
    1952                 :         }
    1953               0 :         xOffset = -width;
    1954                 :     }
    1955               0 :     fXPos = xOffset;
    1956               0 :     fPrevAdvance = 0;
    1957                 : 
    1958               0 :     fText = text;
    1959               0 :     fStop = text + length;
    1960                 :     
    1961               0 :     fXYIndex = paint.isVerticalText() ? 1 : 0;
    1962               0 : }
    1963                 : 
    1964               0 : SkTextToPathIter::~SkTextToPathIter() {
    1965               0 :     SkGlyphCache::AttachCache(fCache);
    1966               0 : }
    1967                 : 
    1968               0 : const SkPath* SkTextToPathIter::next(SkScalar* xpos) {
    1969               0 :     while (fText < fStop) {
    1970               0 :         const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText);
    1971                 : 
    1972               0 :         fXPos += SkScalarMul(SkFixedToScalar(fPrevAdvance + fAutoKern.adjust(glyph)), fScale);
    1973               0 :         fPrevAdvance = advance(glyph, fXYIndex);   // + fPaint.getTextTracking();
    1974                 : 
    1975               0 :         if (glyph.fWidth) {
    1976               0 :             if (xpos) {
    1977               0 :                 *xpos = fXPos;
    1978                 :             }
    1979               0 :             return fCache->findPath(glyph);
    1980                 :         }
    1981                 :     }
    1982               0 :     return NULL;
    1983                 : }
    1984                 : 
    1985                 : ///////////////////////////////////////////////////////////////////////////////
    1986                 : 
    1987               0 : bool SkPaint::nothingToDraw() const {
    1988               0 :     if (fLooper) {
    1989               0 :         return false;
    1990                 :     }
    1991                 :     SkXfermode::Mode mode;
    1992               0 :     if (SkXfermode::AsMode(fXfermode, &mode)) {
    1993               0 :         switch (mode) {
    1994                 :             case SkXfermode::kSrcOver_Mode:
    1995                 :             case SkXfermode::kSrcATop_Mode:
    1996                 :             case SkXfermode::kDstOut_Mode:
    1997                 :             case SkXfermode::kDstOver_Mode:
    1998                 :             case SkXfermode::kPlus_Mode:
    1999               0 :                 return 0 == this->getAlpha();
    2000                 :             case SkXfermode::kDst_Mode:
    2001               0 :                 return true;
    2002                 :             default:
    2003                 :                 break;
    2004                 :         }
    2005                 :     }
    2006               0 :     return false;
    2007                 : }
    2008                 : 
    2009                 : 
    2010                 : //////////// Move these to their own file soon.
    2011                 : 
    2012               0 : bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
    2013                 :                                 const SkMatrix& ctm,
    2014                 :                                 SkBitmap* result, SkIPoint* loc) {
    2015               0 :     SkASSERT(proxy);
    2016               0 :     SkASSERT(result);
    2017               0 :     SkASSERT(loc);
    2018                 :     /*
    2019                 :      *  Give the proxy first shot at the filter. If it returns false, ask
    2020                 :      *  the filter to do it.
    2021                 :      */
    2022               0 :     return proxy->filterImage(this, src, ctm, result, loc) ||
    2023               0 :            this->onFilterImage(proxy, src, ctm, result, loc);
    2024                 : }
    2025                 : 
    2026               0 : bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
    2027                 :                                  SkIRect* dst) {
    2028               0 :     SkASSERT(&src);
    2029               0 :     SkASSERT(dst);
    2030               0 :     return this->onFilterBounds(src, ctm, dst);
    2031                 : }
    2032                 : 
    2033               0 : bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
    2034                 :                                   SkBitmap*, SkIPoint*) {
    2035               0 :     return false;
    2036                 : }
    2037                 : 
    2038               0 : bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
    2039                 :                                    SkIRect* dst) {
    2040               0 :     *dst = src;
    2041               0 :     return true;
    2042                 : }
    2043                 : 
    2044               0 : bool SkImageFilter::asABlur(SkSize* sigma) const {
    2045               0 :     return false;
    2046            4392 : }
    2047                 : 

Generated by: LCOV version 1.7