Home | History | Annotate | Download | only in core
      1 /* libs/graphics/sgl/SkScalerContext.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #include "SkScalerContext.h"
     19 #include "SkColorPriv.h"
     20 #include "SkDescriptor.h"
     21 #include "SkDraw.h"
     22 #include "SkFontHost.h"
     23 #include "SkMaskFilter.h"
     24 #include "SkPathEffect.h"
     25 #include "SkRasterizer.h"
     26 #include "SkRegion.h"
     27 #include "SkStroke.h"
     28 #include "SkThread.h"
     29 
     30 #define ComputeBWRowBytes(width)        (((unsigned)(width) + 7) >> 3)
     31 
     32 static const uint8_t* gBlackGammaTable;
     33 static const uint8_t* gWhiteGammaTable;
     34 
     35 void SkGlyph::toMask(SkMask* mask) const {
     36     SkASSERT(mask);
     37 
     38     mask->fImage = (uint8_t*)fImage;
     39     mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
     40     mask->fRowBytes = this->rowBytes();
     41     mask->fFormat = static_cast<SkMask::Format>(fMaskFormat);
     42 }
     43 
     44 size_t SkGlyph::computeImageSize() const {
     45     const size_t size = this->rowBytes() * fHeight;
     46 
     47     switch (fMaskFormat) {
     48         case SkMask::kHorizontalLCD_Format:
     49             return SkAlign4(size) + sizeof(uint32_t) * ((fWidth + 2) * fHeight);
     50         case SkMask::kVerticalLCD_Format:
     51             return SkAlign4(size) + sizeof(uint32_t) * (fWidth * (fHeight + 2));
     52         case SkMask::k3D_Format:
     53             return 3 * size;
     54         default:
     55             return size;
     56     }
     57 }
     58 
     59 void SkGlyph::zeroMetrics() {
     60     fAdvanceX = 0;
     61     fAdvanceY = 0;
     62     fWidth    = 0;
     63     fHeight   = 0;
     64     fTop      = 0;
     65     fLeft     = 0;
     66     fRsbDelta = 0;
     67     fLsbDelta = 0;
     68 }
     69 
     70 void SkGlyph::expandA8ToLCD() const {
     71     SkASSERT(fMaskFormat == SkMask::kHorizontalLCD_Format ||
     72              fMaskFormat == SkMask::kVerticalLCD_Format);
     73 
     74 #if defined(SK_SUPPORT_LCDTEXT)
     75     uint8_t* input = reinterpret_cast<uint8_t*>(fImage);
     76     uint32_t* output = reinterpret_cast<uint32_t*>(input + SkAlign4(rowBytes() * fHeight));
     77 
     78     if (fMaskFormat == SkMask::kHorizontalLCD_Format) {
     79         for (unsigned y = 0; y < fHeight; ++y) {
     80             const uint8_t* inputRow = input;
     81             *output++ = 0;  // make the extra column on the left clear
     82             for (unsigned x = 0; x < fWidth; ++x) {
     83                 const uint8_t alpha = *inputRow++;
     84                 *output++ = SkPackARGB32(alpha, alpha, alpha, alpha);
     85             }
     86             *output++ = 0;
     87 
     88             input += rowBytes();
     89         }
     90     } else {
     91         const unsigned outputRowBytes = sizeof(uint32_t) * fWidth;
     92         memset(output, 0, outputRowBytes);
     93         output += fWidth;
     94 
     95         for (unsigned y = 0; y < fHeight; ++y) {
     96             const uint8_t* inputRow = input;
     97             for (unsigned x = 0; x < fWidth; ++x) {
     98                 const uint8_t alpha = *inputRow++;
     99                 *output++ = SkPackARGB32(alpha, alpha, alpha, alpha);
    100             }
    101 
    102             input += rowBytes();
    103         }
    104 
    105         memset(output, 0, outputRowBytes);
    106         output += fWidth;
    107     }
    108 #else
    109 #endif
    110 }
    111 
    112 ///////////////////////////////////////////////////////////////////////////////
    113 
    114 #ifdef SK_DEBUG
    115     #define DUMP_RECx
    116 #endif
    117 
    118 static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) {
    119     SkFlattenable*  obj = NULL;
    120     uint32_t        len;
    121     const void*     data = desc->findEntry(tag, &len);
    122 
    123     if (data) {
    124         SkFlattenableReadBuffer   buffer(data, len);
    125         obj = buffer.readFlattenable();
    126         SkASSERT(buffer.offset() == buffer.size());
    127     }
    128     return obj;
    129 }
    130 
    131 SkScalerContext::SkScalerContext(const SkDescriptor* desc)
    132     : fPathEffect(NULL), fMaskFilter(NULL)
    133 {
    134     static bool gHaveGammaTables;
    135     if (!gHaveGammaTables) {
    136         const uint8_t* tables[2];
    137         SkFontHost::GetGammaTables(tables);
    138         gBlackGammaTable = tables[0];
    139         gWhiteGammaTable = tables[1];
    140         gHaveGammaTables = true;
    141     }
    142 
    143     fBaseGlyphCount = 0;
    144     fNextContext = NULL;
    145 
    146     const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL);
    147     SkASSERT(rec);
    148 
    149     fRec = *rec;
    150 
    151 #ifdef DUMP_REC
    152     desc->assertChecksum();
    153     SkDebugf("SkScalarContext checksum %x count %d length %d\n",
    154              desc->getChecksum(), desc->getCount(), desc->getLength());
    155     SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
    156         rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
    157         rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
    158     SkDebugf("  frame %g miter %g hints %d framefill %d format %d join %d\n",
    159         rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
    160         rec->fMaskFormat, rec->fStrokeJoin);
    161     SkDebugf("  pathEffect %x maskFilter %x\n",
    162              desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
    163         desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
    164 #endif
    165 
    166     fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag);
    167     fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag);
    168     fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag);
    169 }
    170 
    171 SkScalerContext::~SkScalerContext() {
    172     SkDELETE(fNextContext);
    173 
    174     SkSafeUnref(fPathEffect);
    175     SkSafeUnref(fMaskFilter);
    176     SkSafeUnref(fRasterizer);
    177 }
    178 
    179 static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) {
    180     // fonthost will determine the next possible font to search, based
    181     // on the current font in fRec. It will return NULL if ctx is our
    182     // last font that can be searched (i.e. ultimate fallback font)
    183     uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID);
    184     if (0 == newFontID) {
    185         return NULL;
    186     }
    187 
    188     SkAutoDescriptor    ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
    189     SkDescriptor*       desc = ad.getDesc();
    190 
    191     desc->init();
    192     SkScalerContext::Rec* newRec =
    193     (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
    194                                           sizeof(rec), &rec);
    195     newRec->fFontID = newFontID;
    196     desc->computeChecksum();
    197 
    198     return SkFontHost::CreateScalerContext(desc);
    199 }
    200 
    201 /*  Return the next context, creating it if its not already created, but return
    202     NULL if the fonthost says there are no more fonts to fallback to.
    203  */
    204 SkScalerContext* SkScalerContext::getNextContext() {
    205     SkScalerContext* next = fNextContext;
    206     // if next is null, then either it isn't cached yet, or we're at the
    207     // end of our possible chain
    208     if (NULL == next) {
    209         next = allocNextContext(fRec);
    210         if (NULL == next) {
    211             return NULL;
    212         }
    213         // next's base is our base + our local count
    214         next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount());
    215         // cache the answer
    216         fNextContext = next;
    217     }
    218     return next;
    219 }
    220 
    221 SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
    222     unsigned glyphID = glyph.getGlyphID();
    223     SkScalerContext* ctx = this;
    224     for (;;) {
    225         unsigned count = ctx->getGlyphCount();
    226         if (glyphID < count) {
    227             break;
    228         }
    229         glyphID -= count;
    230         ctx = ctx->getNextContext();
    231         if (NULL == ctx) {
    232             SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID());
    233             // just return the original context (this)
    234             return this;
    235         }
    236     }
    237     return ctx;
    238 }
    239 
    240 /*  This loops through all available fallback contexts (if needed) until it
    241     finds some context that can handle the unichar. If all fail, returns 0
    242  */
    243 uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
    244     SkScalerContext* ctx = this;
    245     unsigned glyphID;
    246     for (;;) {
    247         glyphID = ctx->generateCharToGlyph(uni);
    248         if (glyphID) {
    249             break;  // found it
    250         }
    251         ctx = ctx->getNextContext();
    252         if (NULL == ctx) {
    253             return 0;   // no more contexts, return missing glyph
    254         }
    255     }
    256     // add the ctx's base, making glyphID unique for chain of contexts
    257     glyphID += ctx->fBaseGlyphCount;
    258     // check for overflow of 16bits, since our glyphID cannot exceed that
    259     if (glyphID > 0xFFFF) {
    260         glyphID = 0;
    261     }
    262     return SkToU16(glyphID);
    263 }
    264 
    265 SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) {
    266     SkScalerContext* ctx = this;
    267     unsigned rangeEnd = 0;
    268     do {
    269         unsigned rangeStart = rangeEnd;
    270 
    271         rangeEnd += ctx->getGlyphCount();
    272         if (rangeStart <= glyphID && glyphID < rangeEnd) {
    273             return ctx->generateGlyphToChar(glyphID - rangeStart);
    274         }
    275         ctx = ctx->getNextContext();
    276     } while (NULL != ctx);
    277     return 0;
    278 }
    279 
    280 void SkScalerContext::getAdvance(SkGlyph* glyph) {
    281     // mark us as just having a valid advance
    282     glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
    283     // we mark the format before making the call, in case the impl
    284     // internally ends up calling its generateMetrics, which is OK
    285     // albeit slower than strictly necessary
    286     this->getGlyphContext(*glyph)->generateAdvance(glyph);
    287 }
    288 
    289 void SkScalerContext::getMetrics(SkGlyph* glyph) {
    290     this->getGlyphContext(*glyph)->generateMetrics(glyph);
    291 
    292     // for now we have separate cache entries for devkerning on and off
    293     // in the future we might share caches, but make our measure/draw
    294     // code make the distinction. Thus we zap the values if the caller
    295     // has not asked for them.
    296     if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
    297         // no devkern, so zap the fields
    298         glyph->fLsbDelta = glyph->fRsbDelta = 0;
    299     }
    300 
    301     // if either dimension is empty, zap the image bounds of the glyph
    302     if (0 == glyph->fWidth || 0 == glyph->fHeight) {
    303         glyph->fWidth   = 0;
    304         glyph->fHeight  = 0;
    305         glyph->fTop     = 0;
    306         glyph->fLeft    = 0;
    307         glyph->fMaskFormat = 0;
    308         return;
    309     }
    310 
    311     if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
    312         SkPath      devPath, fillPath;
    313         SkMatrix    fillToDevMatrix;
    314 
    315         this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
    316 
    317         if (fRasterizer) {
    318             SkMask  mask;
    319 
    320             if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
    321                                        fMaskFilter, &mask,
    322                                        SkMask::kJustComputeBounds_CreateMode)) {
    323                 glyph->fLeft    = mask.fBounds.fLeft;
    324                 glyph->fTop     = mask.fBounds.fTop;
    325                 glyph->fWidth   = SkToU16(mask.fBounds.width());
    326                 glyph->fHeight  = SkToU16(mask.fBounds.height());
    327             } else {
    328                 goto SK_ERROR;
    329             }
    330         } else {
    331             // just use devPath
    332             SkIRect ir;
    333             devPath.getBounds().roundOut(&ir);
    334 
    335             if (ir.isEmpty() || !ir.is16Bit()) {
    336                 goto SK_ERROR;
    337             }
    338             glyph->fLeft    = ir.fLeft;
    339             glyph->fTop     = ir.fTop;
    340             glyph->fWidth   = SkToU16(ir.width());
    341             glyph->fHeight  = SkToU16(ir.height());
    342         }
    343     }
    344 
    345 	if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
    346 		glyph->fMaskFormat = fRec.fMaskFormat;
    347 	}
    348 
    349     if (fMaskFilter) {
    350         SkMask      src, dst;
    351         SkMatrix    matrix;
    352 
    353         glyph->toMask(&src);
    354         fRec.getMatrixFrom2x2(&matrix);
    355 
    356         src.fImage = NULL;  // only want the bounds from the filter
    357         if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
    358             SkASSERT(dst.fImage == NULL);
    359             glyph->fLeft    = dst.fBounds.fLeft;
    360             glyph->fTop     = dst.fBounds.fTop;
    361             glyph->fWidth   = SkToU16(dst.fBounds.width());
    362             glyph->fHeight  = SkToU16(dst.fBounds.height());
    363             glyph->fMaskFormat = dst.fFormat;
    364         }
    365     }
    366     return;
    367 
    368 SK_ERROR:
    369     // draw nothing 'cause we failed
    370     glyph->fLeft    = 0;
    371     glyph->fTop     = 0;
    372     glyph->fWidth   = 0;
    373     glyph->fHeight  = 0;
    374     // put a valid value here, in case it was earlier set to
    375     // MASK_FORMAT_JUST_ADVANCE
    376     glyph->fMaskFormat = fRec.fMaskFormat;
    377 }
    378 
    379 void SkScalerContext::getImage(const SkGlyph& origGlyph) {
    380     const SkGlyph*  glyph = &origGlyph;
    381     SkGlyph         tmpGlyph;
    382 
    383     if (fMaskFilter) {   // restore the prefilter bounds
    384         tmpGlyph.init(origGlyph.fID);
    385 
    386         // need the original bounds, sans our maskfilter
    387         SkMaskFilter* mf = fMaskFilter;
    388         fMaskFilter = NULL;             // temp disable
    389         this->getMetrics(&tmpGlyph);
    390         fMaskFilter = mf;               // restore
    391 
    392         tmpGlyph.fImage = origGlyph.fImage;
    393 
    394         // we need the prefilter bounds to be <= filter bounds
    395         SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
    396         SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
    397         glyph = &tmpGlyph;
    398     }
    399 
    400     if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
    401         SkPath      devPath, fillPath;
    402         SkMatrix    fillToDevMatrix;
    403 
    404         this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
    405 
    406         const bool lcdMode = fRec.fMaskFormat == SkMask::kHorizontalLCD_Format ||
    407                              fRec.fMaskFormat == SkMask::kVerticalLCD_Format;
    408 
    409         if (fRasterizer) {
    410             SkMask  mask;
    411 
    412             glyph->toMask(&mask);
    413             mask.fFormat = SkMask::kA8_Format;
    414             sk_bzero(glyph->fImage, mask.computeImageSize());
    415 
    416             if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
    417                                         fMaskFilter, &mask,
    418                                         SkMask::kJustRenderImage_CreateMode)) {
    419                 return;
    420             }
    421         } else {
    422             SkBitmap    bm;
    423             SkBitmap::Config config;
    424             SkMatrix    matrix;
    425             SkRegion    clip;
    426             SkPaint     paint;
    427             SkDraw      draw;
    428 
    429             if (SkMask::kA8_Format == fRec.fMaskFormat || lcdMode) {
    430                 config = SkBitmap::kA8_Config;
    431                 paint.setAntiAlias(true);
    432             } else {
    433                 SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat);
    434                 config = SkBitmap::kA1_Config;
    435                 paint.setAntiAlias(false);
    436             }
    437 
    438             clip.setRect(0, 0, glyph->fWidth, glyph->fHeight);
    439             matrix.setTranslate(-SkIntToScalar(glyph->fLeft),
    440                                 -SkIntToScalar(glyph->fTop));
    441             bm.setConfig(config, glyph->fWidth, glyph->fHeight,
    442                          glyph->rowBytes());
    443             bm.setPixels(glyph->fImage);
    444             sk_bzero(glyph->fImage, bm.height() * bm.rowBytes());
    445 
    446             draw.fClip  = &clip;
    447             draw.fMatrix = &matrix;
    448             draw.fBitmap = &bm;
    449             draw.fBounder = NULL;
    450             draw.drawPath(devPath, paint);
    451         }
    452 
    453         if (lcdMode) {
    454             glyph->expandA8ToLCD();
    455         }
    456     } else {
    457         this->getGlyphContext(*glyph)->generateImage(*glyph);
    458     }
    459 
    460     if (fMaskFilter) {
    461         SkMask      srcM, dstM;
    462         SkMatrix    matrix;
    463 
    464         // the src glyph image shouldn't be 3D
    465         SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
    466         glyph->toMask(&srcM);
    467         fRec.getMatrixFrom2x2(&matrix);
    468 
    469         if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
    470             int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
    471             int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
    472             int dstRB = origGlyph.rowBytes();
    473             int srcRB = dstM.fRowBytes;
    474 
    475             const uint8_t* src = (const uint8_t*)dstM.fImage;
    476             uint8_t* dst = (uint8_t*)origGlyph.fImage;
    477 
    478             if (SkMask::k3D_Format == dstM.fFormat) {
    479                 // we have to copy 3 times as much
    480                 height *= 3;
    481             }
    482 
    483             // clean out our glyph, since it may be larger than dstM
    484             //sk_bzero(dst, height * dstRB);
    485 
    486             while (--height >= 0) {
    487                 memcpy(dst, src, width);
    488                 src += srcRB;
    489                 dst += dstRB;
    490             }
    491             SkMask::FreeImage(dstM.fImage);
    492         }
    493     }
    494 
    495     // check to see if we should filter the alpha channel
    496 
    497     if (NULL == fMaskFilter &&
    498         fRec.fMaskFormat != SkMask::kBW_Format &&
    499         fRec.fMaskFormat != SkMask::kLCD16_Format &&
    500         (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0)
    501     {
    502         const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable;
    503         if (NULL != table) {
    504             uint8_t* dst = (uint8_t*)origGlyph.fImage;
    505             unsigned rowBytes = origGlyph.rowBytes();
    506 
    507             for (int y = origGlyph.fHeight - 1; y >= 0; --y) {
    508                 for (int x = origGlyph.fWidth - 1; x >= 0; --x) {
    509                     dst[x] = table[dst[x]];
    510                 }
    511                 dst += rowBytes;
    512             }
    513         }
    514     }
    515 }
    516 
    517 void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) {
    518     this->internalGetPath(glyph, NULL, path, NULL);
    519 }
    520 
    521 void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx,
    522                                      SkPaint::FontMetrics* my) {
    523     this->generateFontMetrics(mx, my);
    524 }
    525 
    526 SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) {
    527     return 0;
    528 }
    529 
    530 ///////////////////////////////////////////////////////////////////////////////
    531 
    532 void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
    533                                   SkPath* devPath, SkMatrix* fillToDevMatrix) {
    534     SkPath  path;
    535 
    536     this->getGlyphContext(glyph)->generatePath(glyph, &path);
    537 
    538     if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
    539         // need the path in user-space, with only the point-size applied
    540         // so that our stroking and effects will operate the same way they
    541         // would if the user had extracted the path themself, and then
    542         // called drawPath
    543         SkPath      localPath;
    544         SkMatrix    matrix, inverse;
    545 
    546         fRec.getMatrixFrom2x2(&matrix);
    547         matrix.invert(&inverse);
    548         path.transform(inverse, &localPath);
    549         // now localPath is only affected by the paint settings, and not the canvas matrix
    550 
    551         SkScalar width = fRec.fFrameWidth;
    552 
    553         if (fPathEffect) {
    554             SkPath effectPath;
    555 
    556             if (fPathEffect->filterPath(&effectPath, localPath, &width)) {
    557                 localPath.swap(effectPath);
    558             }
    559         }
    560 
    561         if (width > 0) {
    562             SkStroke    stroker;
    563             SkPath      outline;
    564 
    565             stroker.setWidth(width);
    566             stroker.setMiterLimit(fRec.fMiterLimit);
    567             stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin);
    568             stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag));
    569             stroker.strokePath(localPath, &outline);
    570             localPath.swap(outline);
    571         }
    572 
    573         // now return stuff to the caller
    574         if (fillToDevMatrix) {
    575             *fillToDevMatrix = matrix;
    576         }
    577         if (devPath) {
    578             localPath.transform(matrix, devPath);
    579         }
    580         if (fillPath) {
    581             fillPath->swap(localPath);
    582         }
    583     } else {   // nothing tricky to do
    584         if (fillToDevMatrix) {
    585             fillToDevMatrix->reset();
    586         }
    587         if (devPath) {
    588             if (fillPath == NULL) {
    589                 devPath->swap(path);
    590             } else {
    591                 *devPath = path;
    592             }
    593         }
    594 
    595         if (fillPath) {
    596             fillPath->swap(path);
    597         }
    598     }
    599 
    600     if (devPath) {
    601         devPath->updateBoundsCache();
    602     }
    603     if (fillPath) {
    604         fillPath->updateBoundsCache();
    605     }
    606 }
    607 
    608 
    609 void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const {
    610     dst->reset();
    611     dst->setScaleX(fPost2x2[0][0]);
    612     dst->setSkewX( fPost2x2[0][1]);
    613     dst->setSkewY( fPost2x2[1][0]);
    614     dst->setScaleY(fPost2x2[1][1]);
    615 }
    616 
    617 void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const {
    618     m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize);
    619     if (fPreSkewX) {
    620         m->postSkew(fPreSkewX, 0);
    621     }
    622 }
    623 
    624 void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const {
    625     this->getLocalMatrix(m);
    626 
    627     //  now concat the device matrix
    628     SkMatrix    deviceMatrix;
    629     this->getMatrixFrom2x2(&deviceMatrix);
    630     m->postConcat(deviceMatrix);
    631 }
    632 
    633 ///////////////////////////////////////////////////////////////////////////////
    634 
    635 #include "SkFontHost.h"
    636 
    637 class SkScalerContext_Empty : public SkScalerContext {
    638 public:
    639     SkScalerContext_Empty(const SkDescriptor* desc) : SkScalerContext(desc) {}
    640 
    641 protected:
    642     virtual unsigned generateGlyphCount() {
    643         return 0;
    644     }
    645     virtual uint16_t generateCharToGlyph(SkUnichar uni) {
    646         return 0;
    647     }
    648     virtual void generateAdvance(SkGlyph* glyph) {
    649         glyph->zeroMetrics();
    650     }
    651     virtual void generateMetrics(SkGlyph* glyph) {
    652         glyph->zeroMetrics();
    653     }
    654     virtual void generateImage(const SkGlyph& glyph) {}
    655     virtual void generatePath(const SkGlyph& glyph, SkPath* path) {}
    656     virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
    657                                      SkPaint::FontMetrics* my) {
    658         if (mx) {
    659             sk_bzero(mx, sizeof(*mx));
    660         }
    661         if (my) {
    662             sk_bzero(my, sizeof(*my));
    663         }
    664     }
    665 };
    666 
    667 extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
    668 
    669 SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc) {
    670 	SkScalerContext* c = NULL;  //SkCreateColorScalerContext(desc);
    671 	if (NULL == c) {
    672 		c = SkFontHost::CreateScalerContext(desc);
    673 	}
    674     if (NULL == c) {
    675         c = SkNEW_ARGS(SkScalerContext_Empty, (desc));
    676     }
    677     return c;
    678 }
    679 
    680