Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkGlyphCache.h"
      9 #include "SkPaint.h"
     10 #include "SkScalerContext.h"
     11 
     12 #include "SkAutoMalloc.h"
     13 #include "SkAutoPixmapStorage.h"
     14 #include "SkColorData.h"
     15 #include "SkDescriptor.h"
     16 #include "SkDraw.h"
     17 #include "SkGlyph.h"
     18 #include "SkMakeUnique.h"
     19 #include "SkMaskFilter.h"
     20 #include "SkMaskGamma.h"
     21 #include "SkMatrix22.h"
     22 #include "SkPaintPriv.h"
     23 #include "SkPathEffect.h"
     24 #include "SkRasterClip.h"
     25 #include "SkReadBuffer.h"
     26 #include "SkStroke.h"
     27 #include "SkStrokeRec.h"
     28 #include "SkSurfacePriv.h"
     29 #include "SkTextFormatParams.h"
     30 #include "SkWriteBuffer.h"
     31 
     32 void SkGlyph::toMask(SkMask* mask) const {
     33     SkASSERT(mask);
     34 
     35     mask->fImage = (uint8_t*)fImage;
     36     mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
     37     mask->fRowBytes = this->rowBytes();
     38     mask->fFormat = static_cast<SkMask::Format>(fMaskFormat);
     39 }
     40 
     41 size_t SkGlyph::computeImageSize() const {
     42     const size_t size = this->rowBytes() * fHeight;
     43 
     44     switch (fMaskFormat) {
     45         case SkMask::k3D_Format:
     46             return 3 * size;
     47         default:
     48             return size;
     49     }
     50 }
     51 
     52 void SkGlyph::zeroMetrics() {
     53     fAdvanceX = 0;
     54     fAdvanceY = 0;
     55     fWidth    = 0;
     56     fHeight   = 0;
     57     fTop      = 0;
     58     fLeft     = 0;
     59     fRsbDelta = 0;
     60     fLsbDelta = 0;
     61 }
     62 
     63 ///////////////////////////////////////////////////////////////////////////////
     64 
     65 #ifdef SK_DEBUG
     66     #define DUMP_RECx
     67 #endif
     68 
     69 SkScalerContext::SkScalerContext(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
     70                                  const SkDescriptor* desc)
     71     : fRec(*static_cast<const SkScalerContextRec*>(desc->findEntry(kRec_SkDescriptorTag, nullptr)))
     72 
     73     , fTypeface(std::move(typeface))
     74     , fPathEffect(sk_ref_sp(effects.fPathEffect))
     75     , fMaskFilter(sk_ref_sp(effects.fMaskFilter))
     76       // Initialize based on our settings. Subclasses can also force this.
     77     , fGenerateImageFromPath(fRec.fFrameWidth > 0 || fPathEffect != nullptr)
     78 
     79     , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec))
     80     , fPreBlendForFilter(fMaskFilter ? SkScalerContext::GetMaskPreBlend(fRec)
     81                                      : SkMaskGamma::PreBlend())
     82 {
     83 #ifdef DUMP_REC
     84     SkDebugf("SkScalerContext checksum %x count %d length %d\n",
     85              desc->getChecksum(), desc->getCount(), desc->getLength());
     86     SkDebugf("%s", fRec.dump().c_str());
     87     SkDebugf("  pathEffect %x maskFilter %x\n",
     88              desc->findEntry(kPathEffect_SkDescriptorTag, nullptr),
     89         desc->findEntry(kMaskFilter_SkDescriptorTag, nullptr));
     90 #endif
     91 }
     92 
     93 SkScalerContext::~SkScalerContext() {}
     94 
     95 void SkScalerContext::getAdvance(SkGlyph* glyph) {
     96     // mark us as just having a valid advance
     97     glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
     98     // we mark the format before making the call, in case the impl
     99     // internally ends up calling its generateMetrics, which is OK
    100     // albeit slower than strictly necessary
    101     generateAdvance(glyph);
    102 }
    103 
    104 void SkScalerContext::getMetrics(SkGlyph* glyph) {
    105     generateMetrics(glyph);
    106 
    107     // for now we have separate cache entries for devkerning on and off
    108     // in the future we might share caches, but make our measure/draw
    109     // code make the distinction. Thus we zap the values if the caller
    110     // has not asked for them.
    111     if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
    112         // no devkern, so zap the fields
    113         glyph->fLsbDelta = glyph->fRsbDelta = 0;
    114     }
    115 
    116     // if either dimension is empty, zap the image bounds of the glyph
    117     if (0 == glyph->fWidth || 0 == glyph->fHeight) {
    118         glyph->fWidth   = 0;
    119         glyph->fHeight  = 0;
    120         glyph->fTop     = 0;
    121         glyph->fLeft    = 0;
    122         glyph->fMaskFormat = 0;
    123         return;
    124     }
    125 
    126     bool generatingImageFromPath = fGenerateImageFromPath;
    127     if (fGenerateImageFromPath) {
    128         SkPath      devPath, fillPath;
    129         SkMatrix    fillToDevMatrix;
    130 
    131         this->internalGetPath(glyph->getPackedID(), &fillPath, &devPath, &fillToDevMatrix);
    132         if (fillPath.isEmpty()) {
    133             generatingImageFromPath = false;
    134         } else {
    135             // just use devPath
    136             const SkIRect ir = devPath.getBounds().roundOut();
    137 
    138             if (ir.isEmpty() || !ir.is16Bit()) {
    139                 goto SK_ERROR;
    140             }
    141             glyph->fLeft    = ir.fLeft;
    142             glyph->fTop     = ir.fTop;
    143             glyph->fWidth   = SkToU16(ir.width());
    144             glyph->fHeight  = SkToU16(ir.height());
    145 
    146             if (glyph->fWidth > 0) {
    147                 switch (fRec.fMaskFormat) {
    148                 case SkMask::kLCD16_Format:
    149                     glyph->fWidth += 2;
    150                     glyph->fLeft -= 1;
    151                     break;
    152                 default:
    153                     break;
    154                 }
    155             }
    156         }
    157     }
    158 
    159     if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
    160         glyph->fMaskFormat = fRec.fMaskFormat;
    161     }
    162 
    163     // If we are going to create the mask, then we cannot keep the color
    164     if ((generatingImageFromPath || fMaskFilter) && SkMask::kARGB32_Format == glyph->fMaskFormat) {
    165         glyph->fMaskFormat = SkMask::kA8_Format;
    166     }
    167 
    168     if (fMaskFilter) {
    169         SkMask      src, dst;
    170         SkMatrix    matrix;
    171 
    172         glyph->toMask(&src);
    173         fRec.getMatrixFrom2x2(&matrix);
    174 
    175         src.fImage = nullptr;  // only want the bounds from the filter
    176         if (as_MFB(fMaskFilter)->filterMask(&dst, src, matrix, nullptr)) {
    177             if (dst.fBounds.isEmpty() || !dst.fBounds.is16Bit()) {
    178                 goto SK_ERROR;
    179             }
    180             SkASSERT(dst.fImage == nullptr);
    181             glyph->fLeft    = dst.fBounds.fLeft;
    182             glyph->fTop     = dst.fBounds.fTop;
    183             glyph->fWidth   = SkToU16(dst.fBounds.width());
    184             glyph->fHeight  = SkToU16(dst.fBounds.height());
    185             glyph->fMaskFormat = dst.fFormat;
    186         }
    187     }
    188     return;
    189 
    190 SK_ERROR:
    191     // draw nothing 'cause we failed
    192     glyph->fLeft    = 0;
    193     glyph->fTop     = 0;
    194     glyph->fWidth   = 0;
    195     glyph->fHeight  = 0;
    196     // put a valid value here, in case it was earlier set to
    197     // MASK_FORMAT_JUST_ADVANCE
    198     glyph->fMaskFormat = fRec.fMaskFormat;
    199 }
    200 
    201 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
    202 
    203 static void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) {
    204     uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage;
    205     unsigned rowBytes = mask.fRowBytes;
    206 
    207     for (int y = mask.fBounds.height() - 1; y >= 0; --y) {
    208         for (int x = mask.fBounds.width() - 1; x >= 0; --x) {
    209             dst[x] = lut[dst[x]];
    210         }
    211         dst += rowBytes;
    212     }
    213 }
    214 
    215 template<bool APPLY_PREBLEND>
    216 static void pack4xHToLCD16(const SkPixmap& src, const SkMask& dst,
    217                            const SkMaskGamma::PreBlend& maskPreBlend) {
    218 #define SAMPLES_PER_PIXEL 4
    219 #define LCD_PER_PIXEL 3
    220     SkASSERT(kAlpha_8_SkColorType == src.colorType());
    221     SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
    222 
    223     const int sample_width = src.width();
    224     const int height = src.height();
    225 
    226     uint16_t* dstP = (uint16_t*)dst.fImage;
    227     size_t dstRB = dst.fRowBytes;
    228     // An N tap FIR is defined by
    229     // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N]
    230     // or
    231     // out[n] = sum(i, 0, N, coeff[i]*x[n-i])
    232 
    233     // The strategy is to use one FIR (different coefficients) for each of r, g, and b.
    234     // This means using every 4th FIR output value of each FIR and discarding the rest.
    235     // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'.
    236     // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.)
    237 
    238     // These are in some fixed point repesentation.
    239     // Adding up to more than one simulates ink spread.
    240     // For implementation reasons, these should never add up to more than two.
    241 
    242     // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast').
    243     // Calculated using tools/generate_fir_coeff.py
    244     // With this one almost no fringing is ever seen, but it is imperceptibly blurry.
    245     // The lcd smoothed text is almost imperceptibly different from gray,
    246     // but is still sharper on small stems and small rounded corners than gray.
    247     // This also seems to be about as wide as one can get and only have a three pixel kernel.
    248     // TODO: caculate these at runtime so parameters can be adjusted (esp contrast).
    249     static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = {
    250         //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted.
    251         { 0x03, 0x0b, 0x1c, 0x33,  0x40, 0x39, 0x24, 0x10,  0x05, 0x01, 0x00, 0x00, },
    252         //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric
    253         { 0x00, 0x02, 0x08, 0x16,  0x2b, 0x3d, 0x3d, 0x2b,  0x16, 0x08, 0x02, 0x00, },
    254         //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted.
    255         { 0x00, 0x00, 0x01, 0x05,  0x10, 0x24, 0x39, 0x40,  0x33, 0x1c, 0x0b, 0x03, },
    256     };
    257 
    258     for (int y = 0; y < height; ++y) {
    259         const uint8_t* srcP = src.addr8(0, y);
    260 
    261         // TODO: this fir filter implementation is straight forward, but slow.
    262         // It should be possible to make it much faster.
    263         for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample_x += 4, ++pixel_x) {
    264             int fir[LCD_PER_PIXEL] = { 0 };
    265             for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4)
    266                 ; sample_index < SkMin32(sample_x + 8, sample_width)
    267                 ; ++sample_index, ++coeff_index)
    268             {
    269                 int sample_value = srcP[sample_index];
    270                 for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
    271                     fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value;
    272                 }
    273             }
    274             for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
    275                 fir[subpxl_index] /= 0x100;
    276                 fir[subpxl_index] = SkMin32(fir[subpxl_index], 255);
    277             }
    278 
    279             U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR);
    280             U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG);
    281             U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB);
    282 #if SK_SHOW_TEXT_BLIT_COVERAGE
    283             r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
    284 #endif
    285             dstP[pixel_x] = SkPack888ToRGB16(r, g, b);
    286         }
    287         dstP = (uint16_t*)((char*)dstP + dstRB);
    288     }
    289 }
    290 
    291 static inline int convert_8_to_1(unsigned byte) {
    292     SkASSERT(byte <= 0xFF);
    293     return byte >> 7;
    294 }
    295 
    296 static uint8_t pack_8_to_1(const uint8_t alpha[8]) {
    297     unsigned bits = 0;
    298     for (int i = 0; i < 8; ++i) {
    299         bits <<= 1;
    300         bits |= convert_8_to_1(alpha[i]);
    301     }
    302     return SkToU8(bits);
    303 }
    304 
    305 static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
    306     const int height = mask.fBounds.height();
    307     const int width = mask.fBounds.width();
    308     const int octs = width >> 3;
    309     const int leftOverBits = width & 7;
    310 
    311     uint8_t* dst = mask.fImage;
    312     const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
    313     SkASSERT(dstPad >= 0);
    314 
    315     SkASSERT(width >= 0);
    316     SkASSERT(srcRB >= (size_t)width);
    317     const size_t srcPad = srcRB - width;
    318 
    319     for (int y = 0; y < height; ++y) {
    320         for (int i = 0; i < octs; ++i) {
    321             *dst++ = pack_8_to_1(src);
    322             src += 8;
    323         }
    324         if (leftOverBits > 0) {
    325             unsigned bits = 0;
    326             int shift = 7;
    327             for (int i = 0; i < leftOverBits; ++i, --shift) {
    328                 bits |= convert_8_to_1(*src++) << shift;
    329             }
    330             *dst++ = bits;
    331         }
    332         src += srcPad;
    333         dst += dstPad;
    334     }
    335 }
    336 
    337 static void generateMask(const SkMask& mask, const SkPath& path,
    338                          const SkMaskGamma::PreBlend& maskPreBlend) {
    339     SkPaint paint;
    340 
    341     int srcW = mask.fBounds.width();
    342     int srcH = mask.fBounds.height();
    343     int dstW = srcW;
    344     int dstH = srcH;
    345     int dstRB = mask.fRowBytes;
    346 
    347     SkMatrix matrix;
    348     matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
    349                         -SkIntToScalar(mask.fBounds.fTop));
    350 
    351     paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat);
    352     switch (mask.fFormat) {
    353         case SkMask::kBW_Format:
    354             dstRB = 0;  // signals we need a copy
    355             break;
    356         case SkMask::kA8_Format:
    357             break;
    358         case SkMask::kLCD16_Format:
    359             // TODO: trigger off LCD orientation
    360             dstW = 4*dstW - 8;
    361             matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
    362                                 -SkIntToScalar(mask.fBounds.fTop));
    363             matrix.postScale(SkIntToScalar(4), SK_Scalar1);
    364             dstRB = 0;  // signals we need a copy
    365             break;
    366         default:
    367             SkDEBUGFAIL("unexpected mask format");
    368     }
    369 
    370     SkRasterClip clip;
    371     clip.setRect(SkIRect::MakeWH(dstW, dstH));
    372 
    373     const SkImageInfo info = SkImageInfo::MakeA8(dstW, dstH);
    374     SkAutoPixmapStorage dst;
    375 
    376     if (0 == dstRB) {
    377         if (!dst.tryAlloc(info)) {
    378             // can't allocate offscreen, so empty the mask and return
    379             sk_bzero(mask.fImage, mask.computeImageSize());
    380             return;
    381         }
    382     } else {
    383         dst.reset(info, mask.fImage, dstRB);
    384     }
    385     sk_bzero(dst.writable_addr(), dst.computeByteSize());
    386 
    387     SkDraw  draw;
    388     draw.fDst   = dst;
    389     draw.fRC    = &clip;
    390     draw.fMatrix = &matrix;
    391     draw.drawPath(path, paint);
    392 
    393     switch (mask.fFormat) {
    394         case SkMask::kBW_Format:
    395             packA8ToA1(mask, dst.addr8(0, 0), dst.rowBytes());
    396             break;
    397         case SkMask::kA8_Format:
    398             if (maskPreBlend.isApplicable()) {
    399                 applyLUTToA8Mask(mask, maskPreBlend.fG);
    400             }
    401             break;
    402         case SkMask::kLCD16_Format:
    403             if (maskPreBlend.isApplicable()) {
    404                 pack4xHToLCD16<true>(dst, mask, maskPreBlend);
    405             } else {
    406                 pack4xHToLCD16<false>(dst, mask, maskPreBlend);
    407             }
    408             break;
    409         default:
    410             break;
    411     }
    412 }
    413 
    414 static void extract_alpha(const SkMask& dst,
    415                           const SkPMColor* srcRow, size_t srcRB) {
    416     int width = dst.fBounds.width();
    417     int height = dst.fBounds.height();
    418     int dstRB = dst.fRowBytes;
    419     uint8_t* dstRow = dst.fImage;
    420 
    421     for (int y = 0; y < height; ++y) {
    422         for (int x = 0; x < width; ++x) {
    423             dstRow[x] = SkGetPackedA32(srcRow[x]);
    424         }
    425         // zero any padding on each row
    426         for (int x = width; x < dstRB; ++x) {
    427             dstRow[x] = 0;
    428         }
    429         dstRow += dstRB;
    430         srcRow = (const SkPMColor*)((const char*)srcRow + srcRB);
    431     }
    432 }
    433 
    434 void SkScalerContext::getImage(const SkGlyph& origGlyph) {
    435     const SkGlyph*  glyph = &origGlyph;
    436     SkGlyph         tmpGlyph;
    437 
    438     // in case we need to call generateImage on a mask-format that is different
    439     // (i.e. larger) than what our caller allocated by looking at origGlyph.
    440     SkAutoMalloc tmpGlyphImageStorage;
    441 
    442     if (fMaskFilter) {   // restore the prefilter bounds
    443         tmpGlyph.initWithGlyphID(origGlyph.getPackedID());
    444 
    445         // need the original bounds, sans our maskfilter
    446         SkMaskFilter* mf = fMaskFilter.release();   // temp disable
    447         this->getMetrics(&tmpGlyph);
    448         fMaskFilter = sk_sp<SkMaskFilter>(mf);      // restore
    449 
    450         // we need the prefilter bounds to be <= filter bounds
    451         SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
    452         SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
    453 
    454         if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) {
    455             tmpGlyph.fImage = origGlyph.fImage;
    456         } else {
    457             tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize());
    458             tmpGlyph.fImage = tmpGlyphImageStorage.get();
    459         }
    460         glyph = &tmpGlyph;
    461     }
    462 
    463     if (fGenerateImageFromPath) {
    464         SkPath      devPath, fillPath;
    465         SkMatrix    fillToDevMatrix;
    466         SkMask      mask;
    467 
    468         this->internalGetPath(glyph->getPackedID(), &fillPath, &devPath, &fillToDevMatrix);
    469         glyph->toMask(&mask);
    470 
    471         if (fillPath.isEmpty()) {
    472             generateImage(*glyph);
    473         } else {
    474             SkASSERT(SkMask::kARGB32_Format != origGlyph.fMaskFormat);
    475             SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
    476             generateMask(mask, devPath, fPreBlend);
    477         }
    478     } else {
    479         generateImage(*glyph);
    480     }
    481 
    482     if (fMaskFilter) {
    483         SkMask      srcM, dstM;
    484         SkMatrix    matrix;
    485 
    486         // the src glyph image shouldn't be 3D
    487         SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
    488 
    489         SkAutoSMalloc<32*32> a8storage;
    490         glyph->toMask(&srcM);
    491         if (SkMask::kARGB32_Format == srcM.fFormat) {
    492             // now we need to extract the alpha-channel from the glyph's image
    493             // and copy it into a temp buffer, and then point srcM at that temp.
    494             srcM.fFormat = SkMask::kA8_Format;
    495             srcM.fRowBytes = SkAlign4(srcM.fBounds.width());
    496             size_t size = srcM.computeImageSize();
    497             a8storage.reset(size);
    498             srcM.fImage = (uint8_t*)a8storage.get();
    499             extract_alpha(srcM,
    500                           (const SkPMColor*)glyph->fImage, glyph->rowBytes());
    501         }
    502 
    503         fRec.getMatrixFrom2x2(&matrix);
    504 
    505         if (as_MFB(fMaskFilter)->filterMask(&dstM, srcM, matrix, nullptr)) {
    506             int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
    507             int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
    508             int dstRB = origGlyph.rowBytes();
    509             int srcRB = dstM.fRowBytes;
    510 
    511             const uint8_t* src = (const uint8_t*)dstM.fImage;
    512             uint8_t* dst = (uint8_t*)origGlyph.fImage;
    513 
    514             if (SkMask::k3D_Format == dstM.fFormat) {
    515                 // we have to copy 3 times as much
    516                 height *= 3;
    517             }
    518 
    519             // clean out our glyph, since it may be larger than dstM
    520             //sk_bzero(dst, height * dstRB);
    521 
    522             while (--height >= 0) {
    523                 memcpy(dst, src, width);
    524                 src += srcRB;
    525                 dst += dstRB;
    526             }
    527             SkMask::FreeImage(dstM.fImage);
    528 
    529             if (fPreBlendForFilter.isApplicable()) {
    530                 applyLUTToA8Mask(srcM, fPreBlendForFilter.fG);
    531             }
    532         }
    533     }
    534 }
    535 
    536 void SkScalerContext::getPath(SkPackedGlyphID glyphID, SkPath* path) {
    537     this->internalGetPath(glyphID, nullptr, path, nullptr);
    538 }
    539 
    540 void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* fm) {
    541     SkASSERT(fm);
    542     this->generateFontMetrics(fm);
    543 }
    544 
    545 SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) {
    546     return 0;
    547 }
    548 
    549 ///////////////////////////////////////////////////////////////////////////////
    550 
    551 void SkScalerContext::internalGetPath(SkPackedGlyphID glyphID, SkPath* fillPath,
    552                                       SkPath* devPath, SkMatrix* fillToDevMatrix) {
    553     SkPath  path;
    554     generatePath(glyphID.code(), &path);
    555 
    556     if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
    557         SkFixed dx = glyphID.getSubXFixed();
    558         SkFixed dy = glyphID.getSubYFixed();
    559         if (dx | dy) {
    560             path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
    561         }
    562     }
    563 
    564     if (fRec.fFrameWidth > 0 || fPathEffect != nullptr) {
    565         // need the path in user-space, with only the point-size applied
    566         // so that our stroking and effects will operate the same way they
    567         // would if the user had extracted the path themself, and then
    568         // called drawPath
    569         SkPath      localPath;
    570         SkMatrix    matrix, inverse;
    571 
    572         fRec.getMatrixFrom2x2(&matrix);
    573         if (!matrix.invert(&inverse)) {
    574             // assume fillPath and devPath are already empty.
    575             return;
    576         }
    577         path.transform(inverse, &localPath);
    578         // now localPath is only affected by the paint settings, and not the canvas matrix
    579 
    580         SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
    581 
    582         if (fRec.fFrameWidth > 0) {
    583             rec.setStrokeStyle(fRec.fFrameWidth,
    584                                SkToBool(fRec.fFlags & kFrameAndFill_Flag));
    585             // glyphs are always closed contours, so cap type is ignored,
    586             // so we just pass something.
    587             rec.setStrokeParams((SkPaint::Cap)fRec.fStrokeCap,
    588                                 (SkPaint::Join)fRec.fStrokeJoin,
    589                                 fRec.fMiterLimit);
    590         }
    591 
    592         if (fPathEffect) {
    593             SkPath effectPath;
    594             if (fPathEffect->filterPath(&effectPath, localPath, &rec, nullptr)) {
    595                 localPath.swap(effectPath);
    596             }
    597         }
    598 
    599         if (rec.needToApply()) {
    600             SkPath strokePath;
    601             if (rec.applyToPath(&strokePath, localPath)) {
    602                 localPath.swap(strokePath);
    603             }
    604         }
    605 
    606         // now return stuff to the caller
    607         if (fillToDevMatrix) {
    608             *fillToDevMatrix = matrix;
    609         }
    610         if (devPath) {
    611             localPath.transform(matrix, devPath);
    612         }
    613         if (fillPath) {
    614             fillPath->swap(localPath);
    615         }
    616     } else {   // nothing tricky to do
    617         if (fillToDevMatrix) {
    618             fillToDevMatrix->reset();
    619         }
    620         if (devPath) {
    621             if (fillPath == nullptr) {
    622                 devPath->swap(path);
    623             } else {
    624                 *devPath = path;
    625             }
    626         }
    627 
    628         if (fillPath) {
    629             fillPath->swap(path);
    630         }
    631     }
    632 
    633     if (devPath) {
    634         devPath->updateBoundsCache();
    635     }
    636     if (fillPath) {
    637         fillPath->updateBoundsCache();
    638     }
    639 }
    640 
    641 
    642 void SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const {
    643     dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0,
    644                 fPost2x2[1][0], fPost2x2[1][1], 0,
    645                 0,              0,              1);
    646 }
    647 
    648 void SkScalerContextRec::getLocalMatrix(SkMatrix* m) const {
    649     SkPaintPriv::MakeTextMatrix(m, fTextSize, fPreScaleX, fPreSkewX);
    650 }
    651 
    652 void SkScalerContextRec::getSingleMatrix(SkMatrix* m) const {
    653     this->getLocalMatrix(m);
    654 
    655     //  now concat the device matrix
    656     SkMatrix    deviceMatrix;
    657     this->getMatrixFrom2x2(&deviceMatrix);
    658     m->postConcat(deviceMatrix);
    659 }
    660 
    661 bool SkScalerContextRec::computeMatrices(PreMatrixScale preMatrixScale, SkVector* s, SkMatrix* sA,
    662                                          SkMatrix* GsA, SkMatrix* G_inv, SkMatrix* A_out)
    663 {
    664     // A is the 'total' matrix.
    665     SkMatrix A;
    666     this->getSingleMatrix(&A);
    667 
    668     // The caller may find the 'total' matrix useful when dealing directly with EM sizes.
    669     if (A_out) {
    670         *A_out = A;
    671     }
    672 
    673     // GA is the matrix A with rotation removed.
    674     SkMatrix GA;
    675     bool skewedOrFlipped = A.getSkewX() || A.getSkewY() || A.getScaleX() < 0 || A.getScaleY() < 0;
    676     if (skewedOrFlipped) {
    677         // QR by Givens rotations. G is Q^T and GA is R. G is rotational (no reflections).
    678         // h is where A maps the horizontal baseline.
    679         SkPoint h = SkPoint::Make(SK_Scalar1, 0);
    680         A.mapPoints(&h, 1);
    681 
    682         // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
    683         SkMatrix G;
    684         SkComputeGivensRotation(h, &G);
    685 
    686         GA = G;
    687         GA.preConcat(A);
    688 
    689         // The 'remainingRotation' is G inverse, which is fairly simple since G is 2x2 rotational.
    690         if (G_inv) {
    691             G_inv->setAll(
    692                 G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
    693                 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
    694                 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
    695         }
    696     } else {
    697         GA = A;
    698         if (G_inv) {
    699             G_inv->reset();
    700         }
    701     }
    702 
    703     // If the 'total' matrix is singular, set the 'scale' to something finite and zero the matrices.
    704     // All underlying ports have issues with zero text size, so use the matricies to zero.
    705     // If one of the scale factors is less than 1/256 then an EM filling square will
    706     // never affect any pixels.
    707     if (SkScalarAbs(GA.get(SkMatrix::kMScaleX)) <= SK_ScalarNearlyZero ||
    708         SkScalarAbs(GA.get(SkMatrix::kMScaleY)) <= SK_ScalarNearlyZero)
    709     {
    710         s->fX = SK_Scalar1;
    711         s->fY = SK_Scalar1;
    712         sA->setScale(0, 0);
    713         if (GsA) {
    714             GsA->setScale(0, 0);
    715         }
    716         if (G_inv) {
    717             G_inv->reset();
    718         }
    719         return false;
    720     }
    721 
    722     // At this point, given GA, create s.
    723     switch (preMatrixScale) {
    724         case kFull_PreMatrixScale:
    725             s->fX = SkScalarAbs(GA.get(SkMatrix::kMScaleX));
    726             s->fY = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
    727             break;
    728         case kVertical_PreMatrixScale: {
    729             SkScalar yScale = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
    730             s->fX = yScale;
    731             s->fY = yScale;
    732             break;
    733         }
    734         case kVerticalInteger_PreMatrixScale: {
    735             SkScalar realYScale = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
    736             SkScalar intYScale = SkScalarRoundToScalar(realYScale);
    737             if (intYScale == 0) {
    738                 intYScale = SK_Scalar1;
    739             }
    740             s->fX = intYScale;
    741             s->fY = intYScale;
    742             break;
    743         }
    744     }
    745 
    746     // The 'remaining' matrix sA is the total matrix A without the scale.
    747     if (!skewedOrFlipped && (
    748             (kFull_PreMatrixScale == preMatrixScale) ||
    749             (kVertical_PreMatrixScale == preMatrixScale && A.getScaleX() == A.getScaleY())))
    750     {
    751         // If GA == A and kFull_PreMatrixScale, sA is identity.
    752         // If GA == A and kVertical_PreMatrixScale and A.scaleX == A.scaleY, sA is identity.
    753         sA->reset();
    754     } else if (!skewedOrFlipped && kVertical_PreMatrixScale == preMatrixScale) {
    755         // If GA == A and kVertical_PreMatrixScale, sA.scaleY is SK_Scalar1.
    756         sA->reset();
    757         sA->setScaleX(A.getScaleX() / s->fY);
    758     } else {
    759         // TODO: like kVertical_PreMatrixScale, kVerticalInteger_PreMatrixScale with int scales.
    760         *sA = A;
    761         sA->preScale(SkScalarInvert(s->fX), SkScalarInvert(s->fY));
    762     }
    763 
    764     // The 'remainingWithoutRotation' matrix GsA is the non-rotational part of A without the scale.
    765     if (GsA) {
    766         *GsA = GA;
    767          // G is rotational so reorders with the scale.
    768         GsA->preScale(SkScalarInvert(s->fX), SkScalarInvert(s->fY));
    769     }
    770 
    771     return true;
    772 }
    773 
    774 SkAxisAlignment SkScalerContext::computeAxisAlignmentForHText() {
    775     // Why fPost2x2 can be used here.
    776     // getSingleMatrix multiplies in getLocalMatrix, which consists of
    777     // * fTextSize (a scale, which has no effect)
    778     // * fPreScaleX (a scale in x, which has no effect)
    779     // * fPreSkewX (has no effect, but would on vertical text alignment).
    780     // In other words, making the text bigger, stretching it along the
    781     // horizontal axis, or fake italicizing it does not move the baseline.
    782 
    783     if (0 == fRec.fPost2x2[1][0]) {
    784         // The x axis is mapped onto the x axis.
    785         return kX_SkAxisAlignment;
    786     }
    787     if (0 == fRec.fPost2x2[0][0]) {
    788         // The x axis is mapped onto the y axis.
    789         return kY_SkAxisAlignment;
    790     }
    791     return kNone_SkAxisAlignment;
    792 }
    793 
    794 ///////////////////////////////////////////////////////////////////////////////
    795 
    796 class SkScalerContext_Empty : public SkScalerContext {
    797 public:
    798     SkScalerContext_Empty(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
    799                           const SkDescriptor* desc)
    800         : SkScalerContext(std::move(typeface), effects, desc) {}
    801 
    802 protected:
    803     unsigned generateGlyphCount() override {
    804         return 0;
    805     }
    806     uint16_t generateCharToGlyph(SkUnichar uni) override {
    807         return 0;
    808     }
    809     void generateAdvance(SkGlyph* glyph) override {
    810         glyph->zeroMetrics();
    811     }
    812     void generateMetrics(SkGlyph* glyph) override {
    813         glyph->zeroMetrics();
    814     }
    815     void generateImage(const SkGlyph& glyph) override {}
    816     void generatePath(SkGlyphID glyph, SkPath* path) override {}
    817     void generateFontMetrics(SkPaint::FontMetrics* metrics) override {
    818         if (metrics) {
    819             sk_bzero(metrics, sizeof(*metrics));
    820         }
    821     }
    822 };
    823 
    824 extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
    825 
    826 std::unique_ptr<SkScalerContext> SkTypeface::createScalerContext(
    827     const SkScalerContextEffects& effects, const SkDescriptor* desc, bool allowFailure) const
    828 {
    829     std::unique_ptr<SkScalerContext> c(this->onCreateScalerContext(effects, desc));
    830     if (!c && !allowFailure) {
    831         c = skstd::make_unique<SkScalerContext_Empty>(sk_ref_sp(const_cast<SkTypeface*>(this)),
    832                                                       effects, desc);
    833     }
    834     return c;
    835 }
    836 
    837 /*
    838  *  Return the scalar with only limited fractional precision. Used to consolidate matrices
    839  *  that vary only slightly when we create our key into the font cache, since the font scaler
    840  *  typically returns the same looking resuts for tiny changes in the matrix.
    841  */
    842 static SkScalar sk_relax(SkScalar x) {
    843     SkScalar n = SkScalarRoundToScalar(x * 1024);
    844     return n / 1024.0f;
    845 }
    846 
    847 static SkMask::Format compute_mask_format(const SkPaint& paint) {
    848     uint32_t flags = paint.getFlags();
    849 
    850     // Antialiasing being disabled trumps all other settings.
    851     if (!(flags & SkPaint::kAntiAlias_Flag)) {
    852         return SkMask::kBW_Format;
    853     }
    854 
    855     if (flags & SkPaint::kLCDRenderText_Flag) {
    856         return SkMask::kLCD16_Format;
    857     }
    858 
    859     return SkMask::kA8_Format;
    860 }
    861 
    862 // Beyond this size, LCD doesn't appreciably improve quality, but it always
    863 // cost more RAM and draws slower, so we set a cap.
    864 #ifndef SK_MAX_SIZE_FOR_LCDTEXT
    865     #define SK_MAX_SIZE_FOR_LCDTEXT    48
    866 #endif
    867 
    868 const SkScalar gMaxSize2ForLCDText = SK_MAX_SIZE_FOR_LCDTEXT * SK_MAX_SIZE_FOR_LCDTEXT;
    869 
    870 static bool too_big_for_lcd(const SkScalerContextRec& rec, bool checkPost2x2) {
    871     if (checkPost2x2) {
    872         SkScalar area = rec.fPost2x2[0][0] * rec.fPost2x2[1][1] -
    873                         rec.fPost2x2[1][0] * rec.fPost2x2[0][1];
    874         area *= rec.fTextSize * rec.fTextSize;
    875         return area > gMaxSize2ForLCDText;
    876     } else {
    877         return rec.fTextSize > SK_MAX_SIZE_FOR_LCDTEXT;
    878     }
    879 }
    880 
    881 // if linear-text is on, then we force hinting to be off (since that's sort of
    882 // the point of linear-text.
    883 static SkPaint::Hinting computeHinting(const SkPaint& paint) {
    884     SkPaint::Hinting h = paint.getHinting();
    885     if (paint.isLinearText()) {
    886         h = SkPaint::kNo_Hinting;
    887     }
    888     return h;
    889 }
    890 
    891 // The only reason this is not file static is because it needs the context of SkScalerContext to
    892 // access SkPaint::computeLuminanceColor.
    893 void SkScalerContext::MakeRecAndEffects(const SkPaint& paint,
    894                                         const SkSurfaceProps* surfaceProps,
    895                                         const SkMatrix* deviceMatrix,
    896                                         SkScalerContextFlags scalerContextFlags,
    897                                         SkScalerContextRec* rec,
    898                                         SkScalerContextEffects* effects) {
    899     SkASSERT(deviceMatrix == nullptr || !deviceMatrix->hasPerspective());
    900 
    901     SkTypeface* typeface = paint.getTypeface();
    902     if (nullptr == typeface) {
    903         typeface = SkTypeface::GetDefaultTypeface();
    904     }
    905     rec->fFontID = typeface->uniqueID();
    906     rec->fTextSize = paint.getTextSize();
    907     rec->fPreScaleX = paint.getTextScaleX();
    908     rec->fPreSkewX  = paint.getTextSkewX();
    909 
    910     bool checkPost2x2 = false;
    911 
    912     if (deviceMatrix) {
    913         const SkMatrix::TypeMask mask = deviceMatrix->getType();
    914         if (mask & SkMatrix::kScale_Mask) {
    915             rec->fPost2x2[0][0] = sk_relax(deviceMatrix->getScaleX());
    916             rec->fPost2x2[1][1] = sk_relax(deviceMatrix->getScaleY());
    917             checkPost2x2 = true;
    918         } else {
    919             rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1;
    920         }
    921         if (mask & SkMatrix::kAffine_Mask) {
    922             rec->fPost2x2[0][1] = sk_relax(deviceMatrix->getSkewX());
    923             rec->fPost2x2[1][0] = sk_relax(deviceMatrix->getSkewY());
    924             checkPost2x2 = true;
    925         } else {
    926             rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0;
    927         }
    928     } else {
    929         rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1;
    930         rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0;
    931     }
    932 
    933     SkPaint::Style  style = paint.getStyle();
    934     SkScalar        strokeWidth = paint.getStrokeWidth();
    935 
    936     unsigned flags = 0;
    937 
    938     if (paint.isFakeBoldText()) {
    939 #ifdef SK_USE_FREETYPE_EMBOLDEN
    940         flags |= SkScalerContext::kEmbolden_Flag;
    941 #else
    942         SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(),
    943                                                     kStdFakeBoldInterpKeys,
    944                                                     kStdFakeBoldInterpValues,
    945                                                     kStdFakeBoldInterpLength);
    946         SkScalar extra = paint.getTextSize() * fakeBoldScale;
    947 
    948         if (style == SkPaint::kFill_Style) {
    949             style = SkPaint::kStrokeAndFill_Style;
    950             strokeWidth = extra;    // ignore paint's strokeWidth if it was "fill"
    951         } else {
    952             strokeWidth += extra;
    953         }
    954 #endif
    955     }
    956 
    957     if (paint.isDevKernText()) {
    958         flags |= SkScalerContext::kDevKernText_Flag;
    959     }
    960 
    961     if (style != SkPaint::kFill_Style && strokeWidth > 0) {
    962         rec->fFrameWidth = strokeWidth;
    963         rec->fMiterLimit = paint.getStrokeMiter();
    964         rec->fStrokeJoin = SkToU8(paint.getStrokeJoin());
    965         rec->fStrokeCap = SkToU8(paint.getStrokeCap());
    966 
    967         if (style == SkPaint::kStrokeAndFill_Style) {
    968             flags |= SkScalerContext::kFrameAndFill_Flag;
    969         }
    970     } else {
    971         rec->fFrameWidth = 0;
    972         rec->fMiterLimit = 0;
    973         rec->fStrokeJoin = 0;
    974         rec->fStrokeCap = 0;
    975     }
    976 
    977     rec->fMaskFormat = SkToU8(compute_mask_format(paint));
    978 
    979     if (SkMask::kLCD16_Format == rec->fMaskFormat) {
    980         if (too_big_for_lcd(*rec, checkPost2x2)) {
    981             rec->fMaskFormat = SkMask::kA8_Format;
    982             flags |= SkScalerContext::kGenA8FromLCD_Flag;
    983         } else {
    984             SkPixelGeometry geometry = surfaceProps
    985                                        ? surfaceProps->pixelGeometry()
    986                                        : SkSurfacePropsDefaultPixelGeometry();
    987             switch (geometry) {
    988                 case kUnknown_SkPixelGeometry:
    989                     // eeek, can't support LCD
    990                     rec->fMaskFormat = SkMask::kA8_Format;
    991                     flags |= SkScalerContext::kGenA8FromLCD_Flag;
    992                     break;
    993                 case kRGB_H_SkPixelGeometry:
    994                     // our default, do nothing.
    995                     break;
    996                 case kBGR_H_SkPixelGeometry:
    997                     flags |= SkScalerContext::kLCD_BGROrder_Flag;
    998                     break;
    999                 case kRGB_V_SkPixelGeometry:
   1000                     flags |= SkScalerContext::kLCD_Vertical_Flag;
   1001                     break;
   1002                 case kBGR_V_SkPixelGeometry:
   1003                     flags |= SkScalerContext::kLCD_Vertical_Flag;
   1004                     flags |= SkScalerContext::kLCD_BGROrder_Flag;
   1005                     break;
   1006             }
   1007         }
   1008     }
   1009 
   1010     if (paint.isEmbeddedBitmapText()) {
   1011         flags |= SkScalerContext::kEmbeddedBitmapText_Flag;
   1012     }
   1013     if (paint.isSubpixelText()) {
   1014         flags |= SkScalerContext::kSubpixelPositioning_Flag;
   1015     }
   1016     if (paint.isAutohinted()) {
   1017         flags |= SkScalerContext::kForceAutohinting_Flag;
   1018     }
   1019     if (paint.isVerticalText()) {
   1020         flags |= SkScalerContext::kVertical_Flag;
   1021     }
   1022     if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) {
   1023         flags |= SkScalerContext::kGenA8FromLCD_Flag;
   1024     }
   1025     rec->fFlags = SkToU16(flags);
   1026 
   1027     // these modify fFlags, so do them after assigning fFlags
   1028     rec->setHinting(computeHinting(paint));
   1029 
   1030     rec->setLuminanceColor(paint.computeLuminanceColor());
   1031 
   1032     // For now always set the paint gamma equal to the device gamma.
   1033     // The math in SkMaskGamma can handle them being different,
   1034     // but it requires superluminous masks when
   1035     // Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large.
   1036     rec->setDeviceGamma(SK_GAMMA_EXPONENT);
   1037     rec->setPaintGamma(SK_GAMMA_EXPONENT);
   1038 
   1039 #ifdef SK_GAMMA_CONTRAST
   1040     rec->setContrast(SK_GAMMA_CONTRAST);
   1041 #else
   1042     // A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise.
   1043     // With lower values small text appears washed out (though correctly so).
   1044     // With higher values lcd fringing is worse and the smoothing effect of
   1045     // partial coverage is diminished.
   1046     rec->setContrast(0.5f);
   1047 #endif
   1048 
   1049     // Allow the fonthost to modify our rec before we use it as a key into the
   1050     // cache. This way if we're asking for something that they will ignore,
   1051     // they can modify our rec up front, so we don't create duplicate cache
   1052     // entries.
   1053     typeface->onFilterRec(rec);
   1054 
   1055     if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kFakeGamma)) {
   1056         rec->ignoreGamma();
   1057     }
   1058     if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kBoostContrast)) {
   1059         rec->setContrast(0);
   1060     }
   1061 
   1062     new (effects) SkScalerContextEffects{paint};
   1063     if (effects->fPathEffect) {
   1064         rec->fMaskFormat = SkMask::kA8_Format;  // force antialiasing when we do the scan conversion
   1065         // seems like we could support kLCD as well at this point...
   1066     }
   1067     if (effects->fMaskFilter) {
   1068         // force antialiasing with maskfilters
   1069         rec->fMaskFormat = SkMask::kA8_Format;
   1070         // Pre-blend is not currently applied to filtered text.
   1071         // The primary filter is blur, for which contrast makes no sense,
   1072         // and for which the destination guess error is more visible.
   1073         // Also, all existing users of blur have calibrated for linear.
   1074         rec->ignorePreBlend();
   1075     }
   1076 
   1077     // If we're asking for A8, we force the colorlum to be gray, since that
   1078     // limits the number of unique entries, and the scaler will only look at
   1079     // the lum of one of them.
   1080     switch (rec->fMaskFormat) {
   1081         case SkMask::kLCD16_Format: {
   1082             // filter down the luminance color to a finite number of bits
   1083             SkColor color = rec->getLuminanceColor();
   1084             rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color));
   1085             break;
   1086         }
   1087         case SkMask::kA8_Format: {
   1088             // filter down the luminance to a single component, since A8 can't
   1089             // use per-component information
   1090             SkColor color = rec->getLuminanceColor();
   1091             U8CPU lum = SkComputeLuminance(SkColorGetR(color),
   1092                                            SkColorGetG(color),
   1093                                            SkColorGetB(color));
   1094             // reduce to our finite number of bits
   1095             color = SkColorSetRGB(lum, lum, lum);
   1096             rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color));
   1097             break;
   1098         }
   1099         case SkMask::kBW_Format:
   1100             // No need to differentiate gamma or apply contrast if we're BW
   1101             rec->ignorePreBlend();
   1102             break;
   1103     }
   1104 }
   1105 
   1106 SkDescriptor* SkScalerContext::MakeDescriptorForPaths(SkFontID typefaceID,
   1107                                                       SkAutoDescriptor* ad) {
   1108     SkScalerContextRec rec;
   1109     memset(&rec, 0, sizeof(rec));
   1110     rec.fFontID = typefaceID;
   1111     rec.fTextSize = SkPaint::kCanonicalTextSizeForPaths;
   1112     rec.fPreScaleX = rec.fPost2x2[0][0] = rec.fPost2x2[1][1] = SK_Scalar1;
   1113     return AutoDescriptorGivenRecAndEffects(rec, SkScalerContextEffects(), ad);
   1114 }
   1115 
   1116 SkDescriptor* SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
   1117     const SkPaint& paint, const SkSurfaceProps* surfaceProps,
   1118     SkScalerContextFlags scalerContextFlags,
   1119     const SkMatrix* deviceMatrix, SkAutoDescriptor* ad,
   1120     SkScalerContextEffects* effects) {
   1121 
   1122     SkScalerContextRec rec;
   1123     MakeRecAndEffects(paint, surfaceProps, deviceMatrix, scalerContextFlags, &rec, effects);
   1124     return AutoDescriptorGivenRecAndEffects(rec, *effects, ad);
   1125 }
   1126 
   1127 static size_t calculate_size_and_flatten(
   1128     const SkScalerContextRec& rec,
   1129     const SkScalerContextEffects& effects,
   1130     SkBinaryWriteBuffer* pathEffectBuffer,
   1131     SkBinaryWriteBuffer* maskFilterBuffer)
   1132 {
   1133     size_t descSize = sizeof(rec);
   1134     int entryCount = 1;
   1135 
   1136     if (effects.fPathEffect) {
   1137         effects.fPathEffect->flatten(*pathEffectBuffer);
   1138         descSize += pathEffectBuffer->bytesWritten();
   1139         entryCount += 1;
   1140     }
   1141     if (effects.fMaskFilter) {
   1142         effects.fMaskFilter->flatten(*maskFilterBuffer);
   1143         descSize += maskFilterBuffer->bytesWritten();
   1144         entryCount += 1;
   1145     }
   1146 
   1147     descSize += SkDescriptor::ComputeOverhead(entryCount);
   1148     return descSize;
   1149 }
   1150 
   1151 #ifdef SK_DEBUG
   1152   #define TEST_DESC
   1153 #endif
   1154 
   1155 #ifdef TEST_DESC
   1156 static void test_desc(const SkScalerContextRec& rec,
   1157                       const SkScalerContextEffects& effects,
   1158                       SkBinaryWriteBuffer* peBuffer,
   1159                       SkBinaryWriteBuffer* mfBuffer,
   1160                       const SkDescriptor* desc) {
   1161     // Check that we completely write the bytes in desc (our key), and that
   1162     // there are no uninitialized bytes. If there were, then we would get
   1163     // false-misses (or worse, false-hits) in our fontcache.
   1164     //
   1165     // We do this buy filling 2 others, one with 0s and the other with 1s
   1166     // and create those, and then check that all 3 are identical.
   1167     SkAutoDescriptor    ad1(desc->getLength());
   1168     SkAutoDescriptor    ad2(desc->getLength());
   1169     SkDescriptor*       desc1 = ad1.getDesc();
   1170     SkDescriptor*       desc2 = ad2.getDesc();
   1171 
   1172     memset(desc1, 0x00, desc->getLength());
   1173     memset(desc2, 0xFF, desc->getLength());
   1174 
   1175     desc1->init();
   1176     desc2->init();
   1177     desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
   1178     desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
   1179 
   1180     auto add_flattenable = [](SkDescriptor* desc, uint32_t tag,
   1181                               SkBinaryWriteBuffer* buffer) {
   1182         buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), nullptr));
   1183     };
   1184 
   1185     if (effects.fPathEffect) {
   1186         add_flattenable(desc1, kPathEffect_SkDescriptorTag, peBuffer);
   1187         add_flattenable(desc2, kPathEffect_SkDescriptorTag, peBuffer);
   1188     }
   1189     if (effects.fMaskFilter) {
   1190         add_flattenable(desc1, kMaskFilter_SkDescriptorTag, mfBuffer);
   1191         add_flattenable(desc2, kMaskFilter_SkDescriptorTag, mfBuffer);
   1192     }
   1193 
   1194     SkASSERT(desc->getLength() == desc1->getLength());
   1195     SkASSERT(desc->getLength() == desc2->getLength());
   1196     desc1->computeChecksum();
   1197     desc2->computeChecksum();
   1198     SkASSERT(!memcmp(desc, desc1, desc->getLength()));
   1199     SkASSERT(!memcmp(desc, desc2, desc->getLength()));
   1200 }
   1201 #endif
   1202 
   1203 void generate_descriptor(
   1204     const SkScalerContextRec& rec,
   1205     const SkScalerContextEffects& effects,
   1206     SkBinaryWriteBuffer* pathEffectBuffer,
   1207     SkBinaryWriteBuffer* maskFilterBuffer,
   1208     SkDescriptor* desc)
   1209 {
   1210     desc->init();
   1211     desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
   1212 
   1213     auto add = [&desc](uint32_t tag, SkBinaryWriteBuffer* buffer) {
   1214         buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), nullptr));
   1215     };
   1216 
   1217     if (effects.fPathEffect) {
   1218         add(kPathEffect_SkDescriptorTag, pathEffectBuffer);
   1219     }
   1220     if (effects.fMaskFilter) {
   1221         add(kMaskFilter_SkDescriptorTag, maskFilterBuffer);
   1222     }
   1223 
   1224     desc->computeChecksum();
   1225 #ifdef TEST_DESC
   1226     test_desc(rec, effects, pathEffectBuffer, maskFilterBuffer, desc);
   1227 #endif
   1228 }
   1229 
   1230 SkDescriptor* SkScalerContext::AutoDescriptorGivenRecAndEffects(
   1231     const SkScalerContextRec& rec,
   1232     const SkScalerContextEffects& effects,
   1233     SkAutoDescriptor* ad)
   1234 {
   1235     SkBinaryWriteBuffer peBuffer, mfBuffer;
   1236 
   1237     ad->reset(calculate_size_and_flatten(rec, effects, &peBuffer, &mfBuffer));
   1238 
   1239     generate_descriptor(rec, effects, &peBuffer, &mfBuffer, ad->getDesc());
   1240 
   1241     return ad->getDesc();
   1242 }
   1243 
   1244 std::unique_ptr<SkDescriptor> SkScalerContext::DescriptorGivenRecAndEffects(
   1245     const SkScalerContextRec& rec,
   1246     const SkScalerContextEffects& effects)
   1247 {
   1248     SkBinaryWriteBuffer peBuffer, mfBuffer;
   1249 
   1250     auto desc = SkDescriptor::Alloc(calculate_size_and_flatten(rec, effects, &peBuffer, &mfBuffer));
   1251 
   1252     generate_descriptor(rec, effects, &peBuffer, &mfBuffer, desc.get());
   1253 
   1254     return desc;
   1255 }
   1256 
   1257 void SkScalerContext::DescriptorBufferGiveRec(const SkScalerContextRec& rec, void* buffer) {
   1258     SkScalerContextEffects noEffects;
   1259     SkBinaryWriteBuffer peBuffer, mfBuffer;
   1260     generate_descriptor(rec, noEffects, &peBuffer, &mfBuffer, (SkDescriptor*)buffer);
   1261 }
   1262 
   1263 bool SkScalerContext::CheckBufferSizeForRec(const SkScalerContextRec& rec,
   1264                                             const SkScalerContextEffects& effects,
   1265                                             size_t size) {
   1266     SkBinaryWriteBuffer peBuffer, mfBuffer;
   1267 
   1268     return size >= calculate_size_and_flatten(rec, effects, &peBuffer, &mfBuffer);
   1269 }
   1270 
   1271 
   1272 
   1273 
   1274