LCOV - code coverage report
Current view: directory - gfx/skia/src/ports - SkFontHost_FreeType.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 731 2 0.3 %
Date: 2012-06-02 Functions: 46 2 4.3 %

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

Generated by: LCOV version 1.7