Home | History | Annotate | Download | only in ports
      1 /*
      2  * Copyright 2006-2012 The Android Open Source Project
      3  * Copyright 2012 Mozilla Foundation
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "SkBitmap.h"
     10 #include "SkCanvas.h"
     11 #include "SkColor.h"
     12 #include "SkColorPriv.h"
     13 #include "SkFDot6.h"
     14 #include "SkFontHost_FreeType_common.h"
     15 #include "SkPath.h"
     16 
     17 #include <ft2build.h>
     18 #include FT_FREETYPE_H
     19 #include FT_BITMAP_H
     20 #include FT_IMAGE_H
     21 #include FT_OUTLINE_H
     22 // In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
     23 #include FT_SYNTHESIS_H
     24 
     25 // FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
     26 // were introduced in FreeType 2.5.0.
     27 // The following may be removed once FreeType 2.5.0 is required to build.
     28 #ifndef FT_LOAD_COLOR
     29 #    define FT_LOAD_COLOR ( 1L << 20 )
     30 #    define FT_PIXEL_MODE_BGRA 7
     31 #endif
     32 
     33 //#define SK_SHOW_TEXT_BLIT_COVERAGE
     34 
     35 namespace {
     36 
     37 FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
     38     switch (format) {
     39         case SkMask::kBW_Format:
     40             return FT_PIXEL_MODE_MONO;
     41         case SkMask::kA8_Format:
     42         default:
     43             return FT_PIXEL_MODE_GRAY;
     44     }
     45 }
     46 
     47 ///////////////////////////////////////////////////////////////////////////////
     48 
     49 uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) {
     50 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
     51     r = SkTMax(r, (U8CPU)0x40);
     52     g = SkTMax(g, (U8CPU)0x40);
     53     b = SkTMax(b, (U8CPU)0x40);
     54 #endif
     55     return SkPack888ToRGB16(r, g, b);
     56 }
     57 
     58 uint16_t grayToRGB16(U8CPU gray) {
     59 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
     60     gray = SkTMax(gray, (U8CPU)0x40);
     61 #endif
     62     return SkPack888ToRGB16(gray, gray, gray);
     63 }
     64 
     65 int bittst(const uint8_t data[], int bitOffset) {
     66     SkASSERT(bitOffset >= 0);
     67     int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7);
     68     return lowBit & 1;
     69 }
     70 
     71 /**
     72  *  Copies a FT_Bitmap into an SkMask with the same dimensions.
     73  *
     74  *  FT_PIXEL_MODE_MONO
     75  *  FT_PIXEL_MODE_GRAY
     76  *  FT_PIXEL_MODE_LCD
     77  *  FT_PIXEL_MODE_LCD_V
     78  */
     79 template<bool APPLY_PREBLEND>
     80 void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR,
     81                   const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB)
     82 {
     83     SkASSERT(SkMask::kLCD16_Format == mask.fFormat);
     84     if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) {
     85         SkASSERT(mask.fBounds.width() == static_cast<int>(bitmap.width));
     86     }
     87     if (FT_PIXEL_MODE_LCD_V != bitmap.pixel_mode) {
     88         SkASSERT(mask.fBounds.height() == static_cast<int>(bitmap.rows));
     89     }
     90 
     91     const uint8_t* src = bitmap.buffer;
     92     uint16_t* dst = reinterpret_cast<uint16_t*>(mask.fImage);
     93     const size_t dstRB = mask.fRowBytes;
     94 
     95     const int width = mask.fBounds.width();
     96     const int height = mask.fBounds.height();
     97 
     98     switch (bitmap.pixel_mode) {
     99         case FT_PIXEL_MODE_MONO:
    100             for (int y = height; y --> 0;) {
    101                 for (int x = 0; x < width; ++x) {
    102                     dst[x] = -bittst(src, x);
    103                 }
    104                 dst = (uint16_t*)((char*)dst + dstRB);
    105                 src += bitmap.pitch;
    106             }
    107             break;
    108         case FT_PIXEL_MODE_GRAY:
    109             for (int y = height; y --> 0;) {
    110                 for (int x = 0; x < width; ++x) {
    111                     dst[x] = grayToRGB16(src[x]);
    112                 }
    113                 dst = (uint16_t*)((char*)dst + dstRB);
    114                 src += bitmap.pitch;
    115             }
    116             break;
    117         case FT_PIXEL_MODE_LCD:
    118             SkASSERT(3 * mask.fBounds.width() == static_cast<int>(bitmap.width));
    119             for (int y = height; y --> 0;) {
    120                 const uint8_t* triple = src;
    121                 if (lcdIsBGR) {
    122                     for (int x = 0; x < width; x++) {
    123                         dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
    124                                             sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
    125                                             sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
    126                         triple += 3;
    127                     }
    128                 } else {
    129                     for (int x = 0; x < width; x++) {
    130                         dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
    131                                             sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
    132                                             sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
    133                         triple += 3;
    134                     }
    135                 }
    136                 src += bitmap.pitch;
    137                 dst = (uint16_t*)((char*)dst + dstRB);
    138             }
    139             break;
    140         case FT_PIXEL_MODE_LCD_V:
    141             SkASSERT(3 * mask.fBounds.height() == static_cast<int>(bitmap.rows));
    142             for (int y = height; y --> 0;) {
    143                 const uint8_t* srcR = src;
    144                 const uint8_t* srcG = srcR + bitmap.pitch;
    145                 const uint8_t* srcB = srcG + bitmap.pitch;
    146                 if (lcdIsBGR) {
    147                     SkTSwap(srcR, srcB);
    148                 }
    149                 for (int x = 0; x < width; x++) {
    150                     dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
    151                                         sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
    152                                         sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
    153                 }
    154                 src += 3 * bitmap.pitch;
    155                 dst = (uint16_t*)((char*)dst + dstRB);
    156             }
    157             break;
    158         default:
    159             SkDEBUGF(("FT_Pixel_Mode %d", bitmap.pixel_mode));
    160             SkDEBUGFAIL("unsupported FT_Pixel_Mode for LCD16");
    161             break;
    162     }
    163 }
    164 
    165 /**
    166  *  Copies a FT_Bitmap into an SkMask with the same dimensions.
    167  *
    168  *  Yes, No, Never Requested, Never Produced
    169  *
    170  *                        kBW kA8 k3D kARGB32 kLCD16
    171  *  FT_PIXEL_MODE_MONO     Y   Y  NR     N       Y
    172  *  FT_PIXEL_MODE_GRAY     N   Y  NR     N       Y
    173  *  FT_PIXEL_MODE_GRAY2   NP  NP  NR    NP      NP
    174  *  FT_PIXEL_MODE_GRAY4   NP  NP  NR    NP      NP
    175  *  FT_PIXEL_MODE_LCD     NP  NP  NR    NP      NP
    176  *  FT_PIXEL_MODE_LCD_V   NP  NP  NR    NP      NP
    177  *  FT_PIXEL_MODE_BGRA     N   N  NR     Y       N
    178  *
    179  *  TODO: All of these N need to be Y or otherwise ruled out.
    180  */
    181 void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) {
    182     SkASSERTF(dstMask.fBounds.width() == static_cast<int>(srcFTBitmap.width),
    183               "dstMask.fBounds.width() = %d\n"
    184               "static_cast<int>(srcFTBitmap.width) = %d",
    185               dstMask.fBounds.width(),
    186               static_cast<int>(srcFTBitmap.width)
    187     );
    188     SkASSERTF(dstMask.fBounds.height() == static_cast<int>(srcFTBitmap.rows),
    189               "dstMask.fBounds.height() = %d\n"
    190               "static_cast<int>(srcFTBitmap.rows) = %d",
    191               dstMask.fBounds.height(),
    192               static_cast<int>(srcFTBitmap.rows)
    193     );
    194 
    195     const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
    196     const FT_Pixel_Mode srcFormat = static_cast<FT_Pixel_Mode>(srcFTBitmap.pixel_mode);
    197     // FT_Bitmap::pitch is an int and allowed to be negative.
    198     const int srcPitch = srcFTBitmap.pitch;
    199     const size_t srcRowBytes = SkTAbs(srcPitch);
    200 
    201     uint8_t* dst = dstMask.fImage;
    202     const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat);
    203     const size_t dstRowBytes = dstMask.fRowBytes;
    204 
    205     const size_t width = srcFTBitmap.width;
    206     const size_t height = srcFTBitmap.rows;
    207 
    208     if (SkMask::kLCD16_Format == dstFormat) {
    209         copyFT2LCD16<false>(srcFTBitmap, dstMask, false, nullptr, nullptr, nullptr);
    210         return;
    211     }
    212 
    213     if ((FT_PIXEL_MODE_MONO == srcFormat && SkMask::kBW_Format == dstFormat) ||
    214         (FT_PIXEL_MODE_GRAY == srcFormat && SkMask::kA8_Format == dstFormat))
    215     {
    216         size_t commonRowBytes = SkTMin(srcRowBytes, dstRowBytes);
    217         for (size_t y = height; y --> 0;) {
    218             memcpy(dst, src, commonRowBytes);
    219             src += srcPitch;
    220             dst += dstRowBytes;
    221         }
    222     } else if (FT_PIXEL_MODE_MONO == srcFormat && SkMask::kA8_Format == dstFormat) {
    223         for (size_t y = height; y --> 0;) {
    224             uint8_t byte = 0;
    225             int bits = 0;
    226             const uint8_t* src_row = src;
    227             uint8_t* dst_row = dst;
    228             for (size_t x = width; x --> 0;) {
    229                 if (0 == bits) {
    230                     byte = *src_row++;
    231                     bits = 8;
    232                 }
    233                 *dst_row++ = byte & 0x80 ? 0xff : 0x00;
    234                 bits--;
    235                 byte <<= 1;
    236             }
    237             src += srcPitch;
    238             dst += dstRowBytes;
    239         }
    240     } else if (FT_PIXEL_MODE_BGRA == srcFormat && SkMask::kARGB32_Format == dstFormat) {
    241         // FT_PIXEL_MODE_BGRA is pre-multiplied.
    242         for (size_t y = height; y --> 0;) {
    243             const uint8_t* src_row = src;
    244             SkPMColor* dst_row = reinterpret_cast<SkPMColor*>(dst);
    245             for (size_t x = 0; x < width; ++x) {
    246                 uint8_t b = *src_row++;
    247                 uint8_t g = *src_row++;
    248                 uint8_t r = *src_row++;
    249                 uint8_t a = *src_row++;
    250                 *dst_row++ = SkPackARGB32(a, r, g, b);
    251 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
    252                 *(dst_row-1) = SkFourByteInterp256(*(dst_row-1), SK_ColorWHITE, 0x40);
    253 #endif
    254             }
    255             src += srcPitch;
    256             dst += dstRowBytes;
    257         }
    258     } else {
    259         SkDEBUGF(("FT_Pixel_Mode %d, SkMask::Format %d\n", srcFormat, dstFormat));
    260         SkDEBUGFAIL("unsupported combination of FT_Pixel_Mode and SkMask::Format");
    261     }
    262 }
    263 
    264 inline int convert_8_to_1(unsigned byte) {
    265     SkASSERT(byte <= 0xFF);
    266     // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better.
    267     return (byte >> 6) != 0;
    268 }
    269 
    270 uint8_t pack_8_to_1(const uint8_t alpha[8]) {
    271     unsigned bits = 0;
    272     for (int i = 0; i < 8; ++i) {
    273         bits <<= 1;
    274         bits |= convert_8_to_1(alpha[i]);
    275     }
    276     return SkToU8(bits);
    277 }
    278 
    279 void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
    280     const int height = mask.fBounds.height();
    281     const int width = mask.fBounds.width();
    282     const int octs = width >> 3;
    283     const int leftOverBits = width & 7;
    284 
    285     uint8_t* dst = mask.fImage;
    286     const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
    287     SkASSERT(dstPad >= 0);
    288 
    289     const int srcPad = srcRB - width;
    290     SkASSERT(srcPad >= 0);
    291 
    292     for (int y = 0; y < height; ++y) {
    293         for (int i = 0; i < octs; ++i) {
    294             *dst++ = pack_8_to_1(src);
    295             src += 8;
    296         }
    297         if (leftOverBits > 0) {
    298             unsigned bits = 0;
    299             int shift = 7;
    300             for (int i = 0; i < leftOverBits; ++i, --shift) {
    301                 bits |= convert_8_to_1(*src++) << shift;
    302             }
    303             *dst++ = bits;
    304         }
    305         src += srcPad;
    306         dst += dstPad;
    307     }
    308 }
    309 
    310 inline SkMask::Format SkMaskFormat_for_SkColorType(SkColorType colorType) {
    311     switch (colorType) {
    312         case kAlpha_8_SkColorType:
    313             return SkMask::kA8_Format;
    314         case kN32_SkColorType:
    315             return SkMask::kARGB32_Format;
    316         default:
    317             SkDEBUGFAIL("unsupported SkBitmap::Config");
    318             return SkMask::kA8_Format;
    319     }
    320 }
    321 
    322 inline SkColorType SkColorType_for_FTPixelMode(FT_Pixel_Mode pixel_mode) {
    323     switch (pixel_mode) {
    324         case FT_PIXEL_MODE_MONO:
    325         case FT_PIXEL_MODE_GRAY:
    326             return kAlpha_8_SkColorType;
    327         case FT_PIXEL_MODE_BGRA:
    328             return kN32_SkColorType;
    329         default:
    330             SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
    331             return kAlpha_8_SkColorType;
    332     }
    333 }
    334 
    335 inline SkColorType SkColorType_for_SkMaskFormat(SkMask::Format format) {
    336     switch (format) {
    337         case SkMask::kBW_Format:
    338         case SkMask::kA8_Format:
    339         case SkMask::kLCD16_Format:
    340             return kAlpha_8_SkColorType;
    341         case SkMask::kARGB32_Format:
    342             return kN32_SkColorType;
    343         default:
    344             SkDEBUGFAIL("unsupported destination SkBitmap::Config");
    345             return kAlpha_8_SkColorType;
    346     }
    347 }
    348 
    349 #ifdef SK_DEBUG
    350 
    351 #  define SK_STRING(X) SK_STRING_IMPL(X)
    352 #  define SK_STRING_IMPL(X) #X
    353 
    354 #  undef __FTERRORS_H__
    355 #  define FT_ERROR_START_LIST
    356 #  define FT_ERRORDEF(e, v, s)  { SK_STRING(e), s },
    357 #  define FT_ERROR_END_LIST
    358 
    359 const struct {
    360   const char* err_code;
    361   const char* err_msg;
    362 } sk_ft_errors[] = {
    363 #  include FT_ERRORS_H
    364 };
    365 
    366 void SkTraceFTR(const char* file, unsigned long line, FT_Error err, const char* msg) {
    367     SkString s;
    368     s.printf("%s:%lu:1: error: 0x%x ", file, line, err);
    369     if (0 <= err && (unsigned)err < SK_ARRAY_COUNT(sk_ft_errors)) {
    370         s.appendf("%s '%s' ", sk_ft_errors[err].err_code, sk_ft_errors[err].err_msg);
    371     } else {
    372         s.appendf("<unknown> ");
    373     }
    374     if (msg) {
    375         s.appendf("%s", msg);
    376     }
    377     SkDebugf("%s\n", s.c_str());
    378 }
    379 
    380 #  define SK_TRACEFTR(_err, _msg) SkTraceFTR(__FILE__, __LINE__, _err, _msg)
    381 #else
    382 #  define SK_TRACEFTR(_err, _msg) sk_ignore_unused_variable(_err)
    383 #endif
    384 
    385 }  // namespace
    386 
    387 void SkScalerContext_FreeType_Base::generateGlyphImage(
    388     FT_Face face,
    389     const SkGlyph& glyph,
    390     const SkMatrix& bitmapTransform)
    391 {
    392     const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
    393     const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
    394 
    395     switch ( face->glyph->format ) {
    396         case FT_GLYPH_FORMAT_OUTLINE: {
    397             FT_Outline* outline = &face->glyph->outline;
    398             FT_BBox     bbox;
    399             FT_Bitmap   target;
    400 
    401             int dx = 0, dy = 0;
    402             if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
    403                 dx = SkFixedToFDot6(glyph.getSubXFixed());
    404                 dy = SkFixedToFDot6(glyph.getSubYFixed());
    405                 // negate dy since freetype-y-goes-up and skia-y-goes-down
    406                 dy = -dy;
    407             }
    408             FT_Outline_Get_CBox(outline, &bbox);
    409             /*
    410                 what we really want to do for subpixel is
    411                     offset(dx, dy)
    412                     compute_bounds
    413                     offset(bbox & !63)
    414                 but that is two calls to offset, so we do the following, which
    415                 achieves the same thing with only one offset call.
    416             */
    417             FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
    418                                           dy - ((bbox.yMin + dy) & ~63));
    419 
    420             if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
    421                 FT_Error err = FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V :
    422                                                                      FT_RENDER_MODE_LCD);
    423                 if (err) {
    424                     SK_TRACEFTR(err, "Could not render glyph.");
    425                     sk_bzero(glyph.fImage, glyph.computeImageSize());
    426                     return;
    427                 }
    428                 SkMask mask;
    429                 glyph.toMask(&mask);
    430                 if (fPreBlend.isApplicable()) {
    431                     copyFT2LCD16<true>(face->glyph->bitmap, mask, doBGR,
    432                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
    433                 } else {
    434                     copyFT2LCD16<false>(face->glyph->bitmap, mask, doBGR,
    435                                         fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
    436                 }
    437             } else {
    438                 target.width = glyph.fWidth;
    439                 target.rows = glyph.fHeight;
    440                 target.pitch = glyph.rowBytes();
    441                 target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
    442                 target.pixel_mode = compute_pixel_mode( (SkMask::Format)fRec.fMaskFormat);
    443                 target.num_grays = 256;
    444 
    445                 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
    446                 FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
    447             }
    448         } break;
    449 
    450         case FT_GLYPH_FORMAT_BITMAP: {
    451             FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
    452             SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
    453 
    454             // Assume that the other formats do not exist.
    455             SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
    456                      FT_PIXEL_MODE_GRAY == pixel_mode ||
    457                      FT_PIXEL_MODE_BGRA == pixel_mode);
    458 
    459             // These are the only formats this ScalerContext should request.
    460             SkASSERT(SkMask::kBW_Format == maskFormat ||
    461                      SkMask::kA8_Format == maskFormat ||
    462                      SkMask::kARGB32_Format == maskFormat ||
    463                      SkMask::kLCD16_Format == maskFormat);
    464 
    465             // If no scaling needed, directly copy glyph bitmap.
    466             if (bitmapTransform.isIdentity()) {
    467                 SkMask dstMask;
    468                 glyph.toMask(&dstMask);
    469                 copyFTBitmap(face->glyph->bitmap, dstMask);
    470                 break;
    471             }
    472 
    473             // Otherwise, scale the bitmap.
    474 
    475             // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
    476             SkBitmap unscaledBitmap;
    477             // TODO: mark this as sRGB when the blits will be sRGB.
    478             unscaledBitmap.allocPixels(SkImageInfo::Make(face->glyph->bitmap.width,
    479                                                          face->glyph->bitmap.rows,
    480                                                          SkColorType_for_FTPixelMode(pixel_mode),
    481                                                          kPremul_SkAlphaType));
    482 
    483             SkMask unscaledBitmapAlias;
    484             unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels());
    485             unscaledBitmapAlias.fBounds.set(0, 0, unscaledBitmap.width(), unscaledBitmap.height());
    486             unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes();
    487             unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkColorType(unscaledBitmap.colorType());
    488             copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias);
    489 
    490             // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
    491             // BW requires an A8 target for resizing, which can then be down sampled.
    492             // LCD should use a 4x A8 target, which will then be down sampled.
    493             // For simplicity, LCD uses A8 and is replicated.
    494             int bitmapRowBytes = 0;
    495             if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
    496                 bitmapRowBytes = glyph.rowBytes();
    497             }
    498             SkBitmap dstBitmap;
    499             // TODO: mark this as sRGB when the blits will be sRGB.
    500             dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
    501                                                 SkColorType_for_SkMaskFormat(maskFormat),
    502                                                 kPremul_SkAlphaType),
    503                               bitmapRowBytes);
    504             if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
    505                 dstBitmap.allocPixels();
    506             } else {
    507                 dstBitmap.setPixels(glyph.fImage);
    508             }
    509 
    510             // Scale unscaledBitmap into dstBitmap.
    511             SkCanvas canvas(dstBitmap);
    512 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
    513             canvas.clear(0x33FF0000);
    514 #else
    515             canvas.clear(SK_ColorTRANSPARENT);
    516 #endif
    517             canvas.translate(-glyph.fLeft, -glyph.fTop);
    518             canvas.concat(bitmapTransform);
    519             canvas.translate(face->glyph->bitmap_left, -face->glyph->bitmap_top);
    520 
    521             SkPaint paint;
    522             paint.setFilterQuality(kMedium_SkFilterQuality);
    523             canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);
    524 
    525             // If the destination is BW or LCD, convert from A8.
    526             if (SkMask::kBW_Format == maskFormat) {
    527                 // Copy the A8 dstBitmap into the A1 glyph.fImage.
    528                 SkMask dstMask;
    529                 glyph.toMask(&dstMask);
    530                 packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
    531             } else if (SkMask::kLCD16_Format == maskFormat) {
    532                 // Copy the A8 dstBitmap into the LCD16 glyph.fImage.
    533                 uint8_t* src = dstBitmap.getAddr8(0, 0);
    534                 uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
    535                 for (int y = dstBitmap.height(); y --> 0;) {
    536                     for (int x = 0; x < dstBitmap.width(); ++x) {
    537                         dst[x] = grayToRGB16(src[x]);
    538                     }
    539                     dst = (uint16_t*)((char*)dst + glyph.rowBytes());
    540                     src += dstBitmap.rowBytes();
    541                 }
    542             }
    543 
    544         } break;
    545 
    546         default:
    547             SkDEBUGFAIL("unknown glyph format");
    548             memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
    549             return;
    550     }
    551 
    552 // We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
    553 // it is optional
    554 #if defined(SK_GAMMA_APPLY_TO_A8)
    555     if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
    556         uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
    557         unsigned rowBytes = glyph.rowBytes();
    558 
    559         for (int y = glyph.fHeight - 1; y >= 0; --y) {
    560             for (int x = glyph.fWidth - 1; x >= 0; --x) {
    561                 dst[x] = fPreBlend.fG[dst[x]];
    562             }
    563             dst += rowBytes;
    564         }
    565     }
    566 #endif
    567 }
    568 
    569 ///////////////////////////////////////////////////////////////////////////////
    570 
    571 namespace {
    572 
    573 int move_proc(const FT_Vector* pt, void* ctx) {
    574     SkPath* path = (SkPath*)ctx;
    575     path->close();  // to close the previous contour (if any)
    576     path->moveTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
    577     return 0;
    578 }
    579 
    580 int line_proc(const FT_Vector* pt, void* ctx) {
    581     SkPath* path = (SkPath*)ctx;
    582     path->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
    583     return 0;
    584 }
    585 
    586 int quad_proc(const FT_Vector* pt0, const FT_Vector* pt1,
    587                      void* ctx) {
    588     SkPath* path = (SkPath*)ctx;
    589     path->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
    590                  SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y));
    591     return 0;
    592 }
    593 
    594 int cubic_proc(const FT_Vector* pt0, const FT_Vector* pt1,
    595                       const FT_Vector* pt2, void* ctx) {
    596     SkPath* path = (SkPath*)ctx;
    597     path->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
    598                   SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y),
    599                   SkFDot6ToScalar(pt2->x), -SkFDot6ToScalar(pt2->y));
    600     return 0;
    601 }
    602 
    603 }  // namespace
    604 
    605 void SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face, SkPath* path) {
    606     FT_Outline_Funcs    funcs;
    607 
    608     funcs.move_to   = move_proc;
    609     funcs.line_to   = line_proc;
    610     funcs.conic_to  = quad_proc;
    611     funcs.cubic_to  = cubic_proc;
    612     funcs.shift     = 0;
    613     funcs.delta     = 0;
    614 
    615     FT_Error err = FT_Outline_Decompose(&face->glyph->outline, &funcs, path);
    616 
    617     if (err != 0) {
    618         path->reset();
    619         return;
    620     }
    621 
    622     path->close();
    623 }
    624