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 #ifdef SK_DEBUG
     31 //    #define TRACK_MISSING_CHARS
     32 #endif
     33 
     34 #define ComputeBWRowBytes(width)        (((unsigned)(width) + 7) >> 3)
     35 
     36 static const uint8_t* gBlackGammaTable;
     37 static const uint8_t* gWhiteGammaTable;
     38 
     39 void SkGlyph::toMask(SkMask* mask) const {
     40     SkASSERT(mask);
     41 
     42     mask->fImage = (uint8_t*)fImage;
     43     mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
     44     mask->fRowBytes = this->rowBytes();
     45     mask->fFormat = static_cast<SkMask::Format>(fMaskFormat);
     46 }
     47 
     48 size_t SkGlyph::computeImageSize() const {
     49     const size_t size = this->rowBytes() * fHeight;
     50 
     51     switch (fMaskFormat) {
     52     case SkMask::kHorizontalLCD_Format:
     53         return SkAlign4(size) + sizeof(uint32_t) * ((fWidth + 2) * fHeight);
     54     case SkMask::kVerticalLCD_Format:
     55         return SkAlign4(size) + sizeof(uint32_t) * (fWidth * (fHeight + 2));
     56     case SkMask::k3D_Format:
     57         return 3 * size;
     58     default:
     59         return size;
     60     }
     61 }
     62 
     63 void SkGlyph::zeroMetrics() {
     64     fAdvanceX = 0;
     65     fAdvanceY = 0;
     66     fWidth    = 0;
     67     fHeight   = 0;
     68     fTop      = 0;
     69     fLeft     = 0;
     70     fRsbDelta = 0;
     71     fLsbDelta = 0;
     72 }
     73 
     74 void SkGlyph::expandA8ToLCD() const {
     75     SkASSERT(fMaskFormat == SkMask::kHorizontalLCD_Format ||
     76              fMaskFormat == SkMask::kVerticalLCD_Format);
     77 
     78 #if defined(SK_SUPPORT_LCDTEXT)
     79     uint8_t* input = reinterpret_cast<uint8_t*>(fImage);
     80     uint32_t* output = reinterpret_cast<uint32_t*>(input + SkAlign4(rowBytes() * fHeight));
     81 
     82     if (fMaskFormat == SkMask::kHorizontalLCD_Format) {
     83         for (unsigned y = 0; y < fHeight; ++y) {
     84             const uint8_t* inputRow = input;
     85             *output++ = 0;  // make the extra column on the left clear
     86             for (unsigned x = 0; x < fWidth; ++x) {
     87                 const uint8_t alpha = *inputRow++;
     88                 *output++ = SkPackARGB32(alpha, alpha, alpha, alpha);
     89             }
     90             *output++ = 0;
     91 
     92             input += rowBytes();
     93         }
     94     } else {
     95         const unsigned outputRowBytes = sizeof(uint32_t) * fWidth;
     96         memset(output, 0, outputRowBytes);
     97         output += fWidth;
     98 
     99         for (unsigned y = 0; y < fHeight; ++y) {
    100             const uint8_t* inputRow = input;
    101             for (unsigned x = 0; x < fWidth; ++x) {
    102                 const uint8_t alpha = *inputRow++;
    103                 *output++ = SkPackARGB32(alpha, alpha, alpha, alpha);
    104             }
    105 
    106             input += rowBytes();
    107         }
    108 
    109         memset(output, 0, outputRowBytes);
    110         output += fWidth;
    111     }
    112 #else
    113 #endif
    114 }
    115 
    116 ///////////////////////////////////////////////////////////////////////////////
    117 
    118 #ifdef SK_DEBUG
    119     #define DUMP_RECx
    120 #endif
    121 
    122 static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) {
    123     SkFlattenable*  obj = NULL;
    124     uint32_t        len;
    125     const void*     data = desc->findEntry(tag, &len);
    126 
    127     if (data) {
    128         SkFlattenableReadBuffer   buffer(data, len);
    129         obj = buffer.readFlattenable();
    130         SkASSERT(buffer.offset() == buffer.size());
    131     }
    132     return obj;
    133 }
    134 
    135 SkScalerContext::SkScalerContext(const SkDescriptor* desc)
    136     : fPathEffect(NULL), fMaskFilter(NULL)
    137 {
    138     static bool gHaveGammaTables;
    139     if (!gHaveGammaTables) {
    140         const uint8_t* tables[2];
    141         SkFontHost::GetGammaTables(tables);
    142         gBlackGammaTable = tables[0];
    143         gWhiteGammaTable = tables[1];
    144         gHaveGammaTables = true;
    145     }
    146 
    147     fBaseGlyphCount = 0;
    148     fNextContext = NULL;
    149 
    150     const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL);
    151     SkASSERT(rec);
    152 
    153     fRec = *rec;
    154 
    155 #ifdef DUMP_REC
    156     desc->assertChecksum();
    157     SkDebugf("SkScalarContext checksum %x count %d length %d\n", desc->getChecksum(), desc->getCount(), desc->getLength());
    158     SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
    159         rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
    160         rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
    161     SkDebugf("  frame %g miter %g hints %d framefill %d format %d join %d\n",
    162         rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
    163         rec->fMaskFormat, rec->fStrokeJoin);
    164     SkDebugf("  pathEffect %x maskFilter %x\n", desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
    165         desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
    166 #endif
    167 
    168     fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag);
    169     fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag);
    170     fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag);
    171 }
    172 
    173 SkScalerContext::~SkScalerContext() {
    174     SkDELETE(fNextContext);
    175 
    176     fPathEffect->safeUnref();
    177     fMaskFilter->safeUnref();
    178     fRasterizer->safeUnref();
    179 }
    180 
    181 static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) {
    182     // fonthost will determine the next possible font to search, based
    183     // on the current font in fRec. It will return NULL if ctx is our
    184     // last font that can be searched (i.e. ultimate fallback font)
    185     uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID);
    186     if (0 == newFontID) {
    187         return NULL;
    188     }
    189 
    190     SkAutoDescriptor    ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
    191     SkDescriptor*       desc = ad.getDesc();
    192 
    193     desc->init();
    194     SkScalerContext::Rec* newRec =
    195     (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
    196                                           sizeof(rec), &rec);
    197     newRec->fFontID = newFontID;
    198     desc->computeChecksum();
    199 
    200     return SkFontHost::CreateScalerContext(desc);
    201 }
    202 
    203 /*  Return the next context, creating it if its not already created, but return
    204     NULL if the fonthost says there are no more fonts to fallback to.
    205  */
    206 SkScalerContext* SkScalerContext::getNextContext() {
    207     SkScalerContext* next = fNextContext;
    208     // if next is null, then either it isn't cached yet, or we're at the
    209     // end of our possible chain
    210     if (NULL == next) {
    211         next = allocNextContext(fRec);
    212         if (NULL == next) {
    213             return NULL;
    214         }
    215         // next's base is our base + our local count
    216         next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount());
    217         // cache the answer
    218         fNextContext = next;
    219     }
    220     return next;
    221 }
    222 
    223 SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
    224     unsigned glyphID = glyph.getGlyphID();
    225     SkScalerContext* ctx = this;
    226     for (;;) {
    227         unsigned count = ctx->getGlyphCount();
    228         if (glyphID < count) {
    229             break;
    230         }
    231         glyphID -= count;
    232         ctx = ctx->getNextContext();
    233         if (NULL == ctx) {
    234             SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID());
    235             // just return the original context (this)
    236             return this;
    237         }
    238     }
    239     return ctx;
    240 }
    241 
    242 /*  This loops through all available fallback contexts (if needed) until it
    243     finds some context that can handle the unichar. If all fail, returns 0
    244  */
    245 uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
    246     SkScalerContext* ctx = this;
    247     unsigned glyphID;
    248     for (;;) {
    249         glyphID = ctx->generateCharToGlyph(uni);
    250         if (glyphID) {
    251             break;  // found it
    252         }
    253         ctx = ctx->getNextContext();
    254         if (NULL == ctx) {
    255             return 0;   // no more contexts, return missing glyph
    256         }
    257     }
    258     // add the ctx's base, making glyphID unique for chain of contexts
    259     glyphID += ctx->fBaseGlyphCount;
    260     // check for overflow of 16bits, since our glyphID cannot exceed that
    261     if (glyphID > 0xFFFF) {
    262         glyphID = 0;
    263     }
    264     return SkToU16(glyphID);
    265 }
    266 
    267 SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) {
    268     SkScalerContext* ctx = this;
    269     unsigned rangeEnd = 0;
    270     do {
    271         unsigned rangeStart = rangeEnd;
    272 
    273         rangeEnd += ctx->getGlyphCount();
    274         if (rangeStart <= glyphID && glyphID < rangeEnd) {
    275             return ctx->generateGlyphToChar(glyphID - rangeStart);
    276         }
    277         ctx = ctx->getNextContext();
    278     } while (NULL != ctx);
    279     return 0;
    280 }
    281 
    282 void SkScalerContext::getAdvance(SkGlyph* glyph) {
    283     // mark us as just having a valid advance
    284     glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
    285     // we mark the format before making the call, in case the impl
    286     // internally ends up calling its generateMetrics, which is OK
    287     // albeit slower than strictly necessary
    288     this->getGlyphContext(*glyph)->generateAdvance(glyph);
    289 }
    290 
    291 void SkScalerContext::getMetrics(SkGlyph* glyph) {
    292     this->getGlyphContext(*glyph)->generateMetrics(glyph);
    293 
    294     // for now we have separate cache entries for devkerning on and off
    295     // in the future we might share caches, but make our measure/draw
    296     // code make the distinction. Thus we zap the values if the caller
    297     // has not asked for them.
    298     if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
    299         // no devkern, so zap the fields
    300         glyph->fLsbDelta = glyph->fRsbDelta = 0;
    301     }
    302 
    303     // if either dimension is empty, zap the image bounds of the glyph
    304     if (0 == glyph->fWidth || 0 == glyph->fHeight) {
    305         glyph->fWidth   = 0;
    306         glyph->fHeight  = 0;
    307         glyph->fTop     = 0;
    308         glyph->fLeft    = 0;
    309         glyph->fMaskFormat = 0;
    310         return;
    311     }
    312 
    313     if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
    314         SkPath      devPath, fillPath;
    315         SkMatrix    fillToDevMatrix;
    316 
    317         this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
    318 
    319         if (fRasterizer) {
    320             SkMask  mask;
    321 
    322             if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
    323                                        fMaskFilter, &mask,
    324                                        SkMask::kJustComputeBounds_CreateMode)) {
    325                 glyph->fLeft    = mask.fBounds.fLeft;
    326                 glyph->fTop     = mask.fBounds.fTop;
    327                 glyph->fWidth   = SkToU16(mask.fBounds.width());
    328                 glyph->fHeight  = SkToU16(mask.fBounds.height());
    329             } else {
    330                 goto SK_ERROR;
    331             }
    332         } else {
    333             // just use devPath
    334             SkIRect ir;
    335             devPath.getBounds().roundOut(&ir);
    336 
    337             if (ir.isEmpty() || !ir.is16Bit()) {
    338                 goto SK_ERROR;
    339             }
    340             glyph->fLeft    = ir.fLeft;
    341             glyph->fTop     = ir.fTop;
    342             glyph->fWidth   = SkToU16(ir.width());
    343             glyph->fHeight  = SkToU16(ir.height());
    344         }
    345     }
    346 
    347     glyph->fMaskFormat = fRec.fMaskFormat;
    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.fID = 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     } else {
    456         this->getGlyphContext(*glyph)->generateImage(*glyph);
    457     }
    458 
    459     if (fMaskFilter) {
    460         SkMask      srcM, dstM;
    461         SkMatrix    matrix;
    462 
    463         // the src glyph image shouldn't be 3D
    464         SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
    465         glyph->toMask(&srcM);
    466         fRec.getMatrixFrom2x2(&matrix);
    467 
    468         if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
    469             int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
    470             int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
    471             int dstRB = origGlyph.rowBytes();
    472             int srcRB = dstM.fRowBytes;
    473 
    474             const uint8_t* src = (const uint8_t*)dstM.fImage;
    475             uint8_t* dst = (uint8_t*)origGlyph.fImage;
    476 
    477             if (SkMask::k3D_Format == dstM.fFormat) {
    478                 // we have to copy 3 times as much
    479                 height *= 3;
    480             }
    481 
    482             // clean out our glyph, since it may be larger than dstM
    483             //sk_bzero(dst, height * dstRB);
    484 
    485             while (--height >= 0) {
    486                 memcpy(dst, src, width);
    487                 src += srcRB;
    488                 dst += dstRB;
    489             }
    490             SkMask::FreeImage(dstM.fImage);
    491         }
    492     }
    493 
    494     // check to see if we should filter the alpha channel
    495 
    496     if (NULL == fMaskFilter &&
    497         fRec.fMaskFormat != SkMask::kBW_Format &&
    498         (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0)
    499     {
    500         const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable;
    501         if (NULL != table)
    502         {
    503             uint8_t* dst = (uint8_t*)origGlyph.fImage;
    504             unsigned rowBytes = origGlyph.rowBytes();
    505 
    506             for (int y = origGlyph.fHeight - 1; y >= 0; --y)
    507             {
    508                 for (int x = origGlyph.fWidth - 1; x >= 0; --x)
    509                     dst[x] = table[dst[x]];
    510                 dst += rowBytes;
    511             }
    512         }
    513     }
    514 }
    515 
    516 void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path)
    517 {
    518     this->internalGetPath(glyph, NULL, path, NULL);
    519 }
    520 
    521 void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my)
    522 {
    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, SkPath* devPath, SkMatrix* fillToDevMatrix)
    533 {
    534     SkPath  path;
    535 
    536     this->getGlyphContext(glyph)->generatePath(glyph, &path);
    537 
    538     if (fRec.fFrameWidth > 0 || fPathEffect != NULL)
    539     {
    540         // need the path in user-space, with only the point-size applied
    541         // so that our stroking and effects will operate the same way they
    542         // would if the user had extracted the path themself, and then
    543         // called drawPath
    544         SkPath      localPath;
    545         SkMatrix    matrix, inverse;
    546 
    547         fRec.getMatrixFrom2x2(&matrix);
    548         matrix.invert(&inverse);
    549         path.transform(inverse, &localPath);
    550         // now localPath is only affected by the paint settings, and not the canvas matrix
    551 
    552         SkScalar width = fRec.fFrameWidth;
    553 
    554         if (fPathEffect)
    555         {
    556             SkPath effectPath;
    557 
    558             if (fPathEffect->filterPath(&effectPath, localPath, &width))
    559                 localPath.swap(effectPath);
    560         }
    561 
    562         if (width > 0)
    563         {
    564             SkStroke    stroker;
    565             SkPath      outline;
    566 
    567             stroker.setWidth(width);
    568             stroker.setMiterLimit(fRec.fMiterLimit);
    569             stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin);
    570             stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag));
    571             stroker.strokePath(localPath, &outline);
    572             localPath.swap(outline);
    573         }
    574 
    575         // now return stuff to the caller
    576         if (fillToDevMatrix)
    577             *fillToDevMatrix = matrix;
    578 
    579         if (devPath)
    580             localPath.transform(matrix, devPath);
    581 
    582         if (fillPath)
    583             fillPath->swap(localPath);
    584     }
    585     else    // nothing tricky to do
    586     {
    587         if (fillToDevMatrix)
    588             fillToDevMatrix->reset();
    589 
    590         if (devPath)
    591         {
    592             if (fillPath == NULL)
    593                 devPath->swap(path);
    594             else
    595                 *devPath = path;
    596         }
    597 
    598         if (fillPath)
    599             fillPath->swap(path);
    600     }
    601 
    602     if (devPath)
    603         devPath->updateBoundsCache();
    604     if (fillPath)
    605         fillPath->updateBoundsCache();
    606 }
    607 
    608 
    609 void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const
    610 {
    611     dst->reset();
    612     dst->setScaleX(fPost2x2[0][0]);
    613     dst->setSkewX( fPost2x2[0][1]);
    614     dst->setSkewY( fPost2x2[1][0]);
    615     dst->setScaleY(fPost2x2[1][1]);
    616 }
    617 
    618 void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const
    619 {
    620     m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize);
    621     if (fPreSkewX)
    622         m->postSkew(fPreSkewX, 0);
    623 }
    624 
    625 void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const
    626 {
    627     this->getLocalMatrix(m);
    628 
    629     //  now concat the device matrix
    630     {
    631         SkMatrix    deviceMatrix;
    632         this->getMatrixFrom2x2(&deviceMatrix);
    633         m->postConcat(deviceMatrix);
    634     }
    635 }
    636 
    637 ///////////////////////////////////////////////////////////////////////////////
    638 
    639 #include "SkFontHost.h"
    640 
    641 class SkScalerContext_Empty : public SkScalerContext {
    642 public:
    643     SkScalerContext_Empty(const SkDescriptor* desc) : SkScalerContext(desc) {}
    644 
    645 protected:
    646     virtual unsigned generateGlyphCount() const {
    647         return 0;
    648     }
    649     virtual uint16_t generateCharToGlyph(SkUnichar uni) {
    650         return 0;
    651     }
    652     virtual void generateAdvance(SkGlyph* glyph) {
    653         glyph->zeroMetrics();
    654     }
    655     virtual void generateMetrics(SkGlyph* glyph) {
    656         glyph->zeroMetrics();
    657     }
    658     virtual void generateImage(const SkGlyph& glyph) {}
    659     virtual void generatePath(const SkGlyph& glyph, SkPath* path) {}
    660     virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
    661                                      SkPaint::FontMetrics* my) {
    662         if (mx) {
    663             sk_bzero(mx, sizeof(*mx));
    664         }
    665         if (my) {
    666             sk_bzero(my, sizeof(*my));
    667         }
    668     }
    669 };
    670 
    671 SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc)
    672 {
    673     SkScalerContext* c = SkFontHost::CreateScalerContext(desc);
    674     if (NULL == c) {
    675         c = SkNEW_ARGS(SkScalerContext_Empty, (desc));
    676     }
    677     return c;
    678 }
    679 
    680