gfx/skia/trunk/src/ports/SkFontHost_mac.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rwxr-xr-x

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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  */
     9 #include <vector>
    10 #ifdef SK_BUILD_FOR_MAC
    11 #import <ApplicationServices/ApplicationServices.h>
    12 #endif
    14 #ifdef SK_BUILD_FOR_IOS
    15 #include <CoreText/CoreText.h>
    16 #include <CoreText/CTFontManager.h>
    17 #include <CoreGraphics/CoreGraphics.h>
    18 #include <CoreFoundation/CoreFoundation.h>
    19 #endif
    21 #include "SkFontHost.h"
    22 #include "SkCGUtils.h"
    23 #include "SkColorPriv.h"
    24 #include "SkDescriptor.h"
    25 #include "SkEndian.h"
    26 #include "SkFontDescriptor.h"
    27 #include "SkFloatingPoint.h"
    28 #include "SkGlyph.h"
    29 #include "SkMaskGamma.h"
    30 #include "SkSFNTHeader.h"
    31 #include "SkOTTable_glyf.h"
    32 #include "SkOTTable_head.h"
    33 #include "SkOTTable_hhea.h"
    34 #include "SkOTTable_loca.h"
    35 #include "SkOTUtils.h"
    36 #include "SkPaint.h"
    37 #include "SkPath.h"
    38 #include "SkString.h"
    39 #include "SkStream.h"
    40 #include "SkThread.h"
    41 #include "SkTypeface_mac.h"
    42 #include "SkUtils.h"
    43 #include "SkTypefaceCache.h"
    44 #include "SkFontMgr.h"
    45 #include "SkUtils.h"
    47 //#define HACK_COLORGLYPHS
    49 class SkScalerContext_Mac;
    51 // CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we
    52 // provide a wrapper here that will return an empty array if need be.
    53 static CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() {
    54 #ifdef SK_BUILD_FOR_IOS
    55     return CFArrayCreate(NULL, NULL, 0, NULL);
    56 #else
    57     return CTFontManagerCopyAvailableFontFamilyNames();
    58 #endif
    59 }
    62 // Being templated and taking const T* prevents calling
    63 // CFSafeRelease(autoCFRelease) through implicit conversion.
    64 template <typename T> static void CFSafeRelease(/*CFTypeRef*/const T* cfTypeRef) {
    65     if (cfTypeRef) {
    66         CFRelease(cfTypeRef);
    67     }
    68 }
    70 // Being templated and taking const T* prevents calling
    71 // CFSafeRetain(autoCFRelease) through implicit conversion.
    72 template <typename T> static void CFSafeRetain(/*CFTypeRef*/const T* cfTypeRef) {
    73     if (cfTypeRef) {
    74         CFRetain(cfTypeRef);
    75     }
    76 }
    78 /** Acts like a CFRef, but calls CFSafeRelease when it goes out of scope. */
    79 template<typename CFRef> class AutoCFRelease : private SkNoncopyable {
    80 public:
    81     explicit AutoCFRelease(CFRef cfRef = NULL) : fCFRef(cfRef) { }
    82     ~AutoCFRelease() { CFSafeRelease(fCFRef); }
    84     void reset(CFRef that = NULL) {
    85         CFSafeRetain(that);
    86         CFSafeRelease(fCFRef);
    87         fCFRef = that;
    88     }
    90     AutoCFRelease& operator =(CFRef that) {
    91         reset(that);
    92         return *this;
    93     }
    95     operator CFRef() const { return fCFRef; }
    96     CFRef get() const { return fCFRef; }
    98     CFRef* operator&() { SkASSERT(fCFRef == NULL); return &fCFRef; }
    99 private:
   100     CFRef fCFRef;
   101 };
   103 static CFStringRef make_CFString(const char str[]) {
   104     return CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
   105 }
   107 template<typename T> class AutoCGTable : SkNoncopyable {
   108 public:
   109     AutoCGTable(CGFontRef font)
   110     //Undocumented: the tag parameter in this call is expected in machine order and not BE order.
   111     : fCFData(CGFontCopyTableForTag(font, SkSetFourByteTag(T::TAG0, T::TAG1, T::TAG2, T::TAG3)))
   112     , fData(fCFData ? reinterpret_cast<const T*>(CFDataGetBytePtr(fCFData)) : NULL)
   113     { }
   115     const T* operator->() const { return fData; }
   117 private:
   118     AutoCFRelease<CFDataRef> fCFData;
   119 public:
   120     const T* fData;
   121 };
   123 // inline versions of these rect helpers
   125 static bool CGRectIsEmpty_inline(const CGRect& rect) {
   126     return rect.size.width <= 0 || rect.size.height <= 0;
   127 }
   129 static CGFloat CGRectGetMinX_inline(const CGRect& rect) {
   130     return rect.origin.x;
   131 }
   133 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) {
   134     return rect.origin.x + rect.size.width;
   135 }
   137 static CGFloat CGRectGetMinY_inline(const CGRect& rect) {
   138     return rect.origin.y;
   139 }
   141 static CGFloat CGRectGetMaxY_inline(const CGRect& rect) {
   142     return rect.origin.y + rect.size.height;
   143 }
   145 static CGFloat CGRectGetWidth_inline(const CGRect& rect) {
   146     return rect.size.width;
   147 }
   149 ///////////////////////////////////////////////////////////////////////////////
   151 static void sk_memset_rect32(uint32_t* ptr, uint32_t value,
   152                              int width, int height, size_t rowBytes) {
   153     SkASSERT(width);
   154     SkASSERT(width * sizeof(uint32_t) <= rowBytes);
   156     if (width >= 32) {
   157         while (height) {
   158             sk_memset32(ptr, value, width);
   159             ptr = (uint32_t*)((char*)ptr + rowBytes);
   160             height -= 1;
   161         }
   162         return;
   163     }
   165     rowBytes -= width * sizeof(uint32_t);
   167     if (width >= 8) {
   168         while (height) {
   169             int w = width;
   170             do {
   171                 *ptr++ = value; *ptr++ = value;
   172                 *ptr++ = value; *ptr++ = value;
   173                 *ptr++ = value; *ptr++ = value;
   174                 *ptr++ = value; *ptr++ = value;
   175                 w -= 8;
   176             } while (w >= 8);
   177             while (--w >= 0) {
   178                 *ptr++ = value;
   179             }
   180             ptr = (uint32_t*)((char*)ptr + rowBytes);
   181             height -= 1;
   182         }
   183     } else {
   184         while (height) {
   185             int w = width;
   186             do {
   187                 *ptr++ = value;
   188             } while (--w > 0);
   189             ptr = (uint32_t*)((char*)ptr + rowBytes);
   190             height -= 1;
   191         }
   192     }
   193 }
   195 #include <sys/utsname.h>
   197 typedef uint32_t CGRGBPixel;
   199 static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) {
   200     return pixel & 0xFF;
   201 }
   203 // The calls to support subpixel are present in 10.5, but are not included in
   204 // the 10.5 SDK. The needed calls have been extracted from the 10.6 SDK and are
   205 // included below. To verify that CGContextSetShouldSubpixelQuantizeFonts, for
   206 // instance, is present in the 10.5 CoreGraphics libary, use:
   207 //   cd /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/
   208 //   cd ApplicationServices.framework/Frameworks/CoreGraphics.framework/
   209 //   nm CoreGraphics | grep CGContextSetShouldSubpixelQuantizeFonts
   211 #if !defined(MAC_OS_X_VERSION_10_6) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6)
   212 CG_EXTERN void CGContextSetAllowsFontSmoothing(CGContextRef context, bool value);
   213 CG_EXTERN void CGContextSetAllowsFontSubpixelPositioning(CGContextRef context, bool value);
   214 CG_EXTERN void CGContextSetShouldSubpixelPositionFonts(CGContextRef context, bool value);
   215 CG_EXTERN void CGContextSetAllowsFontSubpixelQuantization(CGContextRef context, bool value);
   216 CG_EXTERN void CGContextSetShouldSubpixelQuantizeFonts(CGContextRef context, bool value);
   217 #endif
   219 static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
   221 // See Source/WebKit/chromium/base/mac/mac_util.mm DarwinMajorVersionInternal for original source.
   222 static int readVersion() {
   223     struct utsname info;
   224     if (uname(&info) != 0) {
   225         SkDebugf("uname failed\n");
   226         return 0;
   227     }
   228     if (strcmp(info.sysname, "Darwin") != 0) {
   229         SkDebugf("unexpected uname sysname %s\n", info.sysname);
   230         return 0;
   231     }
   232     char* dot = strchr(info.release, '.');
   233     if (!dot) {
   234         SkDebugf("expected dot in uname release %s\n", info.release);
   235         return 0;
   236     }
   237     int version = atoi(info.release);
   238     if (version == 0) {
   239         SkDebugf("could not parse uname release %s\n", info.release);
   240     }
   241     return version;
   242 }
   244 static int darwinVersion() {
   245     static int darwin_version = readVersion();
   246     return darwin_version;
   247 }
   249 static bool isSnowLeopard() {
   250     return darwinVersion() == 10;
   251 }
   253 static bool isLion() {
   254     return darwinVersion() == 11;
   255 }
   257 static bool isMountainLion() {
   258     return darwinVersion() == 12;
   259 }
   261 static bool isLCDFormat(unsigned format) {
   262     return SkMask::kLCD16_Format == format || SkMask::kLCD32_Format == format;
   263 }
   265 static CGFloat ScalarToCG(SkScalar scalar) {
   266     if (sizeof(CGFloat) == sizeof(float)) {
   267         return SkScalarToFloat(scalar);
   268     } else {
   269         SkASSERT(sizeof(CGFloat) == sizeof(double));
   270         return (CGFloat) SkScalarToDouble(scalar);
   271     }
   272 }
   274 static SkScalar CGToScalar(CGFloat cgFloat) {
   275     if (sizeof(CGFloat) == sizeof(float)) {
   276         return cgFloat;
   277     } else {
   278         SkASSERT(sizeof(CGFloat) == sizeof(double));
   279         return SkDoubleToScalar(cgFloat);
   280     }
   281 }
   283 static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix,
   284                                                    SkScalar sx = SK_Scalar1,
   285                                                    SkScalar sy = SK_Scalar1) {
   286     return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx),
   287                                  -ScalarToCG(matrix[SkMatrix::kMSkewY]  * sy),
   288                                  -ScalarToCG(matrix[SkMatrix::kMSkewX]  * sx),
   289                                   ScalarToCG(matrix[SkMatrix::kMScaleY] * sy),
   290                                   ScalarToCG(matrix[SkMatrix::kMTransX] * sx),
   291                                   ScalarToCG(matrix[SkMatrix::kMTransY] * sy));
   292 }
   294 ///////////////////////////////////////////////////////////////////////////////
   296 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
   297 #define BITMAP_INFO_GRAY (kCGImageAlphaNone)
   299 /**
   300  * There does not appear to be a publicly accessable API for determining if lcd
   301  * font smoothing will be applied if we request it. The main issue is that if
   302  * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0.
   303  */
   304 static bool supports_LCD() {
   305     static int gSupportsLCD = -1;
   306     if (gSupportsLCD >= 0) {
   307         return (bool) gSupportsLCD;
   308     }
   309     uint32_t rgb = 0;
   310     AutoCFRelease<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
   311     AutoCFRelease<CGContextRef> cgContext(CGBitmapContextCreate(&rgb, 1, 1, 8, 4,
   312                                                                 colorspace, BITMAP_INFO_RGB));
   313     CGContextSelectFont(cgContext, "Helvetica", 16, kCGEncodingMacRoman);
   314     CGContextSetShouldSmoothFonts(cgContext, true);
   315     CGContextSetShouldAntialias(cgContext, true);
   316     CGContextSetTextDrawingMode(cgContext, kCGTextFill);
   317     CGContextSetGrayFillColor(cgContext, 1, 1);
   318     CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1);
   319     uint32_t r = (rgb >> 16) & 0xFF;
   320     uint32_t g = (rgb >>  8) & 0xFF;
   321     uint32_t b = (rgb >>  0) & 0xFF;
   322     gSupportsLCD = (r != g || r != b);
   323     return (bool) gSupportsLCD;
   324 }
   326 class Offscreen {
   327 public:
   328     Offscreen();
   330     CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
   331                       CGGlyph glyphID, size_t* rowBytesPtr,
   332                       bool generateA8FromLCD);
   334 private:
   335     enum {
   336         kSize = 32 * 32 * sizeof(CGRGBPixel)
   337     };
   338     SkAutoSMalloc<kSize> fImageStorage;
   339     AutoCFRelease<CGColorSpaceRef> fRGBSpace;
   341     // cached state
   342     AutoCFRelease<CGContextRef> fCG;
   343     SkISize fSize;
   344     bool fDoAA;
   345     bool fDoLCD;
   347     static int RoundSize(int dimension) {
   348         return SkNextPow2(dimension);
   349     }
   350 };
   352 Offscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL),
   353                          fDoAA(false), fDoLCD(false) {
   354     fSize.set(0, 0);
   355 }
   357 ///////////////////////////////////////////////////////////////////////////////
   359 static SkTypeface::Style computeStyleBits(CTFontRef font, bool* isFixedPitch) {
   360     unsigned style = SkTypeface::kNormal;
   361     CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font);
   363     if (traits & kCTFontBoldTrait) {
   364         style |= SkTypeface::kBold;
   365     }
   366     if (traits & kCTFontItalicTrait) {
   367         style |= SkTypeface::kItalic;
   368     }
   369     if (isFixedPitch) {
   370         *isFixedPitch = (traits & kCTFontMonoSpaceTrait) != 0;
   371     }
   372     return (SkTypeface::Style)style;
   373 }
   375 static SkFontID CTFontRef_to_SkFontID(CTFontRef fontRef) {
   376     SkFontID id = 0;
   377 // CTFontGetPlatformFont and ATSFontRef are not supported on iOS, so we have to
   378 // bracket this to be Mac only.
   379 #ifdef SK_BUILD_FOR_MAC
   380     ATSFontRef ats = CTFontGetPlatformFont(fontRef, NULL);
   381     id = (SkFontID)ats;
   382     if (id != 0) {
   383         id &= 0x3FFFFFFF; // make top two bits 00
   384         return id;
   385     }
   386 #endif
   387     // CTFontGetPlatformFont returns NULL if the font is local
   388     // (e.g., was created by a CSS3 @font-face rule).
   389     AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fontRef, NULL));
   390     AutoCGTable<SkOTTableHead> headTable(cgFont);
   391     if (headTable.fData) {
   392         id = (SkFontID) headTable->checksumAdjustment;
   393         id = (id & 0x3FFFFFFF) | 0x40000000; // make top two bits 01
   394     }
   395     // well-formed fonts have checksums, but as a last resort, use the pointer.
   396     if (id == 0) {
   397         id = (SkFontID) (uintptr_t) fontRef;
   398         id = (id & 0x3FFFFFFF) | 0x80000000; // make top two bits 10
   399     }
   400     return id;
   401 }
   403 static SkFontStyle stylebits2fontstyle(SkTypeface::Style styleBits) {
   404     return SkFontStyle((styleBits & SkTypeface::kBold)
   405                            ? SkFontStyle::kBold_Weight
   406                            : SkFontStyle::kNormal_Weight,
   407                        SkFontStyle::kNormal_Width,
   408                        (styleBits & SkTypeface::kItalic)
   409                            ? SkFontStyle::kItalic_Slant
   410                            : SkFontStyle::kUpright_Slant);
   411 }
   413 #define WEIGHT_THRESHOLD    ((SkFontStyle::kNormal_Weight + SkFontStyle::kBold_Weight)/2)
   415 static SkTypeface::Style fontstyle2stylebits(const SkFontStyle& fs) {
   416     unsigned style = 0;
   417     if (fs.width() >= WEIGHT_THRESHOLD) {
   418         style |= SkTypeface::kBold;
   419     }
   420     if (fs.isItalic()) {
   421         style |= SkTypeface::kItalic;
   422     }
   423     return (SkTypeface::Style)style;
   424 }
   426 class SkTypeface_Mac : public SkTypeface {
   427 public:
   428     SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isFixedPitch,
   429                    CTFontRef fontRef, const char name[])
   430         : SkTypeface(style, fontID, isFixedPitch)
   431         , fName(name)
   432         , fFontRef(fontRef) // caller has already called CFRetain for us
   433         , fFontStyle(stylebits2fontstyle(style))
   434     {
   435         SkASSERT(fontRef);
   436     }
   438     SkTypeface_Mac(const SkFontStyle& fs, SkFontID fontID, bool isFixedPitch,
   439                    CTFontRef fontRef, const char name[])
   440         : SkTypeface(fontstyle2stylebits(fs), fontID, isFixedPitch)
   441         , fName(name)
   442         , fFontRef(fontRef) // caller has already called CFRetain for us
   443         , fFontStyle(fs)
   444     {
   445         SkASSERT(fontRef);
   446     }
   448     SkString fName;
   449     AutoCFRelease<CTFontRef> fFontRef;
   450     SkFontStyle fFontStyle;
   452 protected:
   453     friend class SkFontHost;    // to access our protected members for deprecated methods
   455     virtual int onGetUPEM() const SK_OVERRIDE;
   456     virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
   457     virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
   458     virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
   459     virtual size_t onGetTableData(SkFontTableTag, size_t offset,
   460                                   size_t length, void* data) const SK_OVERRIDE;
   461     virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
   462     virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
   463     virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
   464     virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
   465                                 SkAdvancedTypefaceMetrics::PerGlyphInfo,
   466                                 const uint32_t*, uint32_t) const SK_OVERRIDE;
   467     virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[],
   468                                 int glyphCount) const SK_OVERRIDE;
   469     virtual int onCountGlyphs() const SK_OVERRIDE;
   471 private:
   473     typedef SkTypeface INHERITED;
   474 };
   476 static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) {
   477     SkASSERT(fontRef);
   478     bool isFixedPitch;
   479     SkTypeface::Style style = computeStyleBits(fontRef, &isFixedPitch);
   480     SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
   482     return new SkTypeface_Mac(style, fontID, isFixedPitch, fontRef, name);
   483 }
   485 static SkTypeface* NewFromName(const char familyName[], SkTypeface::Style theStyle) {
   486     CTFontRef ctFont = NULL;
   488     CTFontSymbolicTraits ctFontTraits = 0;
   489     if (theStyle & SkTypeface::kBold) {
   490         ctFontTraits |= kCTFontBoldTrait;
   491     }
   492     if (theStyle & SkTypeface::kItalic) {
   493         ctFontTraits |= kCTFontItalicTrait;
   494     }
   496     // Create the font info
   497     AutoCFRelease<CFStringRef> cfFontName(make_CFString(familyName));
   499     AutoCFRelease<CFNumberRef> cfFontTraits(
   500             CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits));
   502     AutoCFRelease<CFMutableDictionaryRef> cfAttributes(
   503             CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
   504                                       &kCFTypeDictionaryKeyCallBacks,
   505                                       &kCFTypeDictionaryValueCallBacks));
   507     AutoCFRelease<CFMutableDictionaryRef> cfTraits(
   508             CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
   509                                       &kCFTypeDictionaryKeyCallBacks,
   510                                       &kCFTypeDictionaryValueCallBacks));
   512     // Create the font
   513     if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) {
   514         CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits);
   516         CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName);
   517         CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits);
   519         AutoCFRelease<CTFontDescriptorRef> ctFontDesc(
   520                 CTFontDescriptorCreateWithAttributes(cfAttributes));
   522         if (ctFontDesc != NULL) {
   523             ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL);
   524         }
   525     }
   527     return ctFont ? NewFromFontRef(ctFont, familyName) : NULL;
   528 }
   530 static SkTypeface* GetDefaultFace() {
   531     SK_DECLARE_STATIC_MUTEX(gMutex);
   532     SkAutoMutexAcquire ma(gMutex);
   534     static SkTypeface* gDefaultFace;
   536     if (NULL == gDefaultFace) {
   537         gDefaultFace = NewFromName(FONT_DEFAULT_NAME, SkTypeface::kNormal);
   538         SkTypefaceCache::Add(gDefaultFace, SkTypeface::kNormal);
   539     }
   540     return gDefaultFace;
   541 }
   543 ///////////////////////////////////////////////////////////////////////////////
   545 extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face);
   546 CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) {
   547     const SkTypeface_Mac* macface = (const SkTypeface_Mac*)face;
   548     return macface ? macface->fFontRef.get() : NULL;
   549 }
   551 /*  This function is visible on the outside. It first searches the cache, and if
   552  *  not found, returns a new entry (after adding it to the cache).
   553  */
   554 SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) {
   555     SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
   556     SkTypeface* face = SkTypefaceCache::FindByID(fontID);
   557     if (face) {
   558         face->ref();
   559     } else {
   560         face = NewFromFontRef(fontRef, NULL);
   561         SkTypefaceCache::Add(face, face->style());
   562         // NewFromFontRef doesn't retain the parameter, but the typeface it
   563         // creates does release it in its destructor, so we balance that with
   564         // a retain call here.
   565         CFRetain(fontRef);
   566     }
   567     SkASSERT(face->getRefCnt() > 1);
   568     return face;
   569 }
   571 struct NameStyleRec {
   572     const char*         fName;
   573     SkTypeface::Style   fStyle;
   574 };
   576 static bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style,
   577                             void* ctx) {
   578     const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
   579     const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx);
   581     return rec->fStyle == style && mface->fName.equals(rec->fName);
   582 }
   584 static const char* map_css_names(const char* name) {
   585     static const struct {
   586         const char* fFrom;  // name the caller specified
   587         const char* fTo;    // "canonical" name we map to
   588     } gPairs[] = {
   589         { "sans-serif", "Helvetica" },
   590         { "serif",      "Times"     },
   591         { "monospace",  "Courier"   }
   592     };
   594     for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
   595         if (strcmp(name, gPairs[i].fFrom) == 0) {
   596             return gPairs[i].fTo;
   597         }
   598     }
   599     return name;    // no change
   600 }
   602 static SkTypeface* create_typeface(const SkTypeface* familyFace,
   603                                    const char familyName[],
   604                                    SkTypeface::Style style) {
   605     if (familyName) {
   606         familyName = map_css_names(familyName);
   607     }
   609     // Clone an existing typeface
   610     // TODO: only clone if style matches the familyFace's style...
   611     if (familyName == NULL && familyFace != NULL) {
   612         familyFace->ref();
   613         return const_cast<SkTypeface*>(familyFace);
   614     }
   616     if (!familyName || !*familyName) {
   617         familyName = FONT_DEFAULT_NAME;
   618     }
   620     NameStyleRec rec = { familyName, style };
   621     SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByNameStyle, &rec);
   623     if (NULL == face) {
   624         face = NewFromName(familyName, style);
   625         if (face) {
   626             SkTypefaceCache::Add(face, style);
   627         } else {
   628             face = GetDefaultFace();
   629             face->ref();
   630         }
   631     }
   632     return face;
   633 }
   635 ///////////////////////////////////////////////////////////////////////////////
   637 /** GlyphRect is in FUnits (em space, y up). */
   638 struct GlyphRect {
   639     int16_t fMinX;
   640     int16_t fMinY;
   641     int16_t fMaxX;
   642     int16_t fMaxY;
   643 };
   645 class SkScalerContext_Mac : public SkScalerContext {
   646 public:
   647     SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*);
   649 protected:
   650     unsigned generateGlyphCount(void) SK_OVERRIDE;
   651     uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
   652     void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
   653     void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
   654     void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
   655     void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
   656     void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE;
   658 private:
   659     static void CTPathElement(void *info, const CGPathElement *element);
   661     /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */
   662     void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const;
   664     /** Initializes and returns the value of fFBoundingBoxesGlyphOffset.
   665      *
   666      *  For use with (and must be called before) generateBBoxes.
   667      */
   668     uint16_t getFBoundingBoxesGlyphOffset();
   670     /** Initializes fFBoundingBoxes and returns true on success.
   671      *
   672      *  On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
   673      *  return a bad value in bounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
   674      *  less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
   675      *  font directly.
   676      *
   677      *  This routine initializes fFBoundingBoxes to an array of
   678      *  fGlyphCount - fFBoundingBoxesGlyphOffset GlyphRects which contain the bounds in FUnits
   679      *  (em space, y up) of glyphs with ids in the range [fFBoundingBoxesGlyphOffset, fGlyphCount).
   680      *
   681      *  Returns true if fFBoundingBoxes is properly initialized. The table can only be properly
   682      *  initialized for a TrueType font with 'head', 'loca', and 'glyf' tables.
   683      *
   684      *  TODO: A future optimization will compute fFBoundingBoxes once per fCTFont.
   685      */
   686     bool generateBBoxes();
   688     /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down).
   689      *
   690      *  Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs.
   691      *  Used on Lion to correct CTFontGetBoundingRectsForGlyphs.
   692      */
   693     SkMatrix fFUnitMatrix;
   695     Offscreen fOffscreen;
   696     AutoCFRelease<CTFontRef> fCTFont;
   698     /** Vertical variant of fCTFont.
   699      *
   700      *  CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise.
   701      *  This makes kCTFontDefaultOrientation dangerous, because the metrics from
   702      *  kCTFontHorizontalOrientation are in a different space from kCTFontVerticalOrientation.
   703      *  Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in the same space.
   704      */
   705     AutoCFRelease<CTFontRef> fCTVerticalFont;
   707     AutoCFRelease<CGFontRef> fCGFont;
   708     SkAutoTMalloc<GlyphRect> fFBoundingBoxes;
   709     uint16_t fFBoundingBoxesGlyphOffset;
   710     uint16_t fGlyphCount;
   711     bool fGeneratedFBoundingBoxes;
   712     const bool fDoSubPosition;
   713     const bool fVertical;
   715     friend class Offscreen;
   717     typedef SkScalerContext INHERITED;
   718 };
   720 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
   721                                          const SkDescriptor* desc)
   722         : INHERITED(typeface, desc)
   723         , fFBoundingBoxes()
   724         , fFBoundingBoxesGlyphOffset(0)
   725         , fGeneratedFBoundingBoxes(false)
   726         , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
   727         , fVertical(SkToBool(fRec.fFlags & kVertical_Flag))
   729 {
   730     CTFontRef ctFont = typeface->fFontRef.get();
   731     CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
   732     SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
   733     fGlyphCount = SkToU16(numGlyphs);
   735     fRec.getSingleMatrix(&fFUnitMatrix);
   736     CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix);
   738     AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
   739     if (fVertical) {
   740         AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMutable(
   741                 kCFAllocatorDefault, 0,
   742                 &kCFTypeDictionaryKeyCallBacks,
   743                 &kCFTypeDictionaryValueCallBacks));
   744         if (cfAttributes) {
   745             CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
   746             AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate(
   747                     kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation));
   748             CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVertical);
   749             ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
   750         }
   751     }
   752     // Since our matrix includes everything, we pass 1 for size.
   753     fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, ctFontDesc);
   754     fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL);
   755     if (fVertical) {
   756         CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
   757         transform = CGAffineTransformConcat(rotateLeft, transform);
   758         fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, NULL);
   759     }
   761     SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFont)));
   762     fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit);
   763 }
   765 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
   766                              CGGlyph glyphID, size_t* rowBytesPtr,
   767                              bool generateA8FromLCD) {
   768     if (!fRGBSpace) {
   769         //It doesn't appear to matter what color space is specified.
   770         //Regular blends and antialiased text are always (s*a + d*(1-a))
   771         //and smoothed text is always g=2.0.
   772         fRGBSpace = CGColorSpaceCreateDeviceRGB();
   773     }
   775     // default to kBW_Format
   776     bool doAA = false;
   777     bool doLCD = false;
   779     if (SkMask::kBW_Format != glyph.fMaskFormat) {
   780         doLCD = true;
   781         doAA = true;
   782     }
   784     // FIXME: lcd smoothed un-hinted rasterization unsupported.
   785     if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) {
   786         doLCD = false;
   787         doAA = true;
   788     }
   790     size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
   791     if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
   792         if (fSize.fWidth < glyph.fWidth) {
   793             fSize.fWidth = RoundSize(glyph.fWidth);
   794         }
   795         if (fSize.fHeight < glyph.fHeight) {
   796             fSize.fHeight = RoundSize(glyph.fHeight);
   797         }
   799         rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
   800         void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
   801         fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
   802                                     rowBytes, fRGBSpace, BITMAP_INFO_RGB);
   804         // skia handles quantization itself, so we disable this for cg to get
   805         // full fractional data from them.
   806         CGContextSetAllowsFontSubpixelQuantization(fCG, false);
   807         CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
   809         CGContextSetTextDrawingMode(fCG, kCGTextFill);
   810         CGContextSetFont(fCG, context.fCGFont);
   811         CGContextSetFontSize(fCG, 1 /*CTFontGetSize(context.fCTFont)*/);
   812         CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
   814         // Because CG always draws from the horizontal baseline,
   815         // if there is a non-integral translation from the horizontal origin to the vertical origin,
   816         // then CG cannot draw the glyph in the correct location without subpixel positioning.
   817         CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical);
   818         CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || context.fVertical);
   820         // Draw white on black to create mask.
   821         // TODO: Draw black on white and invert, CG has a special case codepath.
   822         CGContextSetGrayFillColor(fCG, 1.0f, 1.0f);
   824         // force our checks below to happen
   825         fDoAA = !doAA;
   826         fDoLCD = !doLCD;
   827     }
   829     if (fDoAA != doAA) {
   830         CGContextSetShouldAntialias(fCG, doAA);
   831         fDoAA = doAA;
   832     }
   833     if (fDoLCD != doLCD) {
   834         CGContextSetShouldSmoothFonts(fCG, doLCD);
   835         fDoLCD = doLCD;
   836     }
   838     CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
   839     // skip rows based on the glyph's height
   840     image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
   842     // erase to black
   843     sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes);
   845     float subX = 0;
   846     float subY = 0;
   847     if (context.fDoSubPosition) {
   848         subX = SkFixedToFloat(glyph.getSubXFixed());
   849         subY = SkFixedToFloat(glyph.getSubYFixed());
   850     }
   852     // CGContextShowGlyphsAtPoint always draws using the horizontal baseline origin.
   853     if (context.fVertical) {
   854         SkPoint offset;
   855         context.getVerticalOffset(glyphID, &offset);
   856         subX += offset.fX;
   857         subY += offset.fY;
   858     }
   860     CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX,
   861                                glyph.fTop + glyph.fHeight - subY,
   862                                &glyphID, 1);
   864     SkASSERT(rowBytesPtr);
   865     *rowBytesPtr = rowBytes;
   866     return image;
   867 }
   869 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const {
   870     // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up).
   871     // Lion and Leopard return cgVertOffset in CG units (pixels, y up).
   872     CGSize cgVertOffset;
   873     CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1);
   875     SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) };
   876     if (isSnowLeopard()) {
   877         // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
   878         fFUnitMatrix.mapPoints(&skVertOffset, 1);
   879     } else {
   880         // From CG units (pixels, y up) to SkGlyph units (pixels, y down).
   881         skVertOffset.fY = -skVertOffset.fY;
   882     }
   884     *offset = skVertOffset;
   885 }
   887 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() {
   888     if (fFBoundingBoxesGlyphOffset) {
   889         return fFBoundingBoxesGlyphOffset;
   890     }
   891     fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts
   892     AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont);
   893     if (hheaTable.fData) {
   894         fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetrics);
   895     }
   896     return fFBoundingBoxesGlyphOffset;
   897 }
   899 bool SkScalerContext_Mac::generateBBoxes() {
   900     if (fGeneratedFBoundingBoxes) {
   901         return NULL != fFBoundingBoxes.get();
   902     }
   903     fGeneratedFBoundingBoxes = true;
   905     AutoCGTable<SkOTTableHead> headTable(fCGFont);
   906     if (!headTable.fData) {
   907         return false;
   908     }
   910     AutoCGTable<SkOTTableIndexToLocation> locaTable(fCGFont);
   911     if (!locaTable.fData) {
   912         return false;
   913     }
   915     AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont);
   916     if (!glyfTable.fData) {
   917         return false;
   918     }
   920     uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset;
   921     fFBoundingBoxes.reset(entries);
   923     SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat;
   924     SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, locaFormat);
   925     glyphDataIter.advance(fFBoundingBoxesGlyphOffset);
   926     for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundingBoxesIndex) {
   927         const SkOTTableGlyphData* glyphData = glyphDataIter.next();
   928         GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex];
   929         rect.fMinX = SkEndian_SwapBE16(glyphData->xMin);
   930         rect.fMinY = SkEndian_SwapBE16(glyphData->yMin);
   931         rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax);
   932         rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax);
   933     }
   935     return true;
   936 }
   938 unsigned SkScalerContext_Mac::generateGlyphCount(void) {
   939     return fGlyphCount;
   940 }
   942 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) {
   943     CGGlyph cgGlyph[2];
   944     UniChar theChar[2]; // UniChar is a UTF-16 16-bit code unit.
   946     // Get the glyph
   947     size_t numUniChar = SkUTF16_FromUnichar(uni, theChar);
   948     SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t));
   950     // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
   951     // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
   952     // It is documented that if a mapping is unavailable, the glyph will be set to 0.
   953     CTFontGetGlyphsForCharacters(fCTFont, theChar, cgGlyph, numUniChar);
   954     return cgGlyph[0];
   955 }
   957 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
   958     this->generateMetrics(glyph);
   959 }
   961 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
   962     const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount);
   963     glyph->zeroMetrics();
   965     // The following block produces cgAdvance in CG units (pixels, y up).
   966     CGSize cgAdvance;
   967     if (fVertical) {
   968         CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation,
   969                                    &cgGlyph, &cgAdvance, 1);
   970     } else {
   971         CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation,
   972                                    &cgGlyph, &cgAdvance, 1);
   973     }
   974     glyph->fAdvanceX =  SkFloatToFixed_Check(cgAdvance.width);
   975     glyph->fAdvanceY = -SkFloatToFixed_Check(cgAdvance.height);
   977     // The following produces skBounds in SkGlyph units (pixels, y down),
   978     // or returns early if skBounds would be empty.
   979     SkRect skBounds;
   981     // On Mountain Lion, CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation and
   982     // CTFontGetVerticalTranslationsForGlyphs do not agree when using OTF CFF fonts.
   983     // For TTF fonts these two do agree and we can use CTFontGetBoundingRectsForGlyphs to get
   984     // the bounding box and CTFontGetVerticalTranslationsForGlyphs to then draw the glyph
   985     // inside that bounding box. However, with OTF CFF fonts this does not work. It appears that
   986     // CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation on OTF CFF fonts tries
   987     // to center the glyph along the vertical baseline and also perform some mysterious shift
   988     // along the baseline. CTFontGetVerticalTranslationsForGlyphs does not appear to perform
   989     // these steps.
   990     //
   991     // It is not known which is correct (or if either is correct). However, we must always draw
   992     // from the horizontal origin and must use CTFontGetVerticalTranslationsForGlyphs to draw.
   993     // As a result, we do not call CTFontGetBoundingRectsForGlyphs for vertical glyphs.
   995     // On Snow Leopard, CTFontGetBoundingRectsForGlyphs ignores kCTFontVerticalOrientation and
   996     // returns horizontal bounds.
   998     // On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
   999     // return a bad value in cgBounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
  1000     // less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
  1001     // font directly.
  1002     if ((isLion() || isMountainLion()) &&
  1003         (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && generateBBoxes()))
  1005         const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphOffset];
  1006         if (gRect.fMinX >= gRect.fMaxX || gRect.fMinY >= gRect.fMaxY) {
  1007             return;
  1009         skBounds = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY);
  1010         // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
  1011         fFUnitMatrix.mapRect(&skBounds);
  1013     } else {
  1014         // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up).
  1015         CGRect cgBounds;
  1016         CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation,
  1017                                         &cgGlyph, &cgBounds, 1);
  1019         // BUG?
  1020         // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when
  1021         // it should be empty. So, if we see a zero-advance, we check if it has an
  1022         // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance
  1023         // is rare, so we won't incur a big performance cost for this extra check.
  1024         if (0 == cgAdvance.width && 0 == cgAdvance.height) {
  1025             AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL));
  1026             if (NULL == path || CGPathIsEmpty(path)) {
  1027                 return;
  1031         if (CGRectIsEmpty_inline(cgBounds)) {
  1032             return;
  1035         // Convert cgBounds to SkGlyph units (pixels, y down).
  1036         skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height,
  1037                                     cgBounds.size.width, cgBounds.size.height);
  1040     if (fVertical) {
  1041         // Due to all of the vertical bounds bugs, skBounds is always the horizontal bounds.
  1042         // Convert these horizontal bounds into vertical bounds.
  1043         SkPoint offset;
  1044         getVerticalOffset(cgGlyph, &offset);
  1045         skBounds.offset(offset);
  1048     // Currently the bounds are based on being rendered at (0,0).
  1049     // The top left must not move, since that is the base from which subpixel positioning is offset.
  1050     if (fDoSubPosition) {
  1051         skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed());
  1052         skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed());
  1055     SkIRect skIBounds;
  1056     skBounds.roundOut(&skIBounds);
  1057     // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
  1058     // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
  1059     // is not currently known, as CG dilates the outlines by some percentage.
  1060     // Note that if this context is A8 and not back-forming from LCD, there is no need to outset.
  1061     skIBounds.outset(1, 1);
  1062     glyph->fLeft = SkToS16(skIBounds.fLeft);
  1063     glyph->fTop = SkToS16(skIBounds.fTop);
  1064     glyph->fWidth = SkToU16(skIBounds.width());
  1065     glyph->fHeight = SkToU16(skIBounds.height());
  1067 #ifdef HACK_COLORGLYPHS
  1068     glyph->fMaskFormat = SkMask::kARGB32_Format;
  1069 #endif
  1072 #include "SkColorPriv.h"
  1074 static void build_power_table(uint8_t table[], float ee) {
  1075     for (int i = 0; i < 256; i++) {
  1076         float x = i / 255.f;
  1077         x = sk_float_pow(x, ee);
  1078         int xx = SkScalarRoundToInt(x * 255);
  1079         table[i] = SkToU8(xx);
  1083 /**
  1084  *  This will invert the gamma applied by CoreGraphics, so we can get linear
  1085  *  values.
  1087  *  CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value.
  1088  *  The color space used does not appear to affect this choice.
  1089  */
  1090 static const uint8_t* getInverseGammaTableCoreGraphicSmoothing() {
  1091     static bool gInited;
  1092     static uint8_t gTableCoreGraphicsSmoothing[256];
  1093     if (!gInited) {
  1094         build_power_table(gTableCoreGraphicsSmoothing, 2.0f);
  1095         gInited = true;
  1097     return gTableCoreGraphicsSmoothing;
  1100 static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
  1101     while (count > 0) {
  1102         uint8_t mask = 0;
  1103         for (int i = 7; i >= 0; --i) {
  1104             mask |= (CGRGBPixel_getAlpha(*src++) >> 7) << i;
  1105             if (0 == --count) {
  1106                 break;
  1109         *dst++ = mask;
  1113 template<bool APPLY_PREBLEND>
  1114 static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) {
  1115     U8CPU r = (rgb >> 16) & 0xFF;
  1116     U8CPU g = (rgb >>  8) & 0xFF;
  1117     U8CPU b = (rgb >>  0) & 0xFF;
  1118     return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
  1120 template<bool APPLY_PREBLEND>
  1121 static void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes,
  1122                       const SkGlyph& glyph, const uint8_t* table8) {
  1123     const int width = glyph.fWidth;
  1124     size_t dstRB = glyph.rowBytes();
  1125     uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
  1127     for (int y = 0; y < glyph.fHeight; y++) {
  1128         for (int i = 0; i < width; ++i) {
  1129             dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8);
  1131         cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
  1132         dst += dstRB;
  1136 template<bool APPLY_PREBLEND>
  1137 static inline uint16_t rgb_to_lcd16(CGRGBPixel rgb, const uint8_t* tableR,
  1138                                                     const uint8_t* tableG,
  1139                                                     const uint8_t* tableB) {
  1140     U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
  1141     U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
  1142     U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
  1143     return SkPack888ToRGB16(r, g, b);
  1145 template<bool APPLY_PREBLEND>
  1146 static void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
  1147                          const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
  1148     const int width = glyph.fWidth;
  1149     size_t dstRB = glyph.rowBytes();
  1150     uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage;
  1152     for (int y = 0; y < glyph.fHeight; y++) {
  1153         for (int i = 0; i < width; i++) {
  1154             dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
  1156         cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
  1157         dst = (uint16_t*)((char*)dst + dstRB);
  1161 template<bool APPLY_PREBLEND>
  1162 static inline uint32_t rgb_to_lcd32(CGRGBPixel rgb, const uint8_t* tableR,
  1163                                                     const uint8_t* tableG,
  1164                                                     const uint8_t* tableB) {
  1165     U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
  1166     U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
  1167     U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
  1168     return SkPackARGB32(0xFF, r, g, b);
  1170 template<bool APPLY_PREBLEND>
  1171 static void rgb_to_lcd32(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
  1172                          const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
  1173     const int width = glyph.fWidth;
  1174     size_t dstRB = glyph.rowBytes();
  1175     uint32_t* SK_RESTRICT dst = (uint32_t*)glyph.fImage;
  1176     for (int y = 0; y < glyph.fHeight; y++) {
  1177         for (int i = 0; i < width; i++) {
  1178             dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
  1180         cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
  1181         dst = (uint32_t*)((char*)dst + dstRB);
  1185 #ifdef HACK_COLORGLYPHS
  1186 // hack to colorize the output for testing kARGB32_Format
  1187 static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb, const SkGlyph& glyph,
  1188                                      int x, int y) {
  1189     U8CPU r = (rgb >> 16) & 0xFF;
  1190     U8CPU g = (rgb >>  8) & 0xFF;
  1191     U8CPU b = (rgb >>  0) & 0xFF;
  1192     unsigned a = SkComputeLuminance(r, g, b);
  1194     // compute gradient from x,y
  1195     r = x * 255 / glyph.fWidth;
  1196     g = 0;
  1197     b = (glyph.fHeight - y) * 255 / glyph.fHeight;
  1198     return SkPreMultiplyARGB(a, r, g, b);    // red
  1200 #endif
  1202 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
  1203     return (T*)((char*)ptr + byteOffset);
  1206 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
  1207     CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
  1209     // FIXME: lcd smoothed un-hinted rasterization unsupported.
  1210     bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting;
  1212     // Draw the glyph
  1213     size_t cgRowBytes;
  1214     CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, generateA8FromLCD);
  1215     if (cgPixels == NULL) {
  1216         return;
  1219     //TODO: see if drawing black on white and inverting is faster (at least in
  1220     //lcd case) as core graphics appears to have special case code for drawing
  1221     //black text.
  1223     // Fix the glyph
  1224     const bool isLCD = isLCDFormat(glyph.fMaskFormat);
  1225     if (isLCD || (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD)) {
  1226         const uint8_t* table = getInverseGammaTableCoreGraphicSmoothing();
  1228         //Note that the following cannot really be integrated into the
  1229         //pre-blend, since we may not be applying the pre-blend; when we aren't
  1230         //applying the pre-blend it means that a filter wants linear anyway.
  1231         //Other code may also be applying the pre-blend, so we'd need another
  1232         //one with this and one without.
  1233         CGRGBPixel* addr = cgPixels;
  1234         for (int y = 0; y < glyph.fHeight; ++y) {
  1235             for (int x = 0; x < glyph.fWidth; ++x) {
  1236                 int r = (addr[x] >> 16) & 0xFF;
  1237                 int g = (addr[x] >>  8) & 0xFF;
  1238                 int b = (addr[x] >>  0) & 0xFF;
  1239                 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
  1241             addr = SkTAddByteOffset(addr, cgRowBytes);
  1245     // Convert glyph to mask
  1246     switch (glyph.fMaskFormat) {
  1247         case SkMask::kLCD32_Format: {
  1248             if (fPreBlend.isApplicable()) {
  1249                 rgb_to_lcd32<true>(cgPixels, cgRowBytes, glyph,
  1250                                    fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1251             } else {
  1252                 rgb_to_lcd32<false>(cgPixels, cgRowBytes, glyph,
  1253                                     fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1255         } break;
  1256         case SkMask::kLCD16_Format: {
  1257             if (fPreBlend.isApplicable()) {
  1258                 rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph,
  1259                                    fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1260             } else {
  1261                 rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph,
  1262                                     fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1264         } break;
  1265         case SkMask::kA8_Format: {
  1266             if (fPreBlend.isApplicable()) {
  1267                 rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
  1268             } else {
  1269                 rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
  1271         } break;
  1272         case SkMask::kBW_Format: {
  1273             const int width = glyph.fWidth;
  1274             size_t dstRB = glyph.rowBytes();
  1275             uint8_t* dst = (uint8_t*)glyph.fImage;
  1276             for (int y = 0; y < glyph.fHeight; y++) {
  1277                 cgpixels_to_bits(dst, cgPixels, width);
  1278                 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
  1279                 dst += dstRB;
  1281         } break;
  1282 #ifdef HACK_COLORGLYPHS
  1283         case SkMask::kARGB32_Format: {
  1284             const int width = glyph.fWidth;
  1285             size_t dstRB = glyph.rowBytes();
  1286             SkPMColor* dst = (SkPMColor*)glyph.fImage;
  1287             for (int y = 0; y < glyph.fHeight; y++) {
  1288                 for (int x = 0; x < width; ++x) {
  1289                     dst[x] = cgpixels_to_pmcolor(cgPixels[x], glyph, x, y);
  1291                 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
  1292                 dst = (SkPMColor*)((char*)dst + dstRB);
  1294         } break;
  1295 #endif
  1296         default:
  1297             SkDEBUGFAIL("unexpected mask format");
  1298             break;
  1302 /*
  1303  *  Our subpixel resolution is only 2 bits in each direction, so a scale of 4
  1304  *  seems sufficient, and possibly even correct, to allow the hinted outline
  1305  *  to be subpixel positioned.
  1306  */
  1307 #define kScaleForSubPixelPositionHinting (4.0f)
  1309 void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) {
  1310     CTFontRef font = fCTFont;
  1311     SkScalar scaleX = SK_Scalar1;
  1312     SkScalar scaleY = SK_Scalar1;
  1314     /*
  1315      *  For subpixel positioning, we want to return an unhinted outline, so it
  1316      *  can be positioned nicely at fractional offsets. However, we special-case
  1317      *  if the baseline of the (horizontal) text is axis-aligned. In those cases
  1318      *  we want to retain hinting in the direction orthogonal to the baseline.
  1319      *  e.g. for horizontal baseline, we want to retain hinting in Y.
  1320      *  The way we remove hinting is to scale the font by some value (4) in that
  1321      *  direction, ask for the path, and then scale the path back down.
  1322      */
  1323     if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
  1324         SkMatrix m;
  1325         fRec.getSingleMatrix(&m);
  1327         // start out by assuming that we want no hining in X and Y
  1328         scaleX = scaleY = kScaleForSubPixelPositionHinting;
  1329         // now see if we need to restore hinting for axis-aligned baselines
  1330         switch (SkComputeAxisAlignmentForHText(m)) {
  1331             case kX_SkAxisAlignment:
  1332                 scaleY = SK_Scalar1; // want hinting in the Y direction
  1333                 break;
  1334             case kY_SkAxisAlignment:
  1335                 scaleX = SK_Scalar1; // want hinting in the X direction
  1336                 break;
  1337             default:
  1338                 break;
  1341         CGAffineTransform xform = MatrixToCGAffineTransform(m, scaleX, scaleY);
  1342         // need to release font when we're done
  1343         font = CTFontCreateCopyWithAttributes(fCTFont, 1, &xform, NULL);
  1346     CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount);
  1347     AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL));
  1349     path->reset();
  1350     if (cgPath != NULL) {
  1351         CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement);
  1354     if (fDoSubPosition) {
  1355         SkMatrix m;
  1356         m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY));
  1357         path->transform(m);
  1358         // balance the call to CTFontCreateCopyWithAttributes
  1359         CFSafeRelease(font);
  1361     if (fVertical) {
  1362         SkPoint offset;
  1363         getVerticalOffset(cgGlyph, &offset);
  1364         path->offset(offset.fX, offset.fY);
  1368 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
  1369                                               SkPaint::FontMetrics* my) {
  1370     CGRect theBounds = CTFontGetBoundingBox(fCTFont);
  1372     SkPaint::FontMetrics theMetrics;
  1373     theMetrics.fTop          = CGToScalar(-CGRectGetMaxY_inline(theBounds));
  1374     theMetrics.fAscent       = CGToScalar(-CTFontGetAscent(fCTFont));
  1375     theMetrics.fDescent      = CGToScalar( CTFontGetDescent(fCTFont));
  1376     theMetrics.fBottom       = CGToScalar(-CGRectGetMinY_inline(theBounds));
  1377     theMetrics.fLeading      = CGToScalar( CTFontGetLeading(fCTFont));
  1378     theMetrics.fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds));
  1379     theMetrics.fXMin         = CGToScalar( CGRectGetMinX_inline(theBounds));
  1380     theMetrics.fXMax         = CGToScalar( CGRectGetMaxX_inline(theBounds));
  1381     theMetrics.fXHeight      = CGToScalar( CTFontGetXHeight(fCTFont));
  1382     theMetrics.fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont));
  1383     theMetrics.fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont));
  1385     theMetrics.fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
  1386     theMetrics.fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
  1388     if (mx != NULL) {
  1389         *mx = theMetrics;
  1391     if (my != NULL) {
  1392         *my = theMetrics;
  1396 void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) {
  1397     SkPath* skPath = (SkPath*)info;
  1399     // Process the path element
  1400     switch (element->type) {
  1401         case kCGPathElementMoveToPoint:
  1402             skPath->moveTo(element->points[0].x, -element->points[0].y);
  1403             break;
  1405         case kCGPathElementAddLineToPoint:
  1406             skPath->lineTo(element->points[0].x, -element->points[0].y);
  1407             break;
  1409         case kCGPathElementAddQuadCurveToPoint:
  1410             skPath->quadTo(element->points[0].x, -element->points[0].y,
  1411                            element->points[1].x, -element->points[1].y);
  1412             break;
  1414         case kCGPathElementAddCurveToPoint:
  1415             skPath->cubicTo(element->points[0].x, -element->points[0].y,
  1416                             element->points[1].x, -element->points[1].y,
  1417                             element->points[2].x, -element->points[2].y);
  1418             break;
  1420         case kCGPathElementCloseSubpath:
  1421             skPath->close();
  1422             break;
  1424         default:
  1425             SkDEBUGFAIL("Unknown path element!");
  1426             break;
  1431 ///////////////////////////////////////////////////////////////////////////////
  1433 // Returns NULL on failure
  1434 // Call must still manage its ownership of provider
  1435 static SkTypeface* create_from_dataProvider(CGDataProviderRef provider) {
  1436     AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider));
  1437     if (NULL == cg) {
  1438         return NULL;
  1440     CTFontRef ct = CTFontCreateWithGraphicsFont(cg, 0, NULL, NULL);
  1441     return cg ? SkCreateTypefaceFromCTFont(ct) : NULL;
  1444 // Web fonts added to the the CTFont registry do not return their character set.
  1445 // Iterate through the font in this case. The existing caller caches the result,
  1446 // so the performance impact isn't too bad.
  1447 static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
  1448                                            SkTDArray<SkUnichar>* glyphToUnicode) {
  1449     glyphToUnicode->setCount(SkToInt(glyphCount));
  1450     SkUnichar* out = glyphToUnicode->begin();
  1451     sk_bzero(out, glyphCount * sizeof(SkUnichar));
  1452     UniChar unichar = 0;
  1453     while (glyphCount > 0) {
  1454         CGGlyph glyph;
  1455         if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
  1456             out[glyph] = unichar;
  1457             --glyphCount;
  1459         if (++unichar == 0) {
  1460             break;
  1465 // Construct Glyph to Unicode table.
  1466 // Unicode code points that require conjugate pairs in utf16 are not
  1467 // supported.
  1468 static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
  1469                                       SkTDArray<SkUnichar>* glyphToUnicode) {
  1470     AutoCFRelease<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
  1471     if (!charSet) {
  1472         populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
  1473         return;
  1476     AutoCFRelease<CFDataRef> bitmap(CFCharacterSetCreateBitmapRepresentation(kCFAllocatorDefault,
  1477                                                                              charSet));
  1478     if (!bitmap) {
  1479         return;
  1481     CFIndex length = CFDataGetLength(bitmap);
  1482     if (!length) {
  1483         return;
  1485     if (length > 8192) {
  1486         // TODO: Add support for Unicode above 0xFFFF
  1487         // Consider only the BMP portion of the Unicode character points.
  1488         // The bitmap may contain other planes, up to plane 16.
  1489         // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html
  1490         length = 8192;
  1492     const UInt8* bits = CFDataGetBytePtr(bitmap);
  1493     glyphToUnicode->setCount(SkToInt(glyphCount));
  1494     SkUnichar* out = glyphToUnicode->begin();
  1495     sk_bzero(out, glyphCount * sizeof(SkUnichar));
  1496     for (int i = 0; i < length; i++) {
  1497         int mask = bits[i];
  1498         if (!mask) {
  1499             continue;
  1501         for (int j = 0; j < 8; j++) {
  1502             CGGlyph glyph;
  1503             UniChar unichar = static_cast<UniChar>((i << 3) + j);
  1504             if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
  1505                 out[glyph] = unichar;
  1511 static bool getWidthAdvance(CTFontRef ctFont, int gId, int16_t* data) {
  1512     CGSize advance;
  1513     advance.width = 0;
  1514     CGGlyph glyph = gId;
  1515     CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &glyph, &advance, 1);
  1516     *data = sk_float_round2int(advance.width);
  1517     return true;
  1520 // we might move this into our CGUtils...
  1521 static void CFStringToSkString(CFStringRef src, SkString* dst) {
  1522     // Reserve enough room for the worst-case string,
  1523     // plus 1 byte for the trailing null.
  1524     CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src),
  1525                                                        kCFStringEncodingUTF8) + 1;
  1526     dst->resize(length);
  1527     CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8);
  1528     // Resize to the actual UTF-8 length used, stripping the null character.
  1529     dst->resize(strlen(dst->c_str()));
  1532 SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics(
  1533         SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
  1534         const uint32_t* glyphIDs,
  1535         uint32_t glyphIDsCount) const {
  1537     CTFontRef originalCTFont = fFontRef.get();
  1538     AutoCFRelease<CTFontRef> ctFont(CTFontCreateCopyWithAttributes(
  1539             originalCTFont, CTFontGetUnitsPerEm(originalCTFont), NULL, NULL));
  1540     SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
  1543         AutoCFRelease<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont));
  1544         CFStringToSkString(fontName, &info->fFontName);
  1547     info->fMultiMaster = false;
  1548     CFIndex glyphCount = CTFontGetGlyphCount(ctFont);
  1549     info->fLastGlyphID = SkToU16(glyphCount - 1);
  1550     info->fEmSize = CTFontGetUnitsPerEm(ctFont);
  1552     if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
  1553         populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode);
  1556     info->fStyle = 0;
  1558     // If it's not a truetype font, mark it as 'other'. Assume that TrueType
  1559     // fonts always have both glyf and loca tables. At the least, this is what
  1560     // sfntly needs to subset the font. CTFontCopyAttribute() does not always
  1561     // succeed in determining this directly.
  1562     if (!this->getTableSize('glyf') || !this->getTableSize('loca')) {
  1563         info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
  1564         info->fItalicAngle = 0;
  1565         info->fAscent = 0;
  1566         info->fDescent = 0;
  1567         info->fStemV = 0;
  1568         info->fCapHeight = 0;
  1569         info->fBBox = SkIRect::MakeEmpty();
  1570         return info;
  1573     info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
  1574     CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont);
  1575     if (symbolicTraits & kCTFontMonoSpaceTrait) {
  1576         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
  1578     if (symbolicTraits & kCTFontItalicTrait) {
  1579         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
  1581     CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
  1582     if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
  1583         info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
  1584     } else if (stylisticClass & kCTFontScriptsClass) {
  1585         info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
  1587     info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont);
  1588     info->fAscent = (int16_t) CTFontGetAscent(ctFont);
  1589     info->fDescent = (int16_t) CTFontGetDescent(ctFont);
  1590     info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont);
  1591     CGRect bbox = CTFontGetBoundingBox(ctFont);
  1593     SkRect r;
  1594     r.set( CGToScalar(CGRectGetMinX_inline(bbox)),   // Left
  1595            CGToScalar(CGRectGetMaxY_inline(bbox)),   // Top
  1596            CGToScalar(CGRectGetMaxX_inline(bbox)),   // Right
  1597            CGToScalar(CGRectGetMinY_inline(bbox)));  // Bottom
  1599     r.roundOut(&(info->fBBox));
  1601     // Figure out a good guess for StemV - Min width of i, I, !, 1.
  1602     // This probably isn't very good with an italic font.
  1603     int16_t min_width = SHRT_MAX;
  1604     info->fStemV = 0;
  1605     static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
  1606     const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
  1607     CGGlyph glyphs[count];
  1608     CGRect boundingRects[count];
  1609     if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) {
  1610         CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation,
  1611                                         glyphs, boundingRects, count);
  1612         for (size_t i = 0; i < count; i++) {
  1613             int16_t width = (int16_t) boundingRects[i].size.width;
  1614             if (width > 0 && width < min_width) {
  1615                 min_width = width;
  1616                 info->fStemV = min_width;
  1621     if (false) { // TODO: haven't figured out how to know if font is embeddable
  1622         // (information is in the OS/2 table)
  1623         info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
  1624     } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
  1625         if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
  1626             skia_advanced_typeface_metrics_utils::appendRange(&info->fGlyphWidths, 0);
  1627             info->fGlyphWidths->fAdvance.append(1, &min_width);
  1628             skia_advanced_typeface_metrics_utils::finishRange(info->fGlyphWidths.get(), 0,
  1629                         SkAdvancedTypefaceMetrics::WidthRange::kDefault);
  1630         } else {
  1631             info->fGlyphWidths.reset(
  1632                 skia_advanced_typeface_metrics_utils::getAdvanceData(ctFont.get(),
  1633                                SkToInt(glyphCount),
  1634                                glyphIDs,
  1635                                glyphIDsCount,
  1636                                &getWidthAdvance));
  1639     return info;
  1642 ///////////////////////////////////////////////////////////////////////////////
  1644 static SK_SFNT_ULONG get_font_type_tag(const SkTypeface_Mac* typeface) {
  1645     CTFontRef ctFont = typeface->fFontRef.get();
  1646     AutoCFRelease<CFNumberRef> fontFormatRef(
  1647             static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
  1648     if (!fontFormatRef) {
  1649         return 0;
  1652     SInt32 fontFormatValue;
  1653     if (!CFNumberGetValue(fontFormatRef, kCFNumberSInt32Type, &fontFormatValue)) {
  1654         return 0;
  1657     switch (fontFormatValue) {
  1658         case kCTFontFormatOpenTypePostScript:
  1659             return SkSFNTHeader::fontType_OpenTypeCFF::TAG;
  1660         case kCTFontFormatOpenTypeTrueType:
  1661             return SkSFNTHeader::fontType_WindowsTrueType::TAG;
  1662         case kCTFontFormatTrueType:
  1663             return SkSFNTHeader::fontType_MacTrueType::TAG;
  1664         case kCTFontFormatPostScript:
  1665             return SkSFNTHeader::fontType_PostScript::TAG;
  1666         case kCTFontFormatBitmap:
  1667             return SkSFNTHeader::fontType_MacTrueType::TAG;
  1668         case kCTFontFormatUnrecognized:
  1669         default:
  1670             //CT seems to be unreliable in being able to obtain the type,
  1671             //even if all we want is the first four bytes of the font resource.
  1672             //Just the presence of the FontForge 'FFTM' table seems to throw it off.
  1673             return SkSFNTHeader::fontType_WindowsTrueType::TAG;
  1677 SkStream* SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
  1678     SK_SFNT_ULONG fontType = get_font_type_tag(this);
  1679     if (0 == fontType) {
  1680         return NULL;
  1683     // get table tags
  1684     int numTables = this->countTables();
  1685     SkTDArray<SkFontTableTag> tableTags;
  1686     tableTags.setCount(numTables);
  1687     this->getTableTags(tableTags.begin());
  1689     // calc total size for font, save sizes
  1690     SkTDArray<size_t> tableSizes;
  1691     size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
  1692     for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
  1693         size_t tableSize = this->getTableSize(tableTags[tableIndex]);
  1694         totalSize += (tableSize + 3) & ~3;
  1695         *tableSizes.append() = tableSize;
  1698     // reserve memory for stream, and zero it (tables must be zero padded)
  1699     SkMemoryStream* stream = new SkMemoryStream(totalSize);
  1700     char* dataStart = (char*)stream->getMemoryBase();
  1701     sk_bzero(dataStart, totalSize);
  1702     char* dataPtr = dataStart;
  1704     // compute font header entries
  1705     uint16_t entrySelector = 0;
  1706     uint16_t searchRange = 1;
  1707     while (searchRange < numTables >> 1) {
  1708         entrySelector++;
  1709         searchRange <<= 1;
  1711     searchRange <<= 4;
  1712     uint16_t rangeShift = (numTables << 4) - searchRange;
  1714     // write font header
  1715     SkSFNTHeader* header = (SkSFNTHeader*)dataPtr;
  1716     header->fontType = fontType;
  1717     header->numTables = SkEndian_SwapBE16(numTables);
  1718     header->searchRange = SkEndian_SwapBE16(searchRange);
  1719     header->entrySelector = SkEndian_SwapBE16(entrySelector);
  1720     header->rangeShift = SkEndian_SwapBE16(rangeShift);
  1721     dataPtr += sizeof(SkSFNTHeader);
  1723     // write tables
  1724     SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr;
  1725     dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
  1726     for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
  1727         size_t tableSize = tableSizes[tableIndex];
  1728         this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
  1729         entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]);
  1730         entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr,
  1731                                                                          tableSize));
  1732         entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart));
  1733         entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize));
  1735         dataPtr += (tableSize + 3) & ~3;
  1736         ++entry;
  1739     return stream;
  1742 ///////////////////////////////////////////////////////////////////////////////
  1743 ///////////////////////////////////////////////////////////////////////////////
  1745 int SkTypeface_Mac::onGetUPEM() const {
  1746     AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef, NULL));
  1747     return CGFontGetUnitsPerEm(cgFont);
  1750 SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const {
  1751     SkTypeface::LocalizedStrings* nameIter =
  1752         SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
  1753     if (NULL == nameIter) {
  1754         AutoCFRelease<CFStringRef> cfLanguage;
  1755         AutoCFRelease<CFStringRef> cfFamilyName(
  1756             CTFontCopyLocalizedName(fFontRef, kCTFontFamilyNameKey, &cfLanguage));
  1758         SkString skLanguage;
  1759         SkString skFamilyName;
  1760         if (cfLanguage.get()) {
  1761             CFStringToSkString(cfLanguage.get(), &skLanguage);
  1762         } else {
  1763             skLanguage = "und"; //undetermined
  1765         if (cfFamilyName.get()) {
  1766             CFStringToSkString(cfFamilyName.get(), &skFamilyName);
  1769         nameIter = new SkOTUtils::LocalizedStrings_SingleName(skFamilyName, skLanguage);
  1771     return nameIter;
  1774 // If, as is the case with web fonts, the CTFont data isn't available,
  1775 // the CGFont data may work. While the CGFont may always provide the
  1776 // right result, leave the CTFont code path to minimize disruption.
  1777 static CFDataRef copyTableFromFont(CTFontRef ctFont, SkFontTableTag tag) {
  1778     CFDataRef data = CTFontCopyTable(ctFont, (CTFontTableTag) tag,
  1779                                      kCTFontTableOptionNoOptions);
  1780     if (NULL == data) {
  1781         AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, NULL));
  1782         data = CGFontCopyTableForTag(cgFont, tag);
  1784     return data;
  1787 int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
  1788     AutoCFRelease<CFArrayRef> cfArray(CTFontCopyAvailableTables(fFontRef,
  1789                                                 kCTFontTableOptionNoOptions));
  1790     if (NULL == cfArray) {
  1791         return 0;
  1793     int count = SkToInt(CFArrayGetCount(cfArray));
  1794     if (tags) {
  1795         for (int i = 0; i < count; ++i) {
  1796             uintptr_t fontTag = reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(cfArray, i));
  1797             tags[i] = static_cast<SkFontTableTag>(fontTag);
  1800     return count;
  1803 size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset,
  1804                                       size_t length, void* dstData) const {
  1805     AutoCFRelease<CFDataRef> srcData(copyTableFromFont(fFontRef, tag));
  1806     if (NULL == srcData) {
  1807         return 0;
  1810     size_t srcSize = CFDataGetLength(srcData);
  1811     if (offset >= srcSize) {
  1812         return 0;
  1814     if (length > srcSize - offset) {
  1815         length = srcSize - offset;
  1817     if (dstData) {
  1818         memcpy(dstData, CFDataGetBytePtr(srcData) + offset, length);
  1820     return length;
  1823 SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkDescriptor* desc) const {
  1824     return new SkScalerContext_Mac(const_cast<SkTypeface_Mac*>(this), desc);
  1827 void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
  1828     if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
  1829         rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
  1831         rec->fMaskFormat = SkMask::kA8_Format;
  1832         // Render the glyphs as close as possible to what was requested.
  1833         // The above turns off subpixel rendering, but the user requested it.
  1834         // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks.
  1835         // See comments below for more details.
  1836         rec->setHinting(SkPaint::kNormal_Hinting);
  1839     unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag  |
  1840                                   SkScalerContext::kForceAutohinting_Flag  |
  1841                                   SkScalerContext::kLCD_BGROrder_Flag |
  1842                                   SkScalerContext::kLCD_Vertical_Flag;
  1844     rec->fFlags &= ~flagsWeDontSupport;
  1846     bool lcdSupport = supports_LCD();
  1848     // Only two levels of hinting are supported.
  1849     // kNo_Hinting means avoid CoreGraphics outline dilation.
  1850     // kNormal_Hinting means CoreGraphics outline dilation is allowed.
  1851     // If there is no lcd support, hinting (dilation) cannot be supported.
  1852     SkPaint::Hinting hinting = rec->getHinting();
  1853     if (SkPaint::kSlight_Hinting == hinting || !lcdSupport) {
  1854         hinting = SkPaint::kNo_Hinting;
  1855     } else if (SkPaint::kFull_Hinting == hinting) {
  1856         hinting = SkPaint::kNormal_Hinting;
  1858     rec->setHinting(hinting);
  1860     // FIXME: lcd smoothed un-hinted rasterization unsupported.
  1861     // Tracked by http://code.google.com/p/skia/issues/detail?id=915 .
  1862     // There is no current means to honor a request for unhinted lcd,
  1863     // so arbitrarilly ignore the hinting request and honor lcd.
  1865     // Hinting and smoothing should be orthogonal, but currently they are not.
  1866     // CoreGraphics has no API to influence hinting. However, its lcd smoothed
  1867     // output is drawn from auto-dilated outlines (the amount of which is
  1868     // determined by AppleFontSmoothing). Its regular anti-aliased output is
  1869     // drawn from un-dilated outlines.
  1871     // The behavior of Skia is as follows:
  1872     // [AA][no-hint]: generate AA using CoreGraphic's AA output.
  1873     // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single
  1874     // channel. This matches [LCD][yes-hint] in weight.
  1875     // [LCD][no-hint]: curently unable to honor, and must pick which to respect.
  1876     // Currenly side with LCD, effectively ignoring the hinting setting.
  1877     // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output.
  1879     if (isLCDFormat(rec->fMaskFormat)) {
  1880         if (lcdSupport) {
  1881             //CoreGraphics creates 555 masks for smoothed text anyway.
  1882             rec->fMaskFormat = SkMask::kLCD16_Format;
  1883             rec->setHinting(SkPaint::kNormal_Hinting);
  1884         } else {
  1885             rec->fMaskFormat = SkMask::kA8_Format;
  1889     // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
  1890     // All other masks can use regular gamma.
  1891     if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hinting) {
  1892 #ifndef SK_GAMMA_APPLY_TO_A8
  1893         rec->ignorePreBlend();
  1894 #endif
  1895     } else {
  1896         //CoreGraphics dialates smoothed text as needed.
  1897         rec->setContrast(0);
  1901 // we take ownership of the ref
  1902 static const char* get_str(CFStringRef ref, SkString* str) {
  1903     CFStringToSkString(ref, str);
  1904     CFSafeRelease(ref);
  1905     return str->c_str();
  1908 void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc,
  1909                                          bool* isLocalStream) const {
  1910     SkString tmpStr;
  1912     desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef), &tmpStr));
  1913     desc->setFullName(get_str(CTFontCopyFullName(fFontRef), &tmpStr));
  1914     desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef), &tmpStr));
  1915     // TODO: need to add support for local-streams (here and openStream)
  1916     *isLocalStream = false;
  1919 int SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding,
  1920                                     uint16_t glyphs[], int glyphCount) const
  1922     // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
  1923     // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
  1924     // It is documented that if a mapping is unavailable, the glyph will be set to 0.
  1926     SkAutoSTMalloc<1024, UniChar> charStorage;
  1927     const UniChar* src; // UniChar is a UTF-16 16-bit code unit.
  1928     int srcCount;
  1929     switch (encoding) {
  1930         case kUTF8_Encoding: {
  1931             const char* utf8 = reinterpret_cast<const char*>(chars);
  1932             UniChar* utf16 = charStorage.reset(2 * glyphCount);
  1933             src = utf16;
  1934             for (int i = 0; i < glyphCount; ++i) {
  1935                 SkUnichar uni = SkUTF8_NextUnichar(&utf8);
  1936                 utf16 += SkUTF16_FromUnichar(uni, utf16);
  1938             srcCount = SkToInt(utf16 - src);
  1939             break;
  1941         case kUTF16_Encoding: {
  1942             src = reinterpret_cast<const UniChar*>(chars);
  1943             int extra = 0;
  1944             for (int i = 0; i < glyphCount; ++i) {
  1945                 if (SkUTF16_IsHighSurrogate(src[i + extra])) {
  1946                     ++extra;
  1949             srcCount = glyphCount + extra;
  1950             break;
  1952         case kUTF32_Encoding: {
  1953             const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(chars);
  1954             UniChar* utf16 = charStorage.reset(2 * glyphCount);
  1955             src = utf16;
  1956             for (int i = 0; i < glyphCount; ++i) {
  1957                 utf16 += SkUTF16_FromUnichar(utf32[i], utf16);
  1959             srcCount = SkToInt(utf16 - src);
  1960             break;
  1964     // If glyphs is NULL, CT still needs glyph storage for finding the first failure.
  1965     // Also, if there are any non-bmp code points, the provided 'glyphs' storage will be inadequate.
  1966     SkAutoSTMalloc<1024, uint16_t> glyphStorage;
  1967     uint16_t* macGlyphs = glyphs;
  1968     if (NULL == macGlyphs || srcCount > glyphCount) {
  1969         macGlyphs = glyphStorage.reset(srcCount);
  1972     bool allEncoded = CTFontGetGlyphsForCharacters(fFontRef, src, macGlyphs, srcCount);
  1974     // If there were any non-bmp, then copy and compact.
  1975     // If 'glyphs' is NULL, then compact glyphStorage in-place.
  1976     // If all are bmp and 'glyphs' is non-NULL, 'glyphs' already contains the compact glyphs.
  1977     // If some are non-bmp and 'glyphs' is non-NULL, copy and compact into 'glyphs'.
  1978     uint16_t* compactedGlyphs = glyphs;
  1979     if (NULL == compactedGlyphs) {
  1980         compactedGlyphs = macGlyphs;
  1982     if (srcCount > glyphCount) {
  1983         int extra = 0;
  1984         for (int i = 0; i < glyphCount; ++i) {
  1985             if (SkUTF16_IsHighSurrogate(src[i + extra])) {
  1986                 ++extra;
  1988             compactedGlyphs[i] = macGlyphs[i + extra];
  1992     if (allEncoded) {
  1993         return glyphCount;
  1996     // If we got false, then we need to manually look for first failure.
  1997     for (int i = 0; i < glyphCount; ++i) {
  1998         if (0 == compactedGlyphs[i]) {
  1999             return i;
  2002     // Odd to get here, as we expected CT to have returned true up front.
  2003     return glyphCount;
  2006 int SkTypeface_Mac::onCountGlyphs() const {
  2007     return SkToInt(CTFontGetGlyphCount(fFontRef));
  2010 ///////////////////////////////////////////////////////////////////////////////
  2011 ///////////////////////////////////////////////////////////////////////////////
  2012 #if 1
  2014 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
  2015     AutoCFRelease<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
  2016     if (NULL == ref.get()) {
  2017         return false;
  2019     CFStringToSkString(ref, value);
  2020     return true;
  2023 static bool find_dict_float(CFDictionaryRef dict, CFStringRef name, float* value) {
  2024     CFNumberRef num;
  2025     return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num)
  2026     && CFNumberIsFloatType(num)
  2027     && CFNumberGetValue(num, kCFNumberFloatType, value);
  2030 #include "SkFontMgr.h"
  2032 static int unit_weight_to_fontstyle(float unit) {
  2033     float value;
  2034     if (unit < 0) {
  2035         value = 100 + (1 + unit) * 300;
  2036     } else {
  2037         value = 400 + unit * 500;
  2039     return sk_float_round2int(value);
  2042 static int unit_width_to_fontstyle(float unit) {
  2043     float value;
  2044     if (unit < 0) {
  2045         value = 1 + (1 + unit) * 4;
  2046     } else {
  2047         value = 5 + unit * 4;
  2049     return sk_float_round2int(value);
  2052 static inline int sqr(int value) {
  2053     SkASSERT(SkAbs32(value) < 0x7FFF);  // check for overflow
  2054     return value * value;
  2057 // We normalize each axis (weight, width, italic) to be base-900
  2058 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
  2059     return sqr(a.weight() - b.weight()) +
  2060            sqr((a.width() - b.width()) * 100) +
  2061            sqr((a.isItalic() != b.isItalic()) * 900);
  2064 static SkFontStyle desc2fontstyle(CTFontDescriptorRef desc) {
  2065     AutoCFRelease<CFDictionaryRef> dict(
  2066         (CFDictionaryRef)CTFontDescriptorCopyAttribute(desc,
  2067                                                        kCTFontTraitsAttribute));
  2068     if (NULL == dict.get()) {
  2069         return SkFontStyle();
  2072     float weight, width, slant;
  2073     if (!find_dict_float(dict, kCTFontWeightTrait, &weight)) {
  2074         weight = 0;
  2076     if (!find_dict_float(dict, kCTFontWidthTrait, &width)) {
  2077         width = 0;
  2079     if (!find_dict_float(dict, kCTFontSlantTrait, &slant)) {
  2080         slant = 0;
  2083     return SkFontStyle(unit_weight_to_fontstyle(weight),
  2084                        unit_width_to_fontstyle(width),
  2085                        slant ? SkFontStyle::kItalic_Slant
  2086                        : SkFontStyle::kUpright_Slant);
  2089 struct NameFontStyleRec {
  2090     SkString    fFamilyName;
  2091     SkFontStyle fFontStyle;
  2092 };
  2094 static bool nameFontStyleProc(SkTypeface* face, SkTypeface::Style,
  2095                               void* ctx) {
  2096     SkTypeface_Mac* macFace = (SkTypeface_Mac*)face;
  2097     const NameFontStyleRec* rec = (const NameFontStyleRec*)ctx;
  2099     return macFace->fFontStyle == rec->fFontStyle &&
  2100            macFace->fName == rec->fFamilyName;
  2103 static SkTypeface* createFromDesc(CFStringRef cfFamilyName,
  2104                                   CTFontDescriptorRef desc) {
  2105     NameFontStyleRec rec;
  2106     CFStringToSkString(cfFamilyName, &rec.fFamilyName);
  2107     rec.fFontStyle = desc2fontstyle(desc);
  2109     SkTypeface* face = SkTypefaceCache::FindByProcAndRef(nameFontStyleProc,
  2110                                                          &rec);
  2111     if (face) {
  2112         return face;
  2115     AutoCFRelease<CFDictionaryRef> fontFamilyNameDictionary(
  2116         CFDictionaryCreate(kCFAllocatorDefault,
  2117                            (const void**)&kCTFontFamilyNameAttribute, (const void**)&cfFamilyName,
  2118                            1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
  2119     AutoCFRelease<CTFontDescriptorRef> fontDescriptor(
  2120         CTFontDescriptorCreateWithAttributes(fontFamilyNameDictionary));
  2121     AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithFontDescriptor(fontDescriptor, 0, NULL));
  2122     CTFontRef ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL, desc);
  2123     if (NULL == ctFont) {
  2124         return NULL;
  2127     SkString str;
  2128     CFStringToSkString(cfFamilyName, &str);
  2130     bool isFixedPitch;
  2131     (void)computeStyleBits(ctFont, &isFixedPitch);
  2132     SkFontID fontID = CTFontRef_to_SkFontID(ctFont);
  2134     face = SkNEW_ARGS(SkTypeface_Mac, (rec.fFontStyle, fontID, isFixedPitch,
  2135                                        ctFont, str.c_str()));
  2136     SkTypefaceCache::Add(face, face->style());
  2137     return face;
  2140 class SkFontStyleSet_Mac : public SkFontStyleSet {
  2141 public:
  2142     SkFontStyleSet_Mac(CFStringRef familyName, CTFontDescriptorRef desc)
  2143         : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, NULL))
  2144         , fFamilyName(familyName)
  2145         , fCount(0) {
  2146         CFRetain(familyName);
  2147         if (NULL == fArray) {
  2148             fArray = CFArrayCreate(NULL, NULL, 0, NULL);
  2150         fCount = SkToInt(CFArrayGetCount(fArray));
  2153     virtual ~SkFontStyleSet_Mac() {
  2154         CFRelease(fArray);
  2155         CFRelease(fFamilyName);
  2158     virtual int count() SK_OVERRIDE {
  2159         return fCount;
  2162     virtual void getStyle(int index, SkFontStyle* style,
  2163                           SkString* name) SK_OVERRIDE {
  2164         SkASSERT((unsigned)index < (unsigned)fCount);
  2165         CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
  2166         if (style) {
  2167             *style = desc2fontstyle(desc);
  2169         if (name) {
  2170             if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
  2171                 name->reset();
  2176     virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
  2177         SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray));
  2178         CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
  2180         return createFromDesc(fFamilyName, desc);
  2183     virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
  2184         if (0 == fCount) {
  2185             return NULL;
  2187         return createFromDesc(fFamilyName, findMatchingDesc(pattern));
  2190 private:
  2191     CFArrayRef  fArray;
  2192     CFStringRef fFamilyName;
  2193     int         fCount;
  2195     CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
  2196         int bestMetric = SK_MaxS32;
  2197         CTFontDescriptorRef bestDesc = NULL;
  2199         for (int i = 0; i < fCount; ++i) {
  2200             CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, i);
  2201             int metric = compute_metric(pattern, desc2fontstyle(desc));
  2202             if (0 == metric) {
  2203                 return desc;
  2205             if (metric < bestMetric) {
  2206                 bestMetric = metric;
  2207                 bestDesc = desc;
  2210         SkASSERT(bestDesc);
  2211         return bestDesc;
  2213 };
  2215 class SkFontMgr_Mac : public SkFontMgr {
  2216     CFArrayRef  fNames;
  2217     int         fCount;
  2219     CFStringRef stringAt(int index) const {
  2220         SkASSERT((unsigned)index < (unsigned)fCount);
  2221         return (CFStringRef)CFArrayGetValueAtIndex(fNames, index);
  2224     static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) {
  2225         AutoCFRelease<CFMutableDictionaryRef> cfAttr(
  2226                  CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
  2227                                            &kCFTypeDictionaryKeyCallBacks,
  2228                                            &kCFTypeDictionaryValueCallBacks));
  2230         CFDictionaryAddValue(cfAttr, kCTFontFamilyNameAttribute, cfFamilyName);
  2232         AutoCFRelease<CTFontDescriptorRef> desc(
  2233                                 CTFontDescriptorCreateWithAttributes(cfAttr));
  2234         return SkNEW_ARGS(SkFontStyleSet_Mac, (cfFamilyName, desc));
  2237 public:
  2238     SkFontMgr_Mac()
  2239         : fNames(SkCTFontManagerCopyAvailableFontFamilyNames())
  2240         , fCount(fNames ? SkToInt(CFArrayGetCount(fNames)) : 0) {}
  2242     virtual ~SkFontMgr_Mac() {
  2243         CFSafeRelease(fNames);
  2246 protected:
  2247     virtual int onCountFamilies() const SK_OVERRIDE {
  2248         return fCount;
  2251     virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
  2252         if ((unsigned)index < (unsigned)fCount) {
  2253             CFStringToSkString(this->stringAt(index), familyName);
  2254         } else {
  2255             familyName->reset();
  2259     virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
  2260         if ((unsigned)index >= (unsigned)fCount) {
  2261             return NULL;
  2263         return CreateSet(this->stringAt(index));
  2266     virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
  2267         AutoCFRelease<CFStringRef> cfName(make_CFString(familyName));
  2268         return CreateSet(cfName);
  2271     virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
  2272                                            const SkFontStyle&) const SK_OVERRIDE {
  2273         return NULL;
  2276     virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
  2277                                          const SkFontStyle&) const SK_OVERRIDE {
  2278         return NULL;
  2281     virtual SkTypeface* onCreateFromData(SkData* data,
  2282                                          int ttcIndex) const SK_OVERRIDE {
  2283         AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromData(data));
  2284         if (NULL == pr) {
  2285             return NULL;
  2287         return create_from_dataProvider(pr);
  2290     virtual SkTypeface* onCreateFromStream(SkStream* stream,
  2291                                            int ttcIndex) const SK_OVERRIDE {
  2292         AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromStream(stream));
  2293         if (NULL == pr) {
  2294             return NULL;
  2296         return create_from_dataProvider(pr);
  2299     virtual SkTypeface* onCreateFromFile(const char path[],
  2300                                          int ttcIndex) const SK_OVERRIDE {
  2301         AutoCFRelease<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path));
  2302         if (NULL == pr) {
  2303             return NULL;
  2305         return create_from_dataProvider(pr);
  2308     virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
  2309                                                unsigned styleBits) const SK_OVERRIDE {
  2310         return create_typeface(NULL, familyName, (SkTypeface::Style)styleBits);
  2312 };
  2314 ///////////////////////////////////////////////////////////////////////////////
  2316 SkFontMgr* SkFontMgr::Factory() {
  2317     return SkNEW(SkFontMgr_Mac);
  2319 #endif
  2321 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
  2322                                        const char famillyName[],
  2323                                        SkTypeface::Style style)
  2325     SkDEBUGFAIL("SkFontHost::FindTypeface unimplemented");
  2326     return NULL;
  2329 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream*)
  2331     SkDEBUGFAIL("SkFontHost::CreateTypeface unimplemented");
  2332     return NULL;
  2335 SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*)
  2337     SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
  2338     return NULL;

mercurial