Home | History | Annotate | Download | only in ports
      1 
      2 /*
      3  * Copyright 2006 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #include "SkBitmap.h"
     11 #include "SkCanvas.h"
     12 #include "SkColorPriv.h"
     13 #include "SkDescriptor.h"
     14 #include "SkFDot6.h"
     15 #include "SkFontHost.h"
     16 #include "SkMask.h"
     17 #include "SkAdvancedTypefaceMetrics.h"
     18 #include "SkScalerContext.h"
     19 #include "SkStream.h"
     20 #include "SkString.h"
     21 #include "SkTemplates.h"
     22 #include "SkThread.h"
     23 
     24 #include <ft2build.h>
     25 #include FT_FREETYPE_H
     26 #include FT_OUTLINE_H
     27 #include FT_SIZES_H
     28 #include FT_TRUETYPE_TABLES_H
     29 #include FT_TYPE1_TABLES_H
     30 #include FT_BITMAP_H
     31 // In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
     32 #include FT_SYNTHESIS_H
     33 #include FT_XFREE86_H
     34 #ifdef FT_LCD_FILTER_H
     35 #include FT_LCD_FILTER_H
     36 #endif
     37 
     38 #ifdef   FT_ADVANCES_H
     39 #include FT_ADVANCES_H
     40 #endif
     41 
     42 #if 0
     43 // Also include the files by name for build tools which require this.
     44 #include <freetype/freetype.h>
     45 #include <freetype/ftoutln.h>
     46 #include <freetype/ftsizes.h>
     47 #include <freetype/tttables.h>
     48 #include <freetype/ftadvanc.h>
     49 #include <freetype/ftlcdfil.h>
     50 #include <freetype/ftbitmap.h>
     51 #include <freetype/ftsynth.h>
     52 #endif
     53 
     54 //#define ENABLE_GLYPH_SPEW     // for tracing calls
     55 //#define DUMP_STRIKE_CREATION
     56 
     57 //#define SK_GAMMA_APPLY_TO_A8
     58 
     59 #ifndef SK_GAMMA_CONTRAST
     60     #define SK_GAMMA_CONTRAST   0x66
     61 #endif
     62 #ifndef SK_GAMMA_EXPONENT
     63     #define SK_GAMMA_EXPONENT   2.2
     64 #endif
     65 
     66 #ifdef SK_DEBUG
     67     #define SkASSERT_CONTINUE(pred)                                                         \
     68         do {                                                                                \
     69             if (!(pred))                                                                    \
     70                 SkDebugf("file %s:%d: assert failed '" #pred "'\n", __FILE__, __LINE__);    \
     71         } while (false)
     72 #else
     73     #define SkASSERT_CONTINUE(pred)
     74 #endif
     75 
     76 using namespace skia_advanced_typeface_metrics_utils;
     77 
     78 static bool isLCD(const SkScalerContext::Rec& rec) {
     79     switch (rec.fMaskFormat) {
     80         case SkMask::kLCD16_Format:
     81         case SkMask::kLCD32_Format:
     82             return true;
     83         default:
     84             return false;
     85     }
     86 }
     87 
     88 //////////////////////////////////////////////////////////////////////////
     89 
     90 struct SkFaceRec;
     91 
     92 SK_DECLARE_STATIC_MUTEX(gFTMutex);
     93 static int          gFTCount;
     94 static FT_Library   gFTLibrary;
     95 static SkFaceRec*   gFaceRecHead;
     96 static bool         gLCDSupportValid;  // true iff |gLCDSupport| has been set.
     97 static bool         gLCDSupport;  // true iff LCD is supported by the runtime.
     98 static int          gLCDExtra;  // number of extra pixels for filtering.
     99 
    100 static const uint8_t* gGammaTables[2];
    101 
    102 /////////////////////////////////////////////////////////////////////////
    103 
    104 // See http://freetype.sourceforge.net/freetype2/docs/reference/ft2-bitmap_handling.html#FT_Bitmap_Embolden
    105 // This value was chosen by eyeballing the result in Firefox and trying to match it.
    106 static const FT_Pos kBitmapEmboldenStrength = 1 << 6;
    107 
    108 // convert from Skia's fixed (16.16) to FreeType's fixed (26.6) representation
    109 static inline int FixedToDot6(SkFixed x) { return x >> 10; }
    110 // convert from FreeType's fixed (26.6) to Skia's fixed (16.16) representation
    111 static inline SkFixed Dot6ToFixed(int x) { return x << 10; }
    112 
    113 static bool
    114 InitFreetype() {
    115     FT_Error err = FT_Init_FreeType(&gFTLibrary);
    116     if (err) {
    117         return false;
    118     }
    119 
    120     // Setup LCD filtering. This reduces colour fringes for LCD rendered
    121     // glyphs.
    122 #ifdef FT_LCD_FILTER_H
    123 //    err = FT_Library_SetLcdFilter(gFTLibrary, FT_LCD_FILTER_DEFAULT);
    124     err = FT_Library_SetLcdFilter(gFTLibrary, FT_LCD_FILTER_LIGHT);
    125     gLCDSupport = err == 0;
    126     if (gLCDSupport) {
    127         gLCDExtra = 2; //DEFAULT and LIGHT add one pixel to each side.
    128     }
    129 #else
    130     gLCDSupport = false;
    131 #endif
    132     gLCDSupportValid = true;
    133 
    134     return true;
    135 }
    136 
    137 class SkScalerContext_FreeType : public SkScalerContext {
    138 public:
    139     SkScalerContext_FreeType(const SkDescriptor* desc);
    140     virtual ~SkScalerContext_FreeType();
    141 
    142     bool success() const {
    143         return fFaceRec != NULL &&
    144                fFTSize != NULL &&
    145                fFace != NULL;
    146     }
    147 
    148 protected:
    149     virtual unsigned generateGlyphCount();
    150     virtual uint16_t generateCharToGlyph(SkUnichar uni);
    151     virtual void generateAdvance(SkGlyph* glyph);
    152     virtual void generateMetrics(SkGlyph* glyph);
    153     virtual void generateImage(const SkGlyph& glyph);
    154     virtual void generatePath(const SkGlyph& glyph, SkPath* path);
    155     virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
    156                                      SkPaint::FontMetrics* my);
    157     virtual SkUnichar generateGlyphToChar(uint16_t glyph);
    158 
    159 private:
    160     SkFaceRec*  fFaceRec;
    161     FT_Face     fFace;              // reference to shared face in gFaceRecHead
    162     FT_Size     fFTSize;            // our own copy
    163     SkFixed     fScaleX, fScaleY;
    164     FT_Matrix   fMatrix22;
    165     uint32_t    fLoadGlyphFlags;
    166     bool        fDoLinearMetrics;
    167 
    168     FT_Error setupSize();
    169     void emboldenOutline(FT_Outline* outline);
    170     void getBBoxForCurrentGlyph(SkGlyph* glyph, FT_BBox* bbox,
    171                                 bool snapToPixelBoundary = false);
    172     void updateGlyphIfLCD(SkGlyph* glyph);
    173 };
    174 
    175 ///////////////////////////////////////////////////////////////////////////
    176 ///////////////////////////////////////////////////////////////////////////
    177 
    178 #include "SkStream.h"
    179 
    180 struct SkFaceRec {
    181     SkFaceRec*      fNext;
    182     FT_Face         fFace;
    183     FT_StreamRec    fFTStream;
    184     SkStream*       fSkStream;
    185     uint32_t        fRefCnt;
    186     uint32_t        fFontID;
    187 
    188     // assumes ownership of the stream, will call unref() when its done
    189     SkFaceRec(SkStream* strm, uint32_t fontID);
    190     ~SkFaceRec() {
    191         fSkStream->unref();
    192     }
    193 };
    194 
    195 extern "C" {
    196     static unsigned long sk_stream_read(FT_Stream       stream,
    197                                         unsigned long   offset,
    198                                         unsigned char*  buffer,
    199                                         unsigned long   count ) {
    200         SkStream* str = (SkStream*)stream->descriptor.pointer;
    201 
    202         if (count) {
    203             if (!str->rewind()) {
    204                 return 0;
    205             } else {
    206                 unsigned long ret;
    207                 if (offset) {
    208                     ret = str->read(NULL, offset);
    209                     if (ret != offset) {
    210                         return 0;
    211                     }
    212                 }
    213                 ret = str->read(buffer, count);
    214                 if (ret != count) {
    215                     return 0;
    216                 }
    217                 count = ret;
    218             }
    219         }
    220         return count;
    221     }
    222 
    223     static void sk_stream_close( FT_Stream stream) {}
    224 }
    225 
    226 SkFaceRec::SkFaceRec(SkStream* strm, uint32_t fontID)
    227         : fSkStream(strm), fFontID(fontID) {
    228 //    SkDEBUGF(("SkFaceRec: opening %s (%p)\n", key.c_str(), strm));
    229 
    230     sk_bzero(&fFTStream, sizeof(fFTStream));
    231     fFTStream.size = fSkStream->getLength();
    232     fFTStream.descriptor.pointer = fSkStream;
    233     fFTStream.read  = sk_stream_read;
    234     fFTStream.close = sk_stream_close;
    235 }
    236 
    237 // Will return 0 on failure
    238 static SkFaceRec* ref_ft_face(uint32_t fontID) {
    239     SkFaceRec* rec = gFaceRecHead;
    240     while (rec) {
    241         if (rec->fFontID == fontID) {
    242             SkASSERT(rec->fFace);
    243             rec->fRefCnt += 1;
    244             return rec;
    245         }
    246         rec = rec->fNext;
    247     }
    248 
    249     SkStream* strm = SkFontHost::OpenStream(fontID);
    250     if (NULL == strm) {
    251         SkDEBUGF(("SkFontHost::OpenStream failed opening %x\n", fontID));
    252         return 0;
    253     }
    254 
    255     // this passes ownership of strm to the rec
    256     rec = SkNEW_ARGS(SkFaceRec, (strm, fontID));
    257 
    258     FT_Open_Args    args;
    259     memset(&args, 0, sizeof(args));
    260     const void* memoryBase = strm->getMemoryBase();
    261 
    262     if (NULL != memoryBase) {
    263 //printf("mmap(%s)\n", keyString.c_str());
    264         args.flags = FT_OPEN_MEMORY;
    265         args.memory_base = (const FT_Byte*)memoryBase;
    266         args.memory_size = strm->getLength();
    267     } else {
    268 //printf("fopen(%s)\n", keyString.c_str());
    269         args.flags = FT_OPEN_STREAM;
    270         args.stream = &rec->fFTStream;
    271     }
    272 
    273     int face_index;
    274     int length = SkFontHost::GetFileName(fontID, NULL, 0, &face_index);
    275     FT_Error err = FT_Open_Face(gFTLibrary, &args, length ? face_index : 0,
    276                                 &rec->fFace);
    277 
    278     if (err) {    // bad filename, try the default font
    279         fprintf(stderr, "ERROR: unable to open font '%x'\n", fontID);
    280         SkDELETE(rec);
    281         return 0;
    282     } else {
    283         SkASSERT(rec->fFace);
    284         //fprintf(stderr, "Opened font '%s'\n", filename.c_str());
    285         rec->fNext = gFaceRecHead;
    286         gFaceRecHead = rec;
    287         rec->fRefCnt = 1;
    288         return rec;
    289     }
    290 }
    291 
    292 static void unref_ft_face(FT_Face face) {
    293     SkFaceRec*  rec = gFaceRecHead;
    294     SkFaceRec*  prev = NULL;
    295     while (rec) {
    296         SkFaceRec* next = rec->fNext;
    297         if (rec->fFace == face) {
    298             if (--rec->fRefCnt == 0) {
    299                 if (prev) {
    300                     prev->fNext = next;
    301                 } else {
    302                     gFaceRecHead = next;
    303                 }
    304                 FT_Done_Face(face);
    305                 SkDELETE(rec);
    306             }
    307             return;
    308         }
    309         prev = rec;
    310         rec = next;
    311     }
    312     SkDEBUGFAIL("shouldn't get here, face not in list");
    313 }
    314 
    315 ///////////////////////////////////////////////////////////////////////////
    316 
    317 // Work around for old versions of freetype.
    318 static FT_Error getAdvances(FT_Face face, FT_UInt start, FT_UInt count,
    319                            FT_Int32 loadFlags, FT_Fixed* advances) {
    320 #ifdef FT_ADVANCES_H
    321     return FT_Get_Advances(face, start, count, loadFlags, advances);
    322 #else
    323     if (!face || start >= face->num_glyphs ||
    324             start + count > face->num_glyphs || loadFlags != FT_LOAD_NO_SCALE) {
    325         return 6;  // "Invalid argument."
    326     }
    327     if (count == 0)
    328         return 0;
    329 
    330     for (int i = 0; i < count; i++) {
    331         FT_Error err = FT_Load_Glyph(face, start + i, FT_LOAD_NO_SCALE);
    332         if (err)
    333             return err;
    334         advances[i] = face->glyph->advance.x;
    335     }
    336 
    337     return 0;
    338 #endif
    339 }
    340 
    341 static bool canEmbed(FT_Face face) {
    342 #ifdef FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING
    343     FT_UShort fsType = FT_Get_FSType_Flags(face);
    344     return (fsType & (FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING |
    345                       FT_FSTYPE_BITMAP_EMBEDDING_ONLY)) == 0;
    346 #else
    347     // No embedding is 0x2 and bitmap embedding only is 0x200.
    348     TT_OS2* os2_table;
    349     if ((os2_table = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2)) != NULL) {
    350         return (os2_table->fsType & 0x202) == 0;
    351     }
    352     return false;  // We tried, fail safe.
    353 #endif
    354 }
    355 
    356 static bool GetLetterCBox(FT_Face face, char letter, FT_BBox* bbox) {
    357     const FT_UInt glyph_id = FT_Get_Char_Index(face, letter);
    358     if (!glyph_id)
    359         return false;
    360     FT_Load_Glyph(face, glyph_id, FT_LOAD_NO_SCALE);
    361     FT_Outline_Get_CBox(&face->glyph->outline, bbox);
    362     return true;
    363 }
    364 
    365 static bool getWidthAdvance(FT_Face face, int gId, int16_t* data) {
    366     FT_Fixed advance = 0;
    367     if (getAdvances(face, gId, 1, FT_LOAD_NO_SCALE, &advance)) {
    368         return false;
    369     }
    370     SkASSERT(data);
    371     *data = advance;
    372     return true;
    373 }
    374 
    375 static void populate_glyph_to_unicode(FT_Face& face,
    376                                       SkTDArray<SkUnichar>* glyphToUnicode) {
    377     // Check and see if we have Unicode cmaps.
    378     for (int i = 0; i < face->num_charmaps; ++i) {
    379         // CMaps known to support Unicode:
    380         // Platform ID   Encoding ID   Name
    381         // -----------   -----------   -----------------------------------
    382         // 0             0,1           Apple Unicode
    383         // 0             3             Apple Unicode 2.0 (preferred)
    384         // 3             1             Microsoft Unicode UCS-2
    385         // 3             10            Microsoft Unicode UCS-4 (preferred)
    386         //
    387         // See Apple TrueType Reference Manual
    388         // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6cmap.html
    389         // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6name.html#ID
    390         // Microsoft OpenType Specification
    391         // http://www.microsoft.com/typography/otspec/cmap.htm
    392 
    393         FT_UShort platformId = face->charmaps[i]->platform_id;
    394         FT_UShort encodingId = face->charmaps[i]->encoding_id;
    395 
    396         if (platformId != 0 && platformId != 3) {
    397             continue;
    398         }
    399         if (platformId == 3 && encodingId != 1 && encodingId != 10) {
    400             continue;
    401         }
    402         bool preferredMap = ((platformId == 3 && encodingId == 10) ||
    403                              (platformId == 0 && encodingId == 3));
    404 
    405         FT_Set_Charmap(face, face->charmaps[i]);
    406         if (glyphToUnicode->isEmpty()) {
    407             glyphToUnicode->setCount(face->num_glyphs);
    408             memset(glyphToUnicode->begin(), 0,
    409                    sizeof(SkUnichar) * face->num_glyphs);
    410         }
    411 
    412         // Iterate through each cmap entry.
    413         FT_UInt glyphIndex;
    414         for (SkUnichar charCode = FT_Get_First_Char(face, &glyphIndex);
    415              glyphIndex != 0;
    416              charCode = FT_Get_Next_Char(face, charCode, &glyphIndex)) {
    417             if (charCode &&
    418                     ((*glyphToUnicode)[glyphIndex] == 0 || preferredMap)) {
    419                 (*glyphToUnicode)[glyphIndex] = charCode;
    420             }
    421         }
    422     }
    423 }
    424 
    425 // static
    426 SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
    427         uint32_t fontID,
    428         SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
    429         const uint32_t* glyphIDs,
    430         uint32_t glyphIDsCount) {
    431 #if defined(SK_BUILD_FOR_MAC)
    432     return NULL;
    433 #else
    434     SkAutoMutexAcquire ac(gFTMutex);
    435     FT_Library libInit = NULL;
    436     if (gFTCount == 0) {
    437         if (!InitFreetype())
    438             sk_throw();
    439         libInit = gFTLibrary;
    440     }
    441     SkAutoTCallIProc<struct FT_LibraryRec_, FT_Done_FreeType> ftLib(libInit);
    442     SkFaceRec* rec = ref_ft_face(fontID);
    443     if (NULL == rec)
    444         return NULL;
    445     FT_Face face = rec->fFace;
    446 
    447     SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
    448     info->fFontName.set(FT_Get_Postscript_Name(face));
    449     info->fMultiMaster = FT_HAS_MULTIPLE_MASTERS(face);
    450     info->fLastGlyphID = face->num_glyphs - 1;
    451     info->fEmSize = 1000;
    452 
    453     bool cid = false;
    454     const char* fontType = FT_Get_X11_Font_Format(face);
    455     if (strcmp(fontType, "Type 1") == 0) {
    456         info->fType = SkAdvancedTypefaceMetrics::kType1_Font;
    457     } else if (strcmp(fontType, "CID Type 1") == 0) {
    458         info->fType = SkAdvancedTypefaceMetrics::kType1CID_Font;
    459         cid = true;
    460     } else if (strcmp(fontType, "CFF") == 0) {
    461         info->fType = SkAdvancedTypefaceMetrics::kCFF_Font;
    462     } else if (strcmp(fontType, "TrueType") == 0) {
    463         info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
    464         cid = true;
    465         TT_Header* ttHeader;
    466         if ((ttHeader = (TT_Header*)FT_Get_Sfnt_Table(face,
    467                                                       ft_sfnt_head)) != NULL) {
    468             info->fEmSize = ttHeader->Units_Per_EM;
    469         }
    470     }
    471 
    472     info->fStyle = 0;
    473     if (FT_IS_FIXED_WIDTH(face))
    474         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
    475     if (face->style_flags & FT_STYLE_FLAG_ITALIC)
    476         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
    477     // We should set either Symbolic or Nonsymbolic; Nonsymbolic if the font's
    478     // character set is a subset of 'Adobe standard Latin.'
    479     info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style;
    480 
    481     PS_FontInfoRec ps_info;
    482     TT_Postscript* tt_info;
    483     if (FT_Get_PS_Font_Info(face, &ps_info) == 0) {
    484         info->fItalicAngle = ps_info.italic_angle;
    485     } else if ((tt_info =
    486                 (TT_Postscript*)FT_Get_Sfnt_Table(face,
    487                                                   ft_sfnt_post)) != NULL) {
    488         info->fItalicAngle = SkFixedToScalar(tt_info->italicAngle);
    489     } else {
    490         info->fItalicAngle = 0;
    491     }
    492 
    493     info->fAscent = face->ascender;
    494     info->fDescent = face->descender;
    495 
    496     // Figure out a good guess for StemV - Min width of i, I, !, 1.
    497     // This probably isn't very good with an italic font.
    498     int16_t min_width = SHRT_MAX;
    499     info->fStemV = 0;
    500     char stem_chars[] = {'i', 'I', '!', '1'};
    501     for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
    502         FT_BBox bbox;
    503         if (GetLetterCBox(face, stem_chars[i], &bbox)) {
    504             int16_t width = bbox.xMax - bbox.xMin;
    505             if (width > 0 && width < min_width) {
    506                 min_width = width;
    507                 info->fStemV = min_width;
    508             }
    509         }
    510     }
    511 
    512     TT_PCLT* pclt_info;
    513     TT_OS2* os2_table;
    514     if ((pclt_info = (TT_PCLT*)FT_Get_Sfnt_Table(face, ft_sfnt_pclt)) != NULL) {
    515         info->fCapHeight = pclt_info->CapHeight;
    516         uint8_t serif_style = pclt_info->SerifStyle & 0x3F;
    517         if (serif_style >= 2 && serif_style <= 6)
    518             info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
    519         else if (serif_style >= 9 && serif_style <= 12)
    520             info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
    521     } else if ((os2_table =
    522                 (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2)) != NULL) {
    523         info->fCapHeight = os2_table->sCapHeight;
    524     } else {
    525         // Figure out a good guess for CapHeight: average the height of M and X.
    526         FT_BBox m_bbox, x_bbox;
    527         bool got_m, got_x;
    528         got_m = GetLetterCBox(face, 'M', &m_bbox);
    529         got_x = GetLetterCBox(face, 'X', &x_bbox);
    530         if (got_m && got_x) {
    531             info->fCapHeight = (m_bbox.yMax - m_bbox.yMin + x_bbox.yMax -
    532                     x_bbox.yMin) / 2;
    533         } else if (got_m && !got_x) {
    534             info->fCapHeight = m_bbox.yMax - m_bbox.yMin;
    535         } else if (!got_m && got_x) {
    536             info->fCapHeight = x_bbox.yMax - x_bbox.yMin;
    537         }
    538     }
    539 
    540     info->fBBox = SkIRect::MakeLTRB(face->bbox.xMin, face->bbox.yMax,
    541                                     face->bbox.xMax, face->bbox.yMin);
    542 
    543     if (!canEmbed(face) || !FT_IS_SCALABLE(face) ||
    544             info->fType == SkAdvancedTypefaceMetrics::kOther_Font) {
    545         perGlyphInfo = SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo;
    546     }
    547 
    548     if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
    549         if (FT_IS_FIXED_WIDTH(face)) {
    550             appendRange(&info->fGlyphWidths, 0);
    551             int16_t advance = face->max_advance_width;
    552             info->fGlyphWidths->fAdvance.append(1, &advance);
    553             finishRange(info->fGlyphWidths.get(), 0,
    554                         SkAdvancedTypefaceMetrics::WidthRange::kDefault);
    555         } else if (!cid) {
    556             appendRange(&info->fGlyphWidths, 0);
    557             // So as to not blow out the stack, get advances in batches.
    558             for (int gID = 0; gID < face->num_glyphs; gID += 128) {
    559                 FT_Fixed advances[128];
    560                 int advanceCount = 128;
    561                 if (gID + advanceCount > face->num_glyphs)
    562                     advanceCount = face->num_glyphs - gID + 1;
    563                 getAdvances(face, gID, advanceCount, FT_LOAD_NO_SCALE,
    564                             advances);
    565                 for (int i = 0; i < advanceCount; i++) {
    566                     int16_t advance = advances[gID + i];
    567                     info->fGlyphWidths->fAdvance.append(1, &advance);
    568                 }
    569             }
    570             finishRange(info->fGlyphWidths.get(), face->num_glyphs - 1,
    571                         SkAdvancedTypefaceMetrics::WidthRange::kRange);
    572         } else {
    573             info->fGlyphWidths.reset(
    574                 getAdvanceData(face,
    575                                face->num_glyphs,
    576                                glyphIDs,
    577                                glyphIDsCount,
    578                                &getWidthAdvance));
    579         }
    580     }
    581 
    582     if (perGlyphInfo & SkAdvancedTypefaceMetrics::kVAdvance_PerGlyphInfo &&
    583             FT_HAS_VERTICAL(face)) {
    584         SkASSERT(false);  // Not implemented yet.
    585     }
    586 
    587     if (perGlyphInfo & SkAdvancedTypefaceMetrics::kGlyphNames_PerGlyphInfo &&
    588             info->fType == SkAdvancedTypefaceMetrics::kType1_Font) {
    589         // Postscript fonts may contain more than 255 glyphs, so we end up
    590         // using multiple font descriptions with a glyph ordering.  Record
    591         // the name of each glyph.
    592         info->fGlyphNames.reset(
    593                 new SkAutoTArray<SkString>(face->num_glyphs));
    594         for (int gID = 0; gID < face->num_glyphs; gID++) {
    595             char glyphName[128];  // PS limit for names is 127 bytes.
    596             FT_Get_Glyph_Name(face, gID, glyphName, 128);
    597             info->fGlyphNames->get()[gID].set(glyphName);
    598         }
    599     }
    600 
    601     if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo &&
    602            info->fType != SkAdvancedTypefaceMetrics::kType1_Font &&
    603            face->num_charmaps) {
    604         populate_glyph_to_unicode(face, &(info->fGlyphToUnicode));
    605     }
    606 
    607     if (!canEmbed(face))
    608         info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
    609 
    610     unref_ft_face(face);
    611     return info;
    612 #endif
    613 }
    614 
    615 ///////////////////////////////////////////////////////////////////////////
    616 
    617 #define BLACK_LUMINANCE_LIMIT   0x40
    618 #define WHITE_LUMINANCE_LIMIT   0xA0
    619 
    620 static bool bothZero(SkScalar a, SkScalar b) {
    621     return 0 == a && 0 == b;
    622 }
    623 
    624 // returns false if there is any non-90-rotation or skew
    625 static bool isAxisAligned(const SkScalerContext::Rec& rec) {
    626     return 0 == rec.fPreSkewX &&
    627            (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
    628             bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
    629 }
    630 
    631 void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
    632     if (!gLCDSupportValid) {
    633         InitFreetype();
    634         FT_Done_FreeType(gFTLibrary);
    635     }
    636 
    637     if (!gLCDSupport && isLCD(*rec)) {
    638         // If the runtime Freetype library doesn't support LCD mode, we disable
    639         // it here.
    640         rec->fMaskFormat = SkMask::kA8_Format;
    641     }
    642 
    643     SkPaint::Hinting h = rec->getHinting();
    644     if (SkPaint::kFull_Hinting == h && !isLCD(*rec)) {
    645         // collapse full->normal hinting if we're not doing LCD
    646         h = SkPaint::kNormal_Hinting;
    647     }
    648     if ((rec->fFlags & SkScalerContext::kSubpixelPositioning_Flag) || isLCD(*rec)) {
    649         if (SkPaint::kNo_Hinting != h) {
    650             h = SkPaint::kSlight_Hinting;
    651         }
    652     }
    653 
    654 #ifndef SK_IGNORE_ROTATED_FREETYPE_FIX
    655     // rotated text looks bad with hinting, so we disable it as needed
    656     if (!isAxisAligned(*rec)) {
    657         h = SkPaint::kNo_Hinting;
    658     }
    659 #endif
    660     rec->setHinting(h);
    661 
    662 #ifndef SK_USE_COLOR_LUMINANCE
    663     // for compatibility at the moment, discretize luminance to 3 settings
    664     // black, white, gray. This helps with fontcache utilization, since we
    665     // won't create multiple entries that in the end map to the same results.
    666     {
    667         unsigned lum = rec->getLuminanceByte();
    668         if (gGammaTables[0] || gGammaTables[1]) {
    669             if (lum <= BLACK_LUMINANCE_LIMIT) {
    670                 lum = 0;
    671             } else if (lum >= WHITE_LUMINANCE_LIMIT) {
    672                 lum = SkScalerContext::kLuminance_Max;
    673             } else {
    674                 lum = SkScalerContext::kLuminance_Max >> 1;
    675             }
    676         } else {
    677             lum = 0;    // no gamma correct, so use 0 since SkPaint uses that
    678                         // when measuring text w/o regard for luminance
    679         }
    680         rec->setLuminanceBits(lum);
    681     }
    682 #endif
    683 }
    684 
    685 #ifdef SK_BUILD_FOR_ANDROID
    686 uint32_t SkFontHost::GetUnitsPerEm(SkFontID fontID) {
    687     SkAutoMutexAcquire ac(gFTMutex);
    688     SkFaceRec *rec = ref_ft_face(fontID);
    689     uint16_t unitsPerEm = 0;
    690 
    691     if (rec != NULL && rec->fFace != NULL) {
    692         unitsPerEm = rec->fFace->units_per_EM;
    693         unref_ft_face(rec->fFace);
    694     }
    695 
    696     return (uint32_t)unitsPerEm;
    697 }
    698 #endif
    699 
    700 SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
    701         : SkScalerContext(desc) {
    702     SkAutoMutexAcquire  ac(gFTMutex);
    703 
    704     if (gFTCount == 0) {
    705         if (!InitFreetype()) {
    706             sk_throw();
    707         }
    708         SkFontHost::GetGammaTables(gGammaTables);
    709     }
    710     ++gFTCount;
    711 
    712     // load the font file
    713     fFTSize = NULL;
    714     fFace = NULL;
    715     fFaceRec = ref_ft_face(fRec.fFontID);
    716     if (NULL == fFaceRec) {
    717         return;
    718     }
    719     fFace = fFaceRec->fFace;
    720 
    721     // compute our factors from the record
    722 
    723     SkMatrix    m;
    724 
    725     fRec.getSingleMatrix(&m);
    726 
    727 #ifdef DUMP_STRIKE_CREATION
    728     SkString     keyString;
    729     SkFontHost::GetDescriptorKeyString(desc, &keyString);
    730     printf("========== strike [%g %g %g] [%g %g %g %g] hints %d format %d %s\n", SkScalarToFloat(fRec.fTextSize),
    731            SkScalarToFloat(fRec.fPreScaleX), SkScalarToFloat(fRec.fPreSkewX),
    732            SkScalarToFloat(fRec.fPost2x2[0][0]), SkScalarToFloat(fRec.fPost2x2[0][1]),
    733            SkScalarToFloat(fRec.fPost2x2[1][0]), SkScalarToFloat(fRec.fPost2x2[1][1]),
    734            fRec.getHinting(), fRec.fMaskFormat, keyString.c_str());
    735 #endif
    736 
    737     //  now compute our scale factors
    738     SkScalar    sx = m.getScaleX();
    739     SkScalar    sy = m.getScaleY();
    740 
    741     if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0) {
    742         // sort of give up on hinting
    743         sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(m.getSkewX()));
    744         sy = SkMaxScalar(SkScalarAbs(m.getSkewY()), SkScalarAbs(sy));
    745         sx = sy = SkScalarAve(sx, sy);
    746 
    747         SkScalar inv = SkScalarInvert(sx);
    748 
    749         // flip the skew elements to go from our Y-down system to FreeType's
    750         fMatrix22.xx = SkScalarToFixed(SkScalarMul(m.getScaleX(), inv));
    751         fMatrix22.xy = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv));
    752         fMatrix22.yx = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv));
    753         fMatrix22.yy = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv));
    754     } else {
    755         fMatrix22.xx = fMatrix22.yy = SK_Fixed1;
    756         fMatrix22.xy = fMatrix22.yx = 0;
    757     }
    758 
    759     fScaleX = SkScalarToFixed(sx);
    760     fScaleY = SkScalarToFixed(sy);
    761 
    762     // compute the flags we send to Load_Glyph
    763     {
    764         FT_Int32 loadFlags = FT_LOAD_DEFAULT;
    765         bool linearMetrics = false;
    766 
    767         if (SkMask::kBW_Format == fRec.fMaskFormat) {
    768             // See http://code.google.com/p/chromium/issues/detail?id=43252#c24
    769             loadFlags = FT_LOAD_TARGET_MONO;
    770             if (fRec.getHinting() == SkPaint::kNo_Hinting) {
    771                 loadFlags = FT_LOAD_NO_HINTING;
    772                 linearMetrics = true;
    773             }
    774         } else {
    775             switch (fRec.getHinting()) {
    776             case SkPaint::kNo_Hinting:
    777                 loadFlags = FT_LOAD_NO_HINTING;
    778                 linearMetrics = true;
    779                 break;
    780             case SkPaint::kSlight_Hinting:
    781                 loadFlags = FT_LOAD_TARGET_LIGHT;  // This implies FORCE_AUTOHINT
    782                 linearMetrics = true;
    783                 break;
    784             case SkPaint::kNormal_Hinting:
    785                 if (fRec.fFlags & SkScalerContext::kAutohinting_Flag)
    786                     loadFlags = FT_LOAD_FORCE_AUTOHINT;
    787                 else
    788                     loadFlags = FT_LOAD_NO_AUTOHINT;
    789                 break;
    790             case SkPaint::kFull_Hinting:
    791                 if (fRec.fFlags & SkScalerContext::kAutohinting_Flag) {
    792                     loadFlags = FT_LOAD_FORCE_AUTOHINT;
    793                     break;
    794                 }
    795                 loadFlags = FT_LOAD_TARGET_NORMAL;
    796                 if (isLCD(fRec)) {
    797                     if (fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag) {
    798                         loadFlags = FT_LOAD_TARGET_LCD_V;
    799                     } else {
    800                         loadFlags = FT_LOAD_TARGET_LCD;
    801                     }
    802                 }
    803                 break;
    804             default:
    805                 SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting());
    806                 break;
    807             }
    808         }
    809 
    810         if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) {
    811             loadFlags |= FT_LOAD_NO_BITMAP;
    812         }
    813 
    814         // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct
    815         // advances, as fontconfig and cairo do.
    816         // See http://code.google.com/p/skia/issues/detail?id=222.
    817         loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
    818 
    819         fLoadGlyphFlags = loadFlags;
    820         fDoLinearMetrics = linearMetrics;
    821     }
    822 
    823     // now create the FT_Size
    824 
    825     {
    826         FT_Error    err;
    827 
    828         err = FT_New_Size(fFace, &fFTSize);
    829         if (err != 0) {
    830             SkDEBUGF(("SkScalerContext_FreeType::FT_New_Size(%x): FT_Set_Char_Size(0x%x, 0x%x) returned 0x%x\n",
    831                         fFaceRec->fFontID, fScaleX, fScaleY, err));
    832             fFace = NULL;
    833             return;
    834         }
    835 
    836         err = FT_Activate_Size(fFTSize);
    837         if (err != 0) {
    838             SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
    839                         fFaceRec->fFontID, fScaleX, fScaleY, err));
    840             fFTSize = NULL;
    841         }
    842 
    843         err = FT_Set_Char_Size( fFace,
    844                                 SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY),
    845                                 72, 72);
    846         if (err != 0) {
    847             SkDEBUGF(("SkScalerContext_FreeType::FT_Set_Char_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
    848                         fFaceRec->fFontID, fScaleX, fScaleY, err));
    849             fFace = NULL;
    850             return;
    851         }
    852 
    853         FT_Set_Transform( fFace, &fMatrix22, NULL);
    854     }
    855 }
    856 
    857 SkScalerContext_FreeType::~SkScalerContext_FreeType() {
    858     if (fFTSize != NULL) {
    859         FT_Done_Size(fFTSize);
    860     }
    861 
    862     SkAutoMutexAcquire  ac(gFTMutex);
    863 
    864     if (fFace != NULL) {
    865         unref_ft_face(fFace);
    866     }
    867     if (--gFTCount == 0) {
    868 //        SkDEBUGF(("FT_Done_FreeType\n"));
    869         FT_Done_FreeType(gFTLibrary);
    870         SkDEBUGCODE(gFTLibrary = NULL;)
    871     }
    872 }
    873 
    874 /*  We call this before each use of the fFace, since we may be sharing
    875     this face with other context (at different sizes).
    876 */
    877 FT_Error SkScalerContext_FreeType::setupSize() {
    878     FT_Error    err = FT_Activate_Size(fFTSize);
    879 
    880     if (err != 0) {
    881         SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
    882                     fFaceRec->fFontID, fScaleX, fScaleY, err));
    883         fFTSize = NULL;
    884     } else {
    885         // seems we need to reset this every time (not sure why, but without it
    886         // I get random italics from some other fFTSize)
    887         FT_Set_Transform( fFace, &fMatrix22, NULL);
    888     }
    889     return err;
    890 }
    891 
    892 void SkScalerContext_FreeType::emboldenOutline(FT_Outline* outline) {
    893     FT_Pos strength;
    894     strength = FT_MulFix(fFace->units_per_EM, fFace->size->metrics.y_scale)
    895                / 24;
    896     FT_Outline_Embolden(outline, strength);
    897 }
    898 
    899 unsigned SkScalerContext_FreeType::generateGlyphCount() {
    900     return fFace->num_glyphs;
    901 }
    902 
    903 uint16_t SkScalerContext_FreeType::generateCharToGlyph(SkUnichar uni) {
    904     return SkToU16(FT_Get_Char_Index( fFace, uni ));
    905 }
    906 
    907 SkUnichar SkScalerContext_FreeType::generateGlyphToChar(uint16_t glyph) {
    908     // iterate through each cmap entry, looking for matching glyph indices
    909     FT_UInt glyphIndex;
    910     SkUnichar charCode = FT_Get_First_Char( fFace, &glyphIndex );
    911 
    912     while (glyphIndex != 0) {
    913         if (glyphIndex == glyph) {
    914             return charCode;
    915         }
    916         charCode = FT_Get_Next_Char( fFace, charCode, &glyphIndex );
    917     }
    918 
    919     return 0;
    920 }
    921 
    922 static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
    923     switch (format) {
    924         case SkMask::kBW_Format:
    925             return FT_PIXEL_MODE_MONO;
    926         case SkMask::kA8_Format:
    927         default:
    928             return FT_PIXEL_MODE_GRAY;
    929     }
    930 }
    931 
    932 void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) {
    933 #ifdef FT_ADVANCES_H
    934    /* unhinted and light hinted text have linearly scaled advances
    935     * which are very cheap to compute with some font formats...
    936     */
    937     if (fDoLinearMetrics) {
    938         SkAutoMutexAcquire  ac(gFTMutex);
    939 
    940         if (this->setupSize()) {
    941             glyph->zeroMetrics();
    942             return;
    943         }
    944 
    945         FT_Error    error;
    946         FT_Fixed    advance;
    947 
    948         error = FT_Get_Advance( fFace, glyph->getGlyphID(fBaseGlyphCount),
    949                                 fLoadGlyphFlags | FT_ADVANCE_FLAG_FAST_ONLY,
    950                                 &advance );
    951         if (0 == error) {
    952             glyph->fRsbDelta = 0;
    953             glyph->fLsbDelta = 0;
    954             glyph->fAdvanceX = advance;  // advance *2/3; //DEBUG
    955             glyph->fAdvanceY = 0;
    956             return;
    957         }
    958     }
    959 #endif /* FT_ADVANCES_H */
    960     /* otherwise, we need to load/hint the glyph, which is slower */
    961     this->generateMetrics(glyph);
    962     return;
    963 }
    964 
    965 void SkScalerContext_FreeType::getBBoxForCurrentGlyph(SkGlyph* glyph,
    966                                                       FT_BBox* bbox,
    967                                                       bool snapToPixelBoundary) {
    968 
    969     FT_Outline_Get_CBox(&fFace->glyph->outline, bbox);
    970 
    971     if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
    972         int dx = FixedToDot6(glyph->getSubXFixed());
    973         int dy = FixedToDot6(glyph->getSubYFixed());
    974         // negate dy since freetype-y-goes-up and skia-y-goes-down
    975         bbox->xMin += dx;
    976         bbox->yMin -= dy;
    977         bbox->xMax += dx;
    978         bbox->yMax -= dy;
    979     }
    980 
    981     // outset the box to integral boundaries
    982     if (snapToPixelBoundary) {
    983         bbox->xMin &= ~63;
    984         bbox->yMin &= ~63;
    985         bbox->xMax  = (bbox->xMax + 63) & ~63;
    986         bbox->yMax  = (bbox->yMax + 63) & ~63;
    987     }
    988 }
    989 
    990 void SkScalerContext_FreeType::updateGlyphIfLCD(SkGlyph* glyph) {
    991     if (isLCD(fRec)) {
    992         glyph->fWidth += gLCDExtra;
    993         glyph->fLeft -= gLCDExtra >> 1;
    994     }
    995 }
    996 
    997 void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
    998     SkAutoMutexAcquire  ac(gFTMutex);
    999 
   1000     glyph->fRsbDelta = 0;
   1001     glyph->fLsbDelta = 0;
   1002 
   1003     FT_Error    err;
   1004 
   1005     if (this->setupSize()) {
   1006         goto ERROR;
   1007     }
   1008 
   1009     err = FT_Load_Glyph( fFace, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags );
   1010     if (err != 0) {
   1011         SkDEBUGF(("SkScalerContext_FreeType::generateMetrics(%x): FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n",
   1012                     fFaceRec->fFontID, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags, err));
   1013     ERROR:
   1014         glyph->zeroMetrics();
   1015         return;
   1016     }
   1017 
   1018     SkFixed vLeft, vTop;
   1019 
   1020     switch ( fFace->glyph->format ) {
   1021       case FT_GLYPH_FORMAT_OUTLINE: {
   1022         FT_BBox bbox;
   1023 
   1024         if (0 == fFace->glyph->outline.n_contours) {
   1025             glyph->fWidth = 0;
   1026             glyph->fHeight = 0;
   1027             glyph->fTop = 0;
   1028             glyph->fLeft = 0;
   1029             break;
   1030         }
   1031 
   1032         if ((fRec.fFlags & kEmbolden_Flag) && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) {
   1033             emboldenOutline(&fFace->glyph->outline);
   1034         }
   1035 
   1036         getBBoxForCurrentGlyph(glyph, &bbox, true);
   1037 
   1038         glyph->fWidth   = SkToU16((bbox.xMax - bbox.xMin) >> 6);
   1039         glyph->fHeight  = SkToU16((bbox.yMax - bbox.yMin) >> 6);
   1040         glyph->fTop     = -SkToS16(bbox.yMax >> 6);
   1041         glyph->fLeft    = SkToS16(bbox.xMin >> 6);
   1042 
   1043         if ((fRec.fFlags & SkScalerContext::kVertical_Flag)) {
   1044             vLeft = Dot6ToFixed(bbox.xMin);
   1045             vTop = Dot6ToFixed(bbox.yMax);
   1046         }
   1047 
   1048         updateGlyphIfLCD(glyph);
   1049 
   1050         break;
   1051       }
   1052 
   1053       case FT_GLYPH_FORMAT_BITMAP:
   1054         if ((fRec.fFlags & kEmbolden_Flag) && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) {
   1055             FT_GlyphSlot_Own_Bitmap(fFace->glyph);
   1056             FT_Bitmap_Embolden(gFTLibrary, &fFace->glyph->bitmap, kBitmapEmboldenStrength, 0);
   1057         }
   1058         glyph->fWidth   = SkToU16(fFace->glyph->bitmap.width);
   1059         glyph->fHeight  = SkToU16(fFace->glyph->bitmap.rows);
   1060         glyph->fTop     = -SkToS16(fFace->glyph->bitmap_top);
   1061         glyph->fLeft    = SkToS16(fFace->glyph->bitmap_left);
   1062         break;
   1063 
   1064       default:
   1065         SkDEBUGFAIL("unknown glyph format");
   1066         goto ERROR;
   1067     }
   1068 
   1069     if ((fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) == 0) {
   1070         glyph->fAdvanceX = SkFDot6ToFixed(fFace->glyph->advance.x);
   1071         glyph->fAdvanceY = -SkFDot6ToFixed(fFace->glyph->advance.y);
   1072         if (fRec.fFlags & kDevKernText_Flag) {
   1073             glyph->fRsbDelta = SkToS8(fFace->glyph->rsb_delta);
   1074             glyph->fLsbDelta = SkToS8(fFace->glyph->lsb_delta);
   1075         }
   1076     } else {
   1077         glyph->fAdvanceX = SkFixedMul(fMatrix22.xx, fFace->glyph->linearHoriAdvance);
   1078         glyph->fAdvanceY = -SkFixedMul(fMatrix22.yx, fFace->glyph->linearHoriAdvance);
   1079     }
   1080 
   1081     if ((fRec.fFlags & SkScalerContext::kVertical_Flag)
   1082             && fFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
   1083 
   1084         //TODO: do we need to specially handle SubpixelPositioning and Kerning?
   1085 
   1086         FT_Matrix identityMatrix;
   1087         identityMatrix.xx = identityMatrix.yy = SK_Fixed1;
   1088         identityMatrix.xy = identityMatrix.yx = 0;
   1089 
   1090         // if the matrix is not the identity matrix then we need to re-load the
   1091         // glyph with the identity matrix to get the necessary bounding box
   1092         if (memcmp(&fMatrix22, &identityMatrix, sizeof(FT_Matrix)) != 0) {
   1093 
   1094             FT_Set_Transform(fFace, &identityMatrix, NULL);
   1095 
   1096             err = FT_Load_Glyph( fFace, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags );
   1097             if (err != 0) {
   1098                 SkDEBUGF(("SkScalerContext_FreeType::generateMetrics(%x): FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n",
   1099                             fFaceRec->fFontID, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags, err));
   1100                 goto ERROR;
   1101             }
   1102 
   1103             if ((fRec.fFlags & kEmbolden_Flag) && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) {
   1104                 emboldenOutline(&fFace->glyph->outline);
   1105             }
   1106         }
   1107 
   1108         // bounding box of the unskewed and unscaled glyph
   1109         FT_BBox bbox;
   1110         getBBoxForCurrentGlyph(glyph, &bbox);
   1111 
   1112         // compute the vertical gap above and below the glyph if the glyph were
   1113         // centered within the linearVertAdvance
   1114         SkFixed vGap = (fFace->glyph->linearVertAdvance - Dot6ToFixed(bbox.yMax - bbox.yMin)) / 2;
   1115 
   1116         // the origin point of the glyph when rendered vertically
   1117         FT_Vector vOrigin;
   1118         vOrigin.x = fFace->glyph->linearHoriAdvance / 2;
   1119         vOrigin.y = vGap + Dot6ToFixed(bbox.yMax);
   1120 
   1121         // transform the vertical origin based on the matrix of the actual glyph
   1122         FT_Vector_Transform(&vOrigin, &fMatrix22);
   1123 
   1124         // compute a new offset vector for the glyph by subtracting the vertical
   1125         // origin from the original horizontal offset vector
   1126         glyph->fLeft = SkFixedRoundToInt(vLeft - vOrigin.x);
   1127         glyph->fTop =  -SkFixedRoundToInt(vTop - vOrigin.y);
   1128 
   1129         updateGlyphIfLCD(glyph);
   1130 
   1131         // use the vertical advance values computed by freetype
   1132         glyph->fAdvanceX = -SkFixedMul(fMatrix22.xy, fFace->glyph->linearVertAdvance);
   1133         glyph->fAdvanceY = SkFixedMul(fMatrix22.yy, fFace->glyph->linearVertAdvance);
   1134     }
   1135 
   1136 
   1137 #ifdef ENABLE_GLYPH_SPEW
   1138     SkDEBUGF(("FT_Set_Char_Size(this:%p sx:%x sy:%x ", this, fScaleX, fScaleY));
   1139     SkDEBUGF(("Metrics(glyph:%d flags:0x%x) w:%d\n", glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags, glyph->fWidth));
   1140 #endif
   1141 }
   1142 
   1143 ///////////////////////////////////////////////////////////////////////////////
   1144 
   1145 static int apply_contrast(int srca, int contrast) {
   1146     return srca + (((255 - srca) * contrast * srca) / (255*255));
   1147 }
   1148 
   1149 static void build_power_table(uint8_t table[], float ee) {
   1150     for (int i = 0; i < 256; i++) {
   1151         float x = i / 255.f;
   1152         x = powf(x, ee);
   1153         int xx = SkScalarRoundToInt(SkFloatToScalar(x * 255));
   1154         table[i] = SkToU8(xx);
   1155     }
   1156 }
   1157 
   1158 static void build_gamma_table(uint8_t table[256], int src, int dst) {
   1159     static bool gInit;
   1160     static uint8_t powTable[256], invPowTable[256];
   1161     if (!gInit) {
   1162         const float g = SK_GAMMA_EXPONENT;
   1163         build_power_table(powTable, g);
   1164         build_power_table(invPowTable, 1/g);
   1165         gInit = true;
   1166     }
   1167 
   1168     const int linSrc = powTable[src];
   1169     const int linDst = powTable[dst];
   1170     // have our contrast value taper off to 0 as the src luminance becomes white
   1171     const int contrast = SK_GAMMA_CONTRAST * (255 - linSrc) / 255;
   1172 
   1173     for (int i = 0; i < 256; ++i) {
   1174         int srca = apply_contrast(i, contrast);
   1175         SkASSERT((unsigned)srca <= 255);
   1176         int dsta = 255 - srca;
   1177 
   1178         //Calculate the output we want.
   1179         int linOut = (linSrc * srca + dsta * linDst) / 255;
   1180         SkASSERT((unsigned)linOut <= 255);
   1181         int out = invPowTable[linOut];
   1182 
   1183         //Undo what the blit blend will do.
   1184         int result = ((255 * out) - (255 * dst)) / (src - dst);
   1185         SkASSERT((unsigned)result <= 255);
   1186 
   1187         table[i] = result;
   1188     }
   1189 }
   1190 
   1191 static const uint8_t* getGammaTable(U8CPU luminance) {
   1192     static uint8_t gGammaTables[4][256];
   1193     static bool gInited;
   1194     if (!gInited) {
   1195         build_gamma_table(gGammaTables[0], 0x00, 0xFF);
   1196         build_gamma_table(gGammaTables[1], 0x66, 0x99);
   1197         build_gamma_table(gGammaTables[2], 0x99, 0x66);
   1198         build_gamma_table(gGammaTables[3], 0xFF, 0x00);
   1199 
   1200         gInited = true;
   1201     }
   1202     SkASSERT(0 == (luminance >> 8));
   1203     return gGammaTables[luminance >> 6];
   1204 }
   1205 
   1206 #ifndef SK_USE_COLOR_LUMINANCE
   1207 static const uint8_t* getIdentityTable() {
   1208     static bool gOnce;
   1209     static uint8_t gIdentityTable[256];
   1210     if (!gOnce) {
   1211         for (int i = 0; i < 256; ++i) {
   1212             gIdentityTable[i] = i;
   1213         }
   1214         gOnce = true;
   1215     }
   1216     return gIdentityTable;
   1217 }
   1218 #endif
   1219 
   1220 static uint16_t packTriple(unsigned r, unsigned g, unsigned b) {
   1221     return SkPackRGB16(r >> 3, g >> 2, b >> 3);
   1222 }
   1223 
   1224 static uint16_t grayToRGB16(U8CPU gray) {
   1225     SkASSERT(gray <= 255);
   1226     return SkPackRGB16(gray >> 3, gray >> 2, gray >> 3);
   1227 }
   1228 
   1229 static int bittst(const uint8_t data[], int bitOffset) {
   1230     SkASSERT(bitOffset >= 0);
   1231     int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7);
   1232     return lowBit & 1;
   1233 }
   1234 
   1235 static void copyFT2LCD16(const SkGlyph& glyph, const FT_Bitmap& bitmap,
   1236                          int lcdIsBGR, const uint8_t* tableR,
   1237                          const uint8_t* tableG, const uint8_t* tableB) {
   1238     SkASSERT(glyph.fHeight == bitmap.rows);
   1239     uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
   1240     const size_t dstRB = glyph.rowBytes();
   1241     const int width = glyph.fWidth;
   1242     const uint8_t* src = bitmap.buffer;
   1243 
   1244     switch (bitmap.pixel_mode) {
   1245         case FT_PIXEL_MODE_MONO: {
   1246             for (int y = 0; y < glyph.fHeight; ++y) {
   1247                 for (int x = 0; x < width; ++x) {
   1248                     dst[x] = -bittst(src, x);
   1249                 }
   1250                 dst = (uint16_t*)((char*)dst + dstRB);
   1251                 src += bitmap.pitch;
   1252             }
   1253         } break;
   1254         case FT_PIXEL_MODE_GRAY: {
   1255             for (int y = 0; y < glyph.fHeight; ++y) {
   1256                 for (int x = 0; x < width; ++x) {
   1257                     dst[x] = grayToRGB16(src[x]);
   1258                 }
   1259                 dst = (uint16_t*)((char*)dst + dstRB);
   1260                 src += bitmap.pitch;
   1261             }
   1262         } break;
   1263         default: {
   1264             SkASSERT(glyph.fWidth * 3 == bitmap.width);
   1265             for (int y = 0; y < glyph.fHeight; y++) {
   1266                 const uint8_t* triple = src;
   1267                 if (lcdIsBGR) {
   1268                     for (int x = 0; x < width; x++) {
   1269                         dst[x] = packTriple(tableR[triple[2]],
   1270                                             tableG[triple[1]],
   1271                                             tableB[triple[0]]);
   1272                         triple += 3;
   1273                     }
   1274                 } else {
   1275                     for (int x = 0; x < width; x++) {
   1276                         dst[x] = packTriple(tableR[triple[0]],
   1277                                             tableG[triple[1]],
   1278                                             tableB[triple[2]]);
   1279                         triple += 3;
   1280                     }
   1281                 }
   1282                 src += bitmap.pitch;
   1283                 dst = (uint16_t*)((char*)dst + dstRB);
   1284             }
   1285         } break;
   1286     }
   1287 }
   1288 
   1289 void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
   1290     SkAutoMutexAcquire  ac(gFTMutex);
   1291 
   1292     FT_Error    err;
   1293 
   1294     if (this->setupSize()) {
   1295         goto ERROR;
   1296     }
   1297 
   1298     err = FT_Load_Glyph( fFace, glyph.getGlyphID(fBaseGlyphCount), fLoadGlyphFlags);
   1299     if (err != 0) {
   1300         SkDEBUGF(("SkScalerContext_FreeType::generateImage: FT_Load_Glyph(glyph:%d width:%d height:%d rb:%d flags:%d) returned 0x%x\n",
   1301                     glyph.getGlyphID(fBaseGlyphCount), glyph.fWidth, glyph.fHeight, glyph.rowBytes(), fLoadGlyphFlags, err));
   1302     ERROR:
   1303         memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
   1304         return;
   1305     }
   1306 
   1307 #ifdef SK_USE_COLOR_LUMINANCE
   1308     SkColor lumColor = fRec.getLuminanceColor();
   1309     const uint8_t* tableR = getGammaTable(SkColorGetR(lumColor));
   1310     const uint8_t* tableG = getGammaTable(SkColorGetG(lumColor));
   1311     const uint8_t* tableB = getGammaTable(SkColorGetB(lumColor));
   1312 #else
   1313     unsigned lum = fRec.getLuminanceByte();
   1314     const uint8_t* tableR;
   1315     const uint8_t* tableG;
   1316     const uint8_t* tableB;
   1317 
   1318     bool isWhite = lum >= WHITE_LUMINANCE_LIMIT;
   1319     bool isBlack = lum <= BLACK_LUMINANCE_LIMIT;
   1320     if ((gGammaTables[0] || gGammaTables[1]) && (isBlack || isWhite)) {
   1321         tableR = tableG = tableB = gGammaTables[isBlack ? 0 : 1];
   1322     } else {
   1323         tableR = tableG = tableB = getIdentityTable();
   1324     }
   1325 #endif
   1326 
   1327     switch ( fFace->glyph->format ) {
   1328         case FT_GLYPH_FORMAT_OUTLINE: {
   1329             FT_Outline* outline = &fFace->glyph->outline;
   1330             FT_BBox     bbox;
   1331             FT_Bitmap   target;
   1332 
   1333             if ((fRec.fFlags & kEmbolden_Flag) && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) {
   1334                 emboldenOutline(outline);
   1335             }
   1336 
   1337             int dx = 0, dy = 0;
   1338             if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
   1339                 dx = glyph.getSubXFixed() >> 10;
   1340                 dy = glyph.getSubYFixed() >> 10;
   1341                 // negate dy since freetype-y-goes-up and skia-y-goes-down
   1342                 dy = -dy;
   1343             }
   1344             FT_Outline_Get_CBox(outline, &bbox);
   1345             /*
   1346                 what we really want to do for subpixel is
   1347                     offset(dx, dy)
   1348                     compute_bounds
   1349                     offset(bbox & !63)
   1350                 but that is two calls to offset, so we do the following, which
   1351                 achieves the same thing with only one offset call.
   1352             */
   1353             FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
   1354                                           dy - ((bbox.yMin + dy) & ~63));
   1355 
   1356             if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
   1357                 FT_Render_Glyph(fFace->glyph, FT_RENDER_MODE_LCD);
   1358                 copyFT2LCD16(glyph, fFace->glyph->bitmap,
   1359                              fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag,
   1360                              tableR, tableG, tableB);
   1361             } else {
   1362                 target.width = glyph.fWidth;
   1363                 target.rows = glyph.fHeight;
   1364                 target.pitch = glyph.rowBytes();
   1365                 target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
   1366                 target.pixel_mode = compute_pixel_mode(
   1367                                                 (SkMask::Format)fRec.fMaskFormat);
   1368                 target.num_grays = 256;
   1369 
   1370                 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
   1371                 FT_Outline_Get_Bitmap(gFTLibrary, outline, &target);
   1372             }
   1373         } break;
   1374 
   1375         case FT_GLYPH_FORMAT_BITMAP: {
   1376             if ((fRec.fFlags & kEmbolden_Flag) && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) {
   1377                 FT_GlyphSlot_Own_Bitmap(fFace->glyph);
   1378                 FT_Bitmap_Embolden(gFTLibrary, &fFace->glyph->bitmap, kBitmapEmboldenStrength, 0);
   1379             }
   1380             SkASSERT_CONTINUE(glyph.fWidth == fFace->glyph->bitmap.width);
   1381             SkASSERT_CONTINUE(glyph.fHeight == fFace->glyph->bitmap.rows);
   1382             SkASSERT_CONTINUE(glyph.fTop == -fFace->glyph->bitmap_top);
   1383             SkASSERT_CONTINUE(glyph.fLeft == fFace->glyph->bitmap_left);
   1384 
   1385             const uint8_t*  src = (const uint8_t*)fFace->glyph->bitmap.buffer;
   1386             uint8_t*        dst = (uint8_t*)glyph.fImage;
   1387 
   1388             if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ||
   1389                 (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO &&
   1390                  glyph.fMaskFormat == SkMask::kBW_Format)) {
   1391                 unsigned    srcRowBytes = fFace->glyph->bitmap.pitch;
   1392                 unsigned    dstRowBytes = glyph.rowBytes();
   1393                 unsigned    minRowBytes = SkMin32(srcRowBytes, dstRowBytes);
   1394                 unsigned    extraRowBytes = dstRowBytes - minRowBytes;
   1395 
   1396                 for (int y = fFace->glyph->bitmap.rows - 1; y >= 0; --y) {
   1397                     memcpy(dst, src, minRowBytes);
   1398                     memset(dst + minRowBytes, 0, extraRowBytes);
   1399                     src += srcRowBytes;
   1400                     dst += dstRowBytes;
   1401                 }
   1402             } else if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO &&
   1403                        glyph.fMaskFormat == SkMask::kA8_Format) {
   1404                 for (int y = 0; y < fFace->glyph->bitmap.rows; ++y) {
   1405                     uint8_t byte = 0;
   1406                     int bits = 0;
   1407                     const uint8_t* src_row = src;
   1408                     uint8_t* dst_row = dst;
   1409 
   1410                     for (int x = 0; x < fFace->glyph->bitmap.width; ++x) {
   1411                         if (!bits) {
   1412                             byte = *src_row++;
   1413                             bits = 8;
   1414                         }
   1415 
   1416                         *dst_row++ = byte & 0x80 ? 0xff : 0;
   1417                         bits--;
   1418                         byte <<= 1;
   1419                     }
   1420 
   1421                     src += fFace->glyph->bitmap.pitch;
   1422                     dst += glyph.rowBytes();
   1423                 }
   1424             } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
   1425                 copyFT2LCD16(glyph, fFace->glyph->bitmap,
   1426                              fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag,
   1427                              tableR, tableG, tableB);
   1428             } else {
   1429                 SkDEBUGFAIL("unknown glyph bitmap transform needed");
   1430             }
   1431         } break;
   1432 
   1433     default:
   1434         SkDEBUGFAIL("unknown glyph format");
   1435         goto ERROR;
   1436     }
   1437 
   1438 // We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
   1439 // it is optional
   1440 #if defined(SK_GAMMA_APPLY_TO_A8) || !defined(SK_USE_COLOR_LUMINANCE)
   1441     if (SkMask::kA8_Format == glyph.fMaskFormat) {
   1442         SkASSERT(tableR == tableG && tableR == tableB);
   1443         const uint8_t* table = tableR;
   1444         uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
   1445         unsigned rowBytes = glyph.rowBytes();
   1446 
   1447         for (int y = glyph.fHeight - 1; y >= 0; --y) {
   1448             for (int x = glyph.fWidth - 1; x >= 0; --x) {
   1449                 dst[x] = table[dst[x]];
   1450             }
   1451             dst += rowBytes;
   1452         }
   1453     }
   1454 #endif
   1455 }
   1456 
   1457 ///////////////////////////////////////////////////////////////////////////////
   1458 
   1459 #define ft2sk(x)    SkFixedToScalar((x) << 10)
   1460 
   1461 #if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 2
   1462     #define CONST_PARAM const
   1463 #else   // older freetype doesn't use const here
   1464     #define CONST_PARAM
   1465 #endif
   1466 
   1467 static int move_proc(CONST_PARAM FT_Vector* pt, void* ctx) {
   1468     SkPath* path = (SkPath*)ctx;
   1469     path->close();  // to close the previous contour (if any)
   1470     path->moveTo(ft2sk(pt->x), -ft2sk(pt->y));
   1471     return 0;
   1472 }
   1473 
   1474 static int line_proc(CONST_PARAM FT_Vector* pt, void* ctx) {
   1475     SkPath* path = (SkPath*)ctx;
   1476     path->lineTo(ft2sk(pt->x), -ft2sk(pt->y));
   1477     return 0;
   1478 }
   1479 
   1480 static int quad_proc(CONST_PARAM FT_Vector* pt0, CONST_PARAM FT_Vector* pt1,
   1481                      void* ctx) {
   1482     SkPath* path = (SkPath*)ctx;
   1483     path->quadTo(ft2sk(pt0->x), -ft2sk(pt0->y), ft2sk(pt1->x), -ft2sk(pt1->y));
   1484     return 0;
   1485 }
   1486 
   1487 static int cubic_proc(CONST_PARAM FT_Vector* pt0, CONST_PARAM FT_Vector* pt1,
   1488                       CONST_PARAM FT_Vector* pt2, void* ctx) {
   1489     SkPath* path = (SkPath*)ctx;
   1490     path->cubicTo(ft2sk(pt0->x), -ft2sk(pt0->y), ft2sk(pt1->x),
   1491                   -ft2sk(pt1->y), ft2sk(pt2->x), -ft2sk(pt2->y));
   1492     return 0;
   1493 }
   1494 
   1495 void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph,
   1496                                             SkPath* path) {
   1497     SkAutoMutexAcquire  ac(gFTMutex);
   1498 
   1499     SkASSERT(&glyph && path);
   1500 
   1501     if (this->setupSize()) {
   1502         path->reset();
   1503         return;
   1504     }
   1505 
   1506     uint32_t flags = fLoadGlyphFlags;
   1507     flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
   1508     flags &= ~FT_LOAD_RENDER;   // don't scan convert (we just want the outline)
   1509 
   1510     FT_Error err = FT_Load_Glyph( fFace, glyph.getGlyphID(fBaseGlyphCount), flags);
   1511 
   1512     if (err != 0) {
   1513         SkDEBUGF(("SkScalerContext_FreeType::generatePath: FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n",
   1514                     glyph.getGlyphID(fBaseGlyphCount), flags, err));
   1515         path->reset();
   1516         return;
   1517     }
   1518 
   1519     if ((fRec.fFlags & kEmbolden_Flag) && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) {
   1520         emboldenOutline(&fFace->glyph->outline);
   1521     }
   1522 
   1523     FT_Outline_Funcs    funcs;
   1524 
   1525     funcs.move_to   = move_proc;
   1526     funcs.line_to   = line_proc;
   1527     funcs.conic_to  = quad_proc;
   1528     funcs.cubic_to  = cubic_proc;
   1529     funcs.shift     = 0;
   1530     funcs.delta     = 0;
   1531 
   1532     err = FT_Outline_Decompose(&fFace->glyph->outline, &funcs, path);
   1533 
   1534     if (err != 0) {
   1535         SkDEBUGF(("SkScalerContext_FreeType::generatePath: FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n",
   1536                     glyph.getGlyphID(fBaseGlyphCount), flags, err));
   1537         path->reset();
   1538         return;
   1539     }
   1540 
   1541     path->close();
   1542 }
   1543 
   1544 void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx,
   1545                                                    SkPaint::FontMetrics* my) {
   1546     if (NULL == mx && NULL == my) {
   1547         return;
   1548     }
   1549 
   1550     SkAutoMutexAcquire  ac(gFTMutex);
   1551 
   1552     if (this->setupSize()) {
   1553         ERROR:
   1554         if (mx) {
   1555             sk_bzero(mx, sizeof(SkPaint::FontMetrics));
   1556         }
   1557         if (my) {
   1558             sk_bzero(my, sizeof(SkPaint::FontMetrics));
   1559         }
   1560         return;
   1561     }
   1562 
   1563     FT_Face face = fFace;
   1564     int upem = face->units_per_EM;
   1565     if (upem <= 0) {
   1566         goto ERROR;
   1567     }
   1568 
   1569     SkPoint pts[6];
   1570     SkFixed ys[6];
   1571     SkFixed scaleY = fScaleY;
   1572     SkFixed mxy = fMatrix22.xy;
   1573     SkFixed myy = fMatrix22.yy;
   1574     SkScalar xmin = SkIntToScalar(face->bbox.xMin) / upem;
   1575     SkScalar xmax = SkIntToScalar(face->bbox.xMax) / upem;
   1576 
   1577     int leading = face->height - (face->ascender + -face->descender);
   1578     if (leading < 0) {
   1579         leading = 0;
   1580     }
   1581 
   1582     // Try to get the OS/2 table from the font. This contains the specific
   1583     // average font width metrics which Windows uses.
   1584     TT_OS2* os2 = (TT_OS2*) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
   1585 
   1586     ys[0] = -face->bbox.yMax;
   1587     ys[1] = -face->ascender;
   1588     ys[2] = -face->descender;
   1589     ys[3] = -face->bbox.yMin;
   1590     ys[4] = leading;
   1591     ys[5] = os2 ? os2->xAvgCharWidth : 0;
   1592 
   1593     SkScalar x_height;
   1594     if (os2 && os2->sxHeight) {
   1595         x_height = SkFixedToScalar(SkMulDiv(fScaleX, os2->sxHeight, upem));
   1596     } else {
   1597         const FT_UInt x_glyph = FT_Get_Char_Index(fFace, 'x');
   1598         if (x_glyph) {
   1599             FT_BBox bbox;
   1600             FT_Load_Glyph(fFace, x_glyph, fLoadGlyphFlags);
   1601             if ((fRec.fFlags & kEmbolden_Flag) && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) {
   1602                 emboldenOutline(&fFace->glyph->outline);
   1603             }
   1604             FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox);
   1605             x_height = SkFixedToScalar(SkFDot6ToFixed(bbox.yMax));
   1606         } else {
   1607             x_height = 0;
   1608         }
   1609     }
   1610 
   1611     // convert upem-y values into scalar points
   1612     for (int i = 0; i < 6; i++) {
   1613         SkFixed y = SkMulDiv(scaleY, ys[i], upem);
   1614         SkFixed x = SkFixedMul(mxy, y);
   1615         y = SkFixedMul(myy, y);
   1616         pts[i].set(SkFixedToScalar(x), SkFixedToScalar(y));
   1617     }
   1618 
   1619     if (mx) {
   1620         mx->fTop = pts[0].fX;
   1621         mx->fAscent = pts[1].fX;
   1622         mx->fDescent = pts[2].fX;
   1623         mx->fBottom = pts[3].fX;
   1624         mx->fLeading = pts[4].fX;
   1625         mx->fAvgCharWidth = pts[5].fX;
   1626         mx->fXMin = xmin;
   1627         mx->fXMax = xmax;
   1628         mx->fXHeight = x_height;
   1629     }
   1630     if (my) {
   1631         my->fTop = pts[0].fY;
   1632         my->fAscent = pts[1].fY;
   1633         my->fDescent = pts[2].fY;
   1634         my->fBottom = pts[3].fY;
   1635         my->fLeading = pts[4].fY;
   1636         my->fAvgCharWidth = pts[5].fY;
   1637         my->fXMin = xmin;
   1638         my->fXMax = xmax;
   1639         my->fXHeight = x_height;
   1640     }
   1641 }
   1642 
   1643 ////////////////////////////////////////////////////////////////////////
   1644 ////////////////////////////////////////////////////////////////////////
   1645 
   1646 SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
   1647     SkScalerContext_FreeType* c = SkNEW_ARGS(SkScalerContext_FreeType, (desc));
   1648     if (!c->success()) {
   1649         SkDELETE(c);
   1650         c = NULL;
   1651     }
   1652     return c;
   1653 }
   1654 
   1655 ///////////////////////////////////////////////////////////////////////////////
   1656 
   1657 /*  Export this so that other parts of our FonttHost port can make use of our
   1658     ability to extract the name+style from a stream, using FreeType's api.
   1659 */
   1660 bool find_name_and_attributes(SkStream* stream, SkString* name,
   1661                               SkTypeface::Style* style, bool* isFixedWidth) {
   1662     FT_Library  library;
   1663     if (FT_Init_FreeType(&library)) {
   1664         return false;
   1665     }
   1666 
   1667     FT_Open_Args    args;
   1668     memset(&args, 0, sizeof(args));
   1669 
   1670     const void* memoryBase = stream->getMemoryBase();
   1671     FT_StreamRec    streamRec;
   1672 
   1673     if (NULL != memoryBase) {
   1674         args.flags = FT_OPEN_MEMORY;
   1675         args.memory_base = (const FT_Byte*)memoryBase;
   1676         args.memory_size = stream->getLength();
   1677     } else {
   1678         memset(&streamRec, 0, sizeof(streamRec));
   1679         streamRec.size = stream->read(NULL, 0);
   1680         streamRec.descriptor.pointer = stream;
   1681         streamRec.read  = sk_stream_read;
   1682         streamRec.close = sk_stream_close;
   1683 
   1684         args.flags = FT_OPEN_STREAM;
   1685         args.stream = &streamRec;
   1686     }
   1687 
   1688     FT_Face face;
   1689     if (FT_Open_Face(library, &args, 0, &face)) {
   1690         FT_Done_FreeType(library);
   1691         return false;
   1692     }
   1693 
   1694     int tempStyle = SkTypeface::kNormal;
   1695     if (face->style_flags & FT_STYLE_FLAG_BOLD) {
   1696         tempStyle |= SkTypeface::kBold;
   1697     }
   1698     if (face->style_flags & FT_STYLE_FLAG_ITALIC) {
   1699         tempStyle |= SkTypeface::kItalic;
   1700     }
   1701 
   1702     if (name) {
   1703         name->set(face->family_name);
   1704     }
   1705     if (style) {
   1706         *style = (SkTypeface::Style) tempStyle;
   1707     }
   1708     if (isFixedWidth) {
   1709         *isFixedWidth = FT_IS_FIXED_WIDTH(face);
   1710     }
   1711 
   1712     FT_Done_Face(face);
   1713     FT_Done_FreeType(library);
   1714     return true;
   1715 }
   1716