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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/ports/SkFontHost_mac.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2340 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2006 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +#include <vector>
    1.13 +#ifdef SK_BUILD_FOR_MAC
    1.14 +#import <ApplicationServices/ApplicationServices.h>
    1.15 +#endif
    1.16 +
    1.17 +#ifdef SK_BUILD_FOR_IOS
    1.18 +#include <CoreText/CoreText.h>
    1.19 +#include <CoreText/CTFontManager.h>
    1.20 +#include <CoreGraphics/CoreGraphics.h>
    1.21 +#include <CoreFoundation/CoreFoundation.h>
    1.22 +#endif
    1.23 +
    1.24 +#include "SkFontHost.h"
    1.25 +#include "SkCGUtils.h"
    1.26 +#include "SkColorPriv.h"
    1.27 +#include "SkDescriptor.h"
    1.28 +#include "SkEndian.h"
    1.29 +#include "SkFontDescriptor.h"
    1.30 +#include "SkFloatingPoint.h"
    1.31 +#include "SkGlyph.h"
    1.32 +#include "SkMaskGamma.h"
    1.33 +#include "SkSFNTHeader.h"
    1.34 +#include "SkOTTable_glyf.h"
    1.35 +#include "SkOTTable_head.h"
    1.36 +#include "SkOTTable_hhea.h"
    1.37 +#include "SkOTTable_loca.h"
    1.38 +#include "SkOTUtils.h"
    1.39 +#include "SkPaint.h"
    1.40 +#include "SkPath.h"
    1.41 +#include "SkString.h"
    1.42 +#include "SkStream.h"
    1.43 +#include "SkThread.h"
    1.44 +#include "SkTypeface_mac.h"
    1.45 +#include "SkUtils.h"
    1.46 +#include "SkTypefaceCache.h"
    1.47 +#include "SkFontMgr.h"
    1.48 +#include "SkUtils.h"
    1.49 +
    1.50 +//#define HACK_COLORGLYPHS
    1.51 +
    1.52 +class SkScalerContext_Mac;
    1.53 +
    1.54 +// CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we
    1.55 +// provide a wrapper here that will return an empty array if need be.
    1.56 +static CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() {
    1.57 +#ifdef SK_BUILD_FOR_IOS
    1.58 +    return CFArrayCreate(NULL, NULL, 0, NULL);
    1.59 +#else
    1.60 +    return CTFontManagerCopyAvailableFontFamilyNames();
    1.61 +#endif
    1.62 +}
    1.63 +
    1.64 +
    1.65 +// Being templated and taking const T* prevents calling
    1.66 +// CFSafeRelease(autoCFRelease) through implicit conversion.
    1.67 +template <typename T> static void CFSafeRelease(/*CFTypeRef*/const T* cfTypeRef) {
    1.68 +    if (cfTypeRef) {
    1.69 +        CFRelease(cfTypeRef);
    1.70 +    }
    1.71 +}
    1.72 +
    1.73 +// Being templated and taking const T* prevents calling
    1.74 +// CFSafeRetain(autoCFRelease) through implicit conversion.
    1.75 +template <typename T> static void CFSafeRetain(/*CFTypeRef*/const T* cfTypeRef) {
    1.76 +    if (cfTypeRef) {
    1.77 +        CFRetain(cfTypeRef);
    1.78 +    }
    1.79 +}
    1.80 +
    1.81 +/** Acts like a CFRef, but calls CFSafeRelease when it goes out of scope. */
    1.82 +template<typename CFRef> class AutoCFRelease : private SkNoncopyable {
    1.83 +public:
    1.84 +    explicit AutoCFRelease(CFRef cfRef = NULL) : fCFRef(cfRef) { }
    1.85 +    ~AutoCFRelease() { CFSafeRelease(fCFRef); }
    1.86 +
    1.87 +    void reset(CFRef that = NULL) {
    1.88 +        CFSafeRetain(that);
    1.89 +        CFSafeRelease(fCFRef);
    1.90 +        fCFRef = that;
    1.91 +    }
    1.92 +
    1.93 +    AutoCFRelease& operator =(CFRef that) {
    1.94 +        reset(that);
    1.95 +        return *this;
    1.96 +    }
    1.97 +
    1.98 +    operator CFRef() const { return fCFRef; }
    1.99 +    CFRef get() const { return fCFRef; }
   1.100 +
   1.101 +    CFRef* operator&() { SkASSERT(fCFRef == NULL); return &fCFRef; }
   1.102 +private:
   1.103 +    CFRef fCFRef;
   1.104 +};
   1.105 +
   1.106 +static CFStringRef make_CFString(const char str[]) {
   1.107 +    return CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
   1.108 +}
   1.109 +
   1.110 +template<typename T> class AutoCGTable : SkNoncopyable {
   1.111 +public:
   1.112 +    AutoCGTable(CGFontRef font)
   1.113 +    //Undocumented: the tag parameter in this call is expected in machine order and not BE order.
   1.114 +    : fCFData(CGFontCopyTableForTag(font, SkSetFourByteTag(T::TAG0, T::TAG1, T::TAG2, T::TAG3)))
   1.115 +    , fData(fCFData ? reinterpret_cast<const T*>(CFDataGetBytePtr(fCFData)) : NULL)
   1.116 +    { }
   1.117 +
   1.118 +    const T* operator->() const { return fData; }
   1.119 +
   1.120 +private:
   1.121 +    AutoCFRelease<CFDataRef> fCFData;
   1.122 +public:
   1.123 +    const T* fData;
   1.124 +};
   1.125 +
   1.126 +// inline versions of these rect helpers
   1.127 +
   1.128 +static bool CGRectIsEmpty_inline(const CGRect& rect) {
   1.129 +    return rect.size.width <= 0 || rect.size.height <= 0;
   1.130 +}
   1.131 +
   1.132 +static CGFloat CGRectGetMinX_inline(const CGRect& rect) {
   1.133 +    return rect.origin.x;
   1.134 +}
   1.135 +
   1.136 +static CGFloat CGRectGetMaxX_inline(const CGRect& rect) {
   1.137 +    return rect.origin.x + rect.size.width;
   1.138 +}
   1.139 +
   1.140 +static CGFloat CGRectGetMinY_inline(const CGRect& rect) {
   1.141 +    return rect.origin.y;
   1.142 +}
   1.143 +
   1.144 +static CGFloat CGRectGetMaxY_inline(const CGRect& rect) {
   1.145 +    return rect.origin.y + rect.size.height;
   1.146 +}
   1.147 +
   1.148 +static CGFloat CGRectGetWidth_inline(const CGRect& rect) {
   1.149 +    return rect.size.width;
   1.150 +}
   1.151 +
   1.152 +///////////////////////////////////////////////////////////////////////////////
   1.153 +
   1.154 +static void sk_memset_rect32(uint32_t* ptr, uint32_t value,
   1.155 +                             int width, int height, size_t rowBytes) {
   1.156 +    SkASSERT(width);
   1.157 +    SkASSERT(width * sizeof(uint32_t) <= rowBytes);
   1.158 +
   1.159 +    if (width >= 32) {
   1.160 +        while (height) {
   1.161 +            sk_memset32(ptr, value, width);
   1.162 +            ptr = (uint32_t*)((char*)ptr + rowBytes);
   1.163 +            height -= 1;
   1.164 +        }
   1.165 +        return;
   1.166 +    }
   1.167 +
   1.168 +    rowBytes -= width * sizeof(uint32_t);
   1.169 +
   1.170 +    if (width >= 8) {
   1.171 +        while (height) {
   1.172 +            int w = width;
   1.173 +            do {
   1.174 +                *ptr++ = value; *ptr++ = value;
   1.175 +                *ptr++ = value; *ptr++ = value;
   1.176 +                *ptr++ = value; *ptr++ = value;
   1.177 +                *ptr++ = value; *ptr++ = value;
   1.178 +                w -= 8;
   1.179 +            } while (w >= 8);
   1.180 +            while (--w >= 0) {
   1.181 +                *ptr++ = value;
   1.182 +            }
   1.183 +            ptr = (uint32_t*)((char*)ptr + rowBytes);
   1.184 +            height -= 1;
   1.185 +        }
   1.186 +    } else {
   1.187 +        while (height) {
   1.188 +            int w = width;
   1.189 +            do {
   1.190 +                *ptr++ = value;
   1.191 +            } while (--w > 0);
   1.192 +            ptr = (uint32_t*)((char*)ptr + rowBytes);
   1.193 +            height -= 1;
   1.194 +        }
   1.195 +    }
   1.196 +}
   1.197 +
   1.198 +#include <sys/utsname.h>
   1.199 +
   1.200 +typedef uint32_t CGRGBPixel;
   1.201 +
   1.202 +static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) {
   1.203 +    return pixel & 0xFF;
   1.204 +}
   1.205 +
   1.206 +// The calls to support subpixel are present in 10.5, but are not included in
   1.207 +// the 10.5 SDK. The needed calls have been extracted from the 10.6 SDK and are
   1.208 +// included below. To verify that CGContextSetShouldSubpixelQuantizeFonts, for
   1.209 +// instance, is present in the 10.5 CoreGraphics libary, use:
   1.210 +//   cd /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/
   1.211 +//   cd ApplicationServices.framework/Frameworks/CoreGraphics.framework/
   1.212 +//   nm CoreGraphics | grep CGContextSetShouldSubpixelQuantizeFonts
   1.213 +
   1.214 +#if !defined(MAC_OS_X_VERSION_10_6) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6)
   1.215 +CG_EXTERN void CGContextSetAllowsFontSmoothing(CGContextRef context, bool value);
   1.216 +CG_EXTERN void CGContextSetAllowsFontSubpixelPositioning(CGContextRef context, bool value);
   1.217 +CG_EXTERN void CGContextSetShouldSubpixelPositionFonts(CGContextRef context, bool value);
   1.218 +CG_EXTERN void CGContextSetAllowsFontSubpixelQuantization(CGContextRef context, bool value);
   1.219 +CG_EXTERN void CGContextSetShouldSubpixelQuantizeFonts(CGContextRef context, bool value);
   1.220 +#endif
   1.221 +
   1.222 +static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
   1.223 +
   1.224 +// See Source/WebKit/chromium/base/mac/mac_util.mm DarwinMajorVersionInternal for original source.
   1.225 +static int readVersion() {
   1.226 +    struct utsname info;
   1.227 +    if (uname(&info) != 0) {
   1.228 +        SkDebugf("uname failed\n");
   1.229 +        return 0;
   1.230 +    }
   1.231 +    if (strcmp(info.sysname, "Darwin") != 0) {
   1.232 +        SkDebugf("unexpected uname sysname %s\n", info.sysname);
   1.233 +        return 0;
   1.234 +    }
   1.235 +    char* dot = strchr(info.release, '.');
   1.236 +    if (!dot) {
   1.237 +        SkDebugf("expected dot in uname release %s\n", info.release);
   1.238 +        return 0;
   1.239 +    }
   1.240 +    int version = atoi(info.release);
   1.241 +    if (version == 0) {
   1.242 +        SkDebugf("could not parse uname release %s\n", info.release);
   1.243 +    }
   1.244 +    return version;
   1.245 +}
   1.246 +
   1.247 +static int darwinVersion() {
   1.248 +    static int darwin_version = readVersion();
   1.249 +    return darwin_version;
   1.250 +}
   1.251 +
   1.252 +static bool isSnowLeopard() {
   1.253 +    return darwinVersion() == 10;
   1.254 +}
   1.255 +
   1.256 +static bool isLion() {
   1.257 +    return darwinVersion() == 11;
   1.258 +}
   1.259 +
   1.260 +static bool isMountainLion() {
   1.261 +    return darwinVersion() == 12;
   1.262 +}
   1.263 +
   1.264 +static bool isLCDFormat(unsigned format) {
   1.265 +    return SkMask::kLCD16_Format == format || SkMask::kLCD32_Format == format;
   1.266 +}
   1.267 +
   1.268 +static CGFloat ScalarToCG(SkScalar scalar) {
   1.269 +    if (sizeof(CGFloat) == sizeof(float)) {
   1.270 +        return SkScalarToFloat(scalar);
   1.271 +    } else {
   1.272 +        SkASSERT(sizeof(CGFloat) == sizeof(double));
   1.273 +        return (CGFloat) SkScalarToDouble(scalar);
   1.274 +    }
   1.275 +}
   1.276 +
   1.277 +static SkScalar CGToScalar(CGFloat cgFloat) {
   1.278 +    if (sizeof(CGFloat) == sizeof(float)) {
   1.279 +        return cgFloat;
   1.280 +    } else {
   1.281 +        SkASSERT(sizeof(CGFloat) == sizeof(double));
   1.282 +        return SkDoubleToScalar(cgFloat);
   1.283 +    }
   1.284 +}
   1.285 +
   1.286 +static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix,
   1.287 +                                                   SkScalar sx = SK_Scalar1,
   1.288 +                                                   SkScalar sy = SK_Scalar1) {
   1.289 +    return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx),
   1.290 +                                 -ScalarToCG(matrix[SkMatrix::kMSkewY]  * sy),
   1.291 +                                 -ScalarToCG(matrix[SkMatrix::kMSkewX]  * sx),
   1.292 +                                  ScalarToCG(matrix[SkMatrix::kMScaleY] * sy),
   1.293 +                                  ScalarToCG(matrix[SkMatrix::kMTransX] * sx),
   1.294 +                                  ScalarToCG(matrix[SkMatrix::kMTransY] * sy));
   1.295 +}
   1.296 +
   1.297 +///////////////////////////////////////////////////////////////////////////////
   1.298 +
   1.299 +#define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
   1.300 +#define BITMAP_INFO_GRAY (kCGImageAlphaNone)
   1.301 +
   1.302 +/**
   1.303 + * There does not appear to be a publicly accessable API for determining if lcd
   1.304 + * font smoothing will be applied if we request it. The main issue is that if
   1.305 + * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0.
   1.306 + */
   1.307 +static bool supports_LCD() {
   1.308 +    static int gSupportsLCD = -1;
   1.309 +    if (gSupportsLCD >= 0) {
   1.310 +        return (bool) gSupportsLCD;
   1.311 +    }
   1.312 +    uint32_t rgb = 0;
   1.313 +    AutoCFRelease<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
   1.314 +    AutoCFRelease<CGContextRef> cgContext(CGBitmapContextCreate(&rgb, 1, 1, 8, 4,
   1.315 +                                                                colorspace, BITMAP_INFO_RGB));
   1.316 +    CGContextSelectFont(cgContext, "Helvetica", 16, kCGEncodingMacRoman);
   1.317 +    CGContextSetShouldSmoothFonts(cgContext, true);
   1.318 +    CGContextSetShouldAntialias(cgContext, true);
   1.319 +    CGContextSetTextDrawingMode(cgContext, kCGTextFill);
   1.320 +    CGContextSetGrayFillColor(cgContext, 1, 1);
   1.321 +    CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1);
   1.322 +    uint32_t r = (rgb >> 16) & 0xFF;
   1.323 +    uint32_t g = (rgb >>  8) & 0xFF;
   1.324 +    uint32_t b = (rgb >>  0) & 0xFF;
   1.325 +    gSupportsLCD = (r != g || r != b);
   1.326 +    return (bool) gSupportsLCD;
   1.327 +}
   1.328 +
   1.329 +class Offscreen {
   1.330 +public:
   1.331 +    Offscreen();
   1.332 +
   1.333 +    CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
   1.334 +                      CGGlyph glyphID, size_t* rowBytesPtr,
   1.335 +                      bool generateA8FromLCD);
   1.336 +
   1.337 +private:
   1.338 +    enum {
   1.339 +        kSize = 32 * 32 * sizeof(CGRGBPixel)
   1.340 +    };
   1.341 +    SkAutoSMalloc<kSize> fImageStorage;
   1.342 +    AutoCFRelease<CGColorSpaceRef> fRGBSpace;
   1.343 +
   1.344 +    // cached state
   1.345 +    AutoCFRelease<CGContextRef> fCG;
   1.346 +    SkISize fSize;
   1.347 +    bool fDoAA;
   1.348 +    bool fDoLCD;
   1.349 +
   1.350 +    static int RoundSize(int dimension) {
   1.351 +        return SkNextPow2(dimension);
   1.352 +    }
   1.353 +};
   1.354 +
   1.355 +Offscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL),
   1.356 +                         fDoAA(false), fDoLCD(false) {
   1.357 +    fSize.set(0, 0);
   1.358 +}
   1.359 +
   1.360 +///////////////////////////////////////////////////////////////////////////////
   1.361 +
   1.362 +static SkTypeface::Style computeStyleBits(CTFontRef font, bool* isFixedPitch) {
   1.363 +    unsigned style = SkTypeface::kNormal;
   1.364 +    CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font);
   1.365 +
   1.366 +    if (traits & kCTFontBoldTrait) {
   1.367 +        style |= SkTypeface::kBold;
   1.368 +    }
   1.369 +    if (traits & kCTFontItalicTrait) {
   1.370 +        style |= SkTypeface::kItalic;
   1.371 +    }
   1.372 +    if (isFixedPitch) {
   1.373 +        *isFixedPitch = (traits & kCTFontMonoSpaceTrait) != 0;
   1.374 +    }
   1.375 +    return (SkTypeface::Style)style;
   1.376 +}
   1.377 +
   1.378 +static SkFontID CTFontRef_to_SkFontID(CTFontRef fontRef) {
   1.379 +    SkFontID id = 0;
   1.380 +// CTFontGetPlatformFont and ATSFontRef are not supported on iOS, so we have to
   1.381 +// bracket this to be Mac only.
   1.382 +#ifdef SK_BUILD_FOR_MAC
   1.383 +    ATSFontRef ats = CTFontGetPlatformFont(fontRef, NULL);
   1.384 +    id = (SkFontID)ats;
   1.385 +    if (id != 0) {
   1.386 +        id &= 0x3FFFFFFF; // make top two bits 00
   1.387 +        return id;
   1.388 +    }
   1.389 +#endif
   1.390 +    // CTFontGetPlatformFont returns NULL if the font is local
   1.391 +    // (e.g., was created by a CSS3 @font-face rule).
   1.392 +    AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fontRef, NULL));
   1.393 +    AutoCGTable<SkOTTableHead> headTable(cgFont);
   1.394 +    if (headTable.fData) {
   1.395 +        id = (SkFontID) headTable->checksumAdjustment;
   1.396 +        id = (id & 0x3FFFFFFF) | 0x40000000; // make top two bits 01
   1.397 +    }
   1.398 +    // well-formed fonts have checksums, but as a last resort, use the pointer.
   1.399 +    if (id == 0) {
   1.400 +        id = (SkFontID) (uintptr_t) fontRef;
   1.401 +        id = (id & 0x3FFFFFFF) | 0x80000000; // make top two bits 10
   1.402 +    }
   1.403 +    return id;
   1.404 +}
   1.405 +
   1.406 +static SkFontStyle stylebits2fontstyle(SkTypeface::Style styleBits) {
   1.407 +    return SkFontStyle((styleBits & SkTypeface::kBold)
   1.408 +                           ? SkFontStyle::kBold_Weight
   1.409 +                           : SkFontStyle::kNormal_Weight,
   1.410 +                       SkFontStyle::kNormal_Width,
   1.411 +                       (styleBits & SkTypeface::kItalic)
   1.412 +                           ? SkFontStyle::kItalic_Slant
   1.413 +                           : SkFontStyle::kUpright_Slant);
   1.414 +}
   1.415 +
   1.416 +#define WEIGHT_THRESHOLD    ((SkFontStyle::kNormal_Weight + SkFontStyle::kBold_Weight)/2)
   1.417 +
   1.418 +static SkTypeface::Style fontstyle2stylebits(const SkFontStyle& fs) {
   1.419 +    unsigned style = 0;
   1.420 +    if (fs.width() >= WEIGHT_THRESHOLD) {
   1.421 +        style |= SkTypeface::kBold;
   1.422 +    }
   1.423 +    if (fs.isItalic()) {
   1.424 +        style |= SkTypeface::kItalic;
   1.425 +    }
   1.426 +    return (SkTypeface::Style)style;
   1.427 +}
   1.428 +
   1.429 +class SkTypeface_Mac : public SkTypeface {
   1.430 +public:
   1.431 +    SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isFixedPitch,
   1.432 +                   CTFontRef fontRef, const char name[])
   1.433 +        : SkTypeface(style, fontID, isFixedPitch)
   1.434 +        , fName(name)
   1.435 +        , fFontRef(fontRef) // caller has already called CFRetain for us
   1.436 +        , fFontStyle(stylebits2fontstyle(style))
   1.437 +    {
   1.438 +        SkASSERT(fontRef);
   1.439 +    }
   1.440 +
   1.441 +    SkTypeface_Mac(const SkFontStyle& fs, SkFontID fontID, bool isFixedPitch,
   1.442 +                   CTFontRef fontRef, const char name[])
   1.443 +        : SkTypeface(fontstyle2stylebits(fs), fontID, isFixedPitch)
   1.444 +        , fName(name)
   1.445 +        , fFontRef(fontRef) // caller has already called CFRetain for us
   1.446 +        , fFontStyle(fs)
   1.447 +    {
   1.448 +        SkASSERT(fontRef);
   1.449 +    }
   1.450 +
   1.451 +    SkString fName;
   1.452 +    AutoCFRelease<CTFontRef> fFontRef;
   1.453 +    SkFontStyle fFontStyle;
   1.454 +
   1.455 +protected:
   1.456 +    friend class SkFontHost;    // to access our protected members for deprecated methods
   1.457 +
   1.458 +    virtual int onGetUPEM() const SK_OVERRIDE;
   1.459 +    virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
   1.460 +    virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
   1.461 +    virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
   1.462 +    virtual size_t onGetTableData(SkFontTableTag, size_t offset,
   1.463 +                                  size_t length, void* data) const SK_OVERRIDE;
   1.464 +    virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
   1.465 +    virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
   1.466 +    virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
   1.467 +    virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
   1.468 +                                SkAdvancedTypefaceMetrics::PerGlyphInfo,
   1.469 +                                const uint32_t*, uint32_t) const SK_OVERRIDE;
   1.470 +    virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[],
   1.471 +                                int glyphCount) const SK_OVERRIDE;
   1.472 +    virtual int onCountGlyphs() const SK_OVERRIDE;
   1.473 +
   1.474 +private:
   1.475 +
   1.476 +    typedef SkTypeface INHERITED;
   1.477 +};
   1.478 +
   1.479 +static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) {
   1.480 +    SkASSERT(fontRef);
   1.481 +    bool isFixedPitch;
   1.482 +    SkTypeface::Style style = computeStyleBits(fontRef, &isFixedPitch);
   1.483 +    SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
   1.484 +
   1.485 +    return new SkTypeface_Mac(style, fontID, isFixedPitch, fontRef, name);
   1.486 +}
   1.487 +
   1.488 +static SkTypeface* NewFromName(const char familyName[], SkTypeface::Style theStyle) {
   1.489 +    CTFontRef ctFont = NULL;
   1.490 +
   1.491 +    CTFontSymbolicTraits ctFontTraits = 0;
   1.492 +    if (theStyle & SkTypeface::kBold) {
   1.493 +        ctFontTraits |= kCTFontBoldTrait;
   1.494 +    }
   1.495 +    if (theStyle & SkTypeface::kItalic) {
   1.496 +        ctFontTraits |= kCTFontItalicTrait;
   1.497 +    }
   1.498 +
   1.499 +    // Create the font info
   1.500 +    AutoCFRelease<CFStringRef> cfFontName(make_CFString(familyName));
   1.501 +
   1.502 +    AutoCFRelease<CFNumberRef> cfFontTraits(
   1.503 +            CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits));
   1.504 +
   1.505 +    AutoCFRelease<CFMutableDictionaryRef> cfAttributes(
   1.506 +            CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
   1.507 +                                      &kCFTypeDictionaryKeyCallBacks,
   1.508 +                                      &kCFTypeDictionaryValueCallBacks));
   1.509 +
   1.510 +    AutoCFRelease<CFMutableDictionaryRef> cfTraits(
   1.511 +            CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
   1.512 +                                      &kCFTypeDictionaryKeyCallBacks,
   1.513 +                                      &kCFTypeDictionaryValueCallBacks));
   1.514 +
   1.515 +    // Create the font
   1.516 +    if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) {
   1.517 +        CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits);
   1.518 +
   1.519 +        CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName);
   1.520 +        CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits);
   1.521 +
   1.522 +        AutoCFRelease<CTFontDescriptorRef> ctFontDesc(
   1.523 +                CTFontDescriptorCreateWithAttributes(cfAttributes));
   1.524 +
   1.525 +        if (ctFontDesc != NULL) {
   1.526 +            ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL);
   1.527 +        }
   1.528 +    }
   1.529 +
   1.530 +    return ctFont ? NewFromFontRef(ctFont, familyName) : NULL;
   1.531 +}
   1.532 +
   1.533 +static SkTypeface* GetDefaultFace() {
   1.534 +    SK_DECLARE_STATIC_MUTEX(gMutex);
   1.535 +    SkAutoMutexAcquire ma(gMutex);
   1.536 +
   1.537 +    static SkTypeface* gDefaultFace;
   1.538 +
   1.539 +    if (NULL == gDefaultFace) {
   1.540 +        gDefaultFace = NewFromName(FONT_DEFAULT_NAME, SkTypeface::kNormal);
   1.541 +        SkTypefaceCache::Add(gDefaultFace, SkTypeface::kNormal);
   1.542 +    }
   1.543 +    return gDefaultFace;
   1.544 +}
   1.545 +
   1.546 +///////////////////////////////////////////////////////////////////////////////
   1.547 +
   1.548 +extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face);
   1.549 +CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) {
   1.550 +    const SkTypeface_Mac* macface = (const SkTypeface_Mac*)face;
   1.551 +    return macface ? macface->fFontRef.get() : NULL;
   1.552 +}
   1.553 +
   1.554 +/*  This function is visible on the outside. It first searches the cache, and if
   1.555 + *  not found, returns a new entry (after adding it to the cache).
   1.556 + */
   1.557 +SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) {
   1.558 +    SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
   1.559 +    SkTypeface* face = SkTypefaceCache::FindByID(fontID);
   1.560 +    if (face) {
   1.561 +        face->ref();
   1.562 +    } else {
   1.563 +        face = NewFromFontRef(fontRef, NULL);
   1.564 +        SkTypefaceCache::Add(face, face->style());
   1.565 +        // NewFromFontRef doesn't retain the parameter, but the typeface it
   1.566 +        // creates does release it in its destructor, so we balance that with
   1.567 +        // a retain call here.
   1.568 +        CFRetain(fontRef);
   1.569 +    }
   1.570 +    SkASSERT(face->getRefCnt() > 1);
   1.571 +    return face;
   1.572 +}
   1.573 +
   1.574 +struct NameStyleRec {
   1.575 +    const char*         fName;
   1.576 +    SkTypeface::Style   fStyle;
   1.577 +};
   1.578 +
   1.579 +static bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style,
   1.580 +                            void* ctx) {
   1.581 +    const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
   1.582 +    const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx);
   1.583 +
   1.584 +    return rec->fStyle == style && mface->fName.equals(rec->fName);
   1.585 +}
   1.586 +
   1.587 +static const char* map_css_names(const char* name) {
   1.588 +    static const struct {
   1.589 +        const char* fFrom;  // name the caller specified
   1.590 +        const char* fTo;    // "canonical" name we map to
   1.591 +    } gPairs[] = {
   1.592 +        { "sans-serif", "Helvetica" },
   1.593 +        { "serif",      "Times"     },
   1.594 +        { "monospace",  "Courier"   }
   1.595 +    };
   1.596 +
   1.597 +    for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
   1.598 +        if (strcmp(name, gPairs[i].fFrom) == 0) {
   1.599 +            return gPairs[i].fTo;
   1.600 +        }
   1.601 +    }
   1.602 +    return name;    // no change
   1.603 +}
   1.604 +
   1.605 +static SkTypeface* create_typeface(const SkTypeface* familyFace,
   1.606 +                                   const char familyName[],
   1.607 +                                   SkTypeface::Style style) {
   1.608 +    if (familyName) {
   1.609 +        familyName = map_css_names(familyName);
   1.610 +    }
   1.611 +
   1.612 +    // Clone an existing typeface
   1.613 +    // TODO: only clone if style matches the familyFace's style...
   1.614 +    if (familyName == NULL && familyFace != NULL) {
   1.615 +        familyFace->ref();
   1.616 +        return const_cast<SkTypeface*>(familyFace);
   1.617 +    }
   1.618 +
   1.619 +    if (!familyName || !*familyName) {
   1.620 +        familyName = FONT_DEFAULT_NAME;
   1.621 +    }
   1.622 +
   1.623 +    NameStyleRec rec = { familyName, style };
   1.624 +    SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByNameStyle, &rec);
   1.625 +
   1.626 +    if (NULL == face) {
   1.627 +        face = NewFromName(familyName, style);
   1.628 +        if (face) {
   1.629 +            SkTypefaceCache::Add(face, style);
   1.630 +        } else {
   1.631 +            face = GetDefaultFace();
   1.632 +            face->ref();
   1.633 +        }
   1.634 +    }
   1.635 +    return face;
   1.636 +}
   1.637 +
   1.638 +///////////////////////////////////////////////////////////////////////////////
   1.639 +
   1.640 +/** GlyphRect is in FUnits (em space, y up). */
   1.641 +struct GlyphRect {
   1.642 +    int16_t fMinX;
   1.643 +    int16_t fMinY;
   1.644 +    int16_t fMaxX;
   1.645 +    int16_t fMaxY;
   1.646 +};
   1.647 +
   1.648 +class SkScalerContext_Mac : public SkScalerContext {
   1.649 +public:
   1.650 +    SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*);
   1.651 +
   1.652 +protected:
   1.653 +    unsigned generateGlyphCount(void) SK_OVERRIDE;
   1.654 +    uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
   1.655 +    void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
   1.656 +    void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
   1.657 +    void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
   1.658 +    void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
   1.659 +    void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE;
   1.660 +
   1.661 +private:
   1.662 +    static void CTPathElement(void *info, const CGPathElement *element);
   1.663 +
   1.664 +    /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */
   1.665 +    void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const;
   1.666 +
   1.667 +    /** Initializes and returns the value of fFBoundingBoxesGlyphOffset.
   1.668 +     *
   1.669 +     *  For use with (and must be called before) generateBBoxes.
   1.670 +     */
   1.671 +    uint16_t getFBoundingBoxesGlyphOffset();
   1.672 +
   1.673 +    /** Initializes fFBoundingBoxes and returns true on success.
   1.674 +     *
   1.675 +     *  On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
   1.676 +     *  return a bad value in bounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
   1.677 +     *  less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
   1.678 +     *  font directly.
   1.679 +     *
   1.680 +     *  This routine initializes fFBoundingBoxes to an array of
   1.681 +     *  fGlyphCount - fFBoundingBoxesGlyphOffset GlyphRects which contain the bounds in FUnits
   1.682 +     *  (em space, y up) of glyphs with ids in the range [fFBoundingBoxesGlyphOffset, fGlyphCount).
   1.683 +     *
   1.684 +     *  Returns true if fFBoundingBoxes is properly initialized. The table can only be properly
   1.685 +     *  initialized for a TrueType font with 'head', 'loca', and 'glyf' tables.
   1.686 +     *
   1.687 +     *  TODO: A future optimization will compute fFBoundingBoxes once per fCTFont.
   1.688 +     */
   1.689 +    bool generateBBoxes();
   1.690 +
   1.691 +    /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down).
   1.692 +     *
   1.693 +     *  Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs.
   1.694 +     *  Used on Lion to correct CTFontGetBoundingRectsForGlyphs.
   1.695 +     */
   1.696 +    SkMatrix fFUnitMatrix;
   1.697 +
   1.698 +    Offscreen fOffscreen;
   1.699 +    AutoCFRelease<CTFontRef> fCTFont;
   1.700 +
   1.701 +    /** Vertical variant of fCTFont.
   1.702 +     *
   1.703 +     *  CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise.
   1.704 +     *  This makes kCTFontDefaultOrientation dangerous, because the metrics from
   1.705 +     *  kCTFontHorizontalOrientation are in a different space from kCTFontVerticalOrientation.
   1.706 +     *  Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in the same space.
   1.707 +     */
   1.708 +    AutoCFRelease<CTFontRef> fCTVerticalFont;
   1.709 +
   1.710 +    AutoCFRelease<CGFontRef> fCGFont;
   1.711 +    SkAutoTMalloc<GlyphRect> fFBoundingBoxes;
   1.712 +    uint16_t fFBoundingBoxesGlyphOffset;
   1.713 +    uint16_t fGlyphCount;
   1.714 +    bool fGeneratedFBoundingBoxes;
   1.715 +    const bool fDoSubPosition;
   1.716 +    const bool fVertical;
   1.717 +
   1.718 +    friend class Offscreen;
   1.719 +
   1.720 +    typedef SkScalerContext INHERITED;
   1.721 +};
   1.722 +
   1.723 +SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
   1.724 +                                         const SkDescriptor* desc)
   1.725 +        : INHERITED(typeface, desc)
   1.726 +        , fFBoundingBoxes()
   1.727 +        , fFBoundingBoxesGlyphOffset(0)
   1.728 +        , fGeneratedFBoundingBoxes(false)
   1.729 +        , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
   1.730 +        , fVertical(SkToBool(fRec.fFlags & kVertical_Flag))
   1.731 +
   1.732 +{
   1.733 +    CTFontRef ctFont = typeface->fFontRef.get();
   1.734 +    CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
   1.735 +    SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
   1.736 +    fGlyphCount = SkToU16(numGlyphs);
   1.737 +
   1.738 +    fRec.getSingleMatrix(&fFUnitMatrix);
   1.739 +    CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix);
   1.740 +
   1.741 +    AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
   1.742 +    if (fVertical) {
   1.743 +        AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMutable(
   1.744 +                kCFAllocatorDefault, 0,
   1.745 +                &kCFTypeDictionaryKeyCallBacks,
   1.746 +                &kCFTypeDictionaryValueCallBacks));
   1.747 +        if (cfAttributes) {
   1.748 +            CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
   1.749 +            AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate(
   1.750 +                    kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation));
   1.751 +            CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVertical);
   1.752 +            ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
   1.753 +        }
   1.754 +    }
   1.755 +    // Since our matrix includes everything, we pass 1 for size.
   1.756 +    fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, ctFontDesc);
   1.757 +    fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL);
   1.758 +    if (fVertical) {
   1.759 +        CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
   1.760 +        transform = CGAffineTransformConcat(rotateLeft, transform);
   1.761 +        fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, NULL);
   1.762 +    }
   1.763 +
   1.764 +    SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFont)));
   1.765 +    fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit);
   1.766 +}
   1.767 +
   1.768 +CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
   1.769 +                             CGGlyph glyphID, size_t* rowBytesPtr,
   1.770 +                             bool generateA8FromLCD) {
   1.771 +    if (!fRGBSpace) {
   1.772 +        //It doesn't appear to matter what color space is specified.
   1.773 +        //Regular blends and antialiased text are always (s*a + d*(1-a))
   1.774 +        //and smoothed text is always g=2.0.
   1.775 +        fRGBSpace = CGColorSpaceCreateDeviceRGB();
   1.776 +    }
   1.777 +
   1.778 +    // default to kBW_Format
   1.779 +    bool doAA = false;
   1.780 +    bool doLCD = false;
   1.781 +
   1.782 +    if (SkMask::kBW_Format != glyph.fMaskFormat) {
   1.783 +        doLCD = true;
   1.784 +        doAA = true;
   1.785 +    }
   1.786 +
   1.787 +    // FIXME: lcd smoothed un-hinted rasterization unsupported.
   1.788 +    if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) {
   1.789 +        doLCD = false;
   1.790 +        doAA = true;
   1.791 +    }
   1.792 +
   1.793 +    size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
   1.794 +    if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
   1.795 +        if (fSize.fWidth < glyph.fWidth) {
   1.796 +            fSize.fWidth = RoundSize(glyph.fWidth);
   1.797 +        }
   1.798 +        if (fSize.fHeight < glyph.fHeight) {
   1.799 +            fSize.fHeight = RoundSize(glyph.fHeight);
   1.800 +        }
   1.801 +
   1.802 +        rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
   1.803 +        void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
   1.804 +        fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
   1.805 +                                    rowBytes, fRGBSpace, BITMAP_INFO_RGB);
   1.806 +
   1.807 +        // skia handles quantization itself, so we disable this for cg to get
   1.808 +        // full fractional data from them.
   1.809 +        CGContextSetAllowsFontSubpixelQuantization(fCG, false);
   1.810 +        CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
   1.811 +
   1.812 +        CGContextSetTextDrawingMode(fCG, kCGTextFill);
   1.813 +        CGContextSetFont(fCG, context.fCGFont);
   1.814 +        CGContextSetFontSize(fCG, 1 /*CTFontGetSize(context.fCTFont)*/);
   1.815 +        CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
   1.816 +
   1.817 +        // Because CG always draws from the horizontal baseline,
   1.818 +        // if there is a non-integral translation from the horizontal origin to the vertical origin,
   1.819 +        // then CG cannot draw the glyph in the correct location without subpixel positioning.
   1.820 +        CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical);
   1.821 +        CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || context.fVertical);
   1.822 +
   1.823 +        // Draw white on black to create mask.
   1.824 +        // TODO: Draw black on white and invert, CG has a special case codepath.
   1.825 +        CGContextSetGrayFillColor(fCG, 1.0f, 1.0f);
   1.826 +
   1.827 +        // force our checks below to happen
   1.828 +        fDoAA = !doAA;
   1.829 +        fDoLCD = !doLCD;
   1.830 +    }
   1.831 +
   1.832 +    if (fDoAA != doAA) {
   1.833 +        CGContextSetShouldAntialias(fCG, doAA);
   1.834 +        fDoAA = doAA;
   1.835 +    }
   1.836 +    if (fDoLCD != doLCD) {
   1.837 +        CGContextSetShouldSmoothFonts(fCG, doLCD);
   1.838 +        fDoLCD = doLCD;
   1.839 +    }
   1.840 +
   1.841 +    CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
   1.842 +    // skip rows based on the glyph's height
   1.843 +    image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
   1.844 +
   1.845 +    // erase to black
   1.846 +    sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes);
   1.847 +
   1.848 +    float subX = 0;
   1.849 +    float subY = 0;
   1.850 +    if (context.fDoSubPosition) {
   1.851 +        subX = SkFixedToFloat(glyph.getSubXFixed());
   1.852 +        subY = SkFixedToFloat(glyph.getSubYFixed());
   1.853 +    }
   1.854 +
   1.855 +    // CGContextShowGlyphsAtPoint always draws using the horizontal baseline origin.
   1.856 +    if (context.fVertical) {
   1.857 +        SkPoint offset;
   1.858 +        context.getVerticalOffset(glyphID, &offset);
   1.859 +        subX += offset.fX;
   1.860 +        subY += offset.fY;
   1.861 +    }
   1.862 +
   1.863 +    CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX,
   1.864 +                               glyph.fTop + glyph.fHeight - subY,
   1.865 +                               &glyphID, 1);
   1.866 +
   1.867 +    SkASSERT(rowBytesPtr);
   1.868 +    *rowBytesPtr = rowBytes;
   1.869 +    return image;
   1.870 +}
   1.871 +
   1.872 +void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const {
   1.873 +    // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up).
   1.874 +    // Lion and Leopard return cgVertOffset in CG units (pixels, y up).
   1.875 +    CGSize cgVertOffset;
   1.876 +    CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1);
   1.877 +
   1.878 +    SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) };
   1.879 +    if (isSnowLeopard()) {
   1.880 +        // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
   1.881 +        fFUnitMatrix.mapPoints(&skVertOffset, 1);
   1.882 +    } else {
   1.883 +        // From CG units (pixels, y up) to SkGlyph units (pixels, y down).
   1.884 +        skVertOffset.fY = -skVertOffset.fY;
   1.885 +    }
   1.886 +
   1.887 +    *offset = skVertOffset;
   1.888 +}
   1.889 +
   1.890 +uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() {
   1.891 +    if (fFBoundingBoxesGlyphOffset) {
   1.892 +        return fFBoundingBoxesGlyphOffset;
   1.893 +    }
   1.894 +    fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts
   1.895 +    AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont);
   1.896 +    if (hheaTable.fData) {
   1.897 +        fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetrics);
   1.898 +    }
   1.899 +    return fFBoundingBoxesGlyphOffset;
   1.900 +}
   1.901 +
   1.902 +bool SkScalerContext_Mac::generateBBoxes() {
   1.903 +    if (fGeneratedFBoundingBoxes) {
   1.904 +        return NULL != fFBoundingBoxes.get();
   1.905 +    }
   1.906 +    fGeneratedFBoundingBoxes = true;
   1.907 +
   1.908 +    AutoCGTable<SkOTTableHead> headTable(fCGFont);
   1.909 +    if (!headTable.fData) {
   1.910 +        return false;
   1.911 +    }
   1.912 +
   1.913 +    AutoCGTable<SkOTTableIndexToLocation> locaTable(fCGFont);
   1.914 +    if (!locaTable.fData) {
   1.915 +        return false;
   1.916 +    }
   1.917 +
   1.918 +    AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont);
   1.919 +    if (!glyfTable.fData) {
   1.920 +        return false;
   1.921 +    }
   1.922 +
   1.923 +    uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset;
   1.924 +    fFBoundingBoxes.reset(entries);
   1.925 +
   1.926 +    SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat;
   1.927 +    SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, locaFormat);
   1.928 +    glyphDataIter.advance(fFBoundingBoxesGlyphOffset);
   1.929 +    for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundingBoxesIndex) {
   1.930 +        const SkOTTableGlyphData* glyphData = glyphDataIter.next();
   1.931 +        GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex];
   1.932 +        rect.fMinX = SkEndian_SwapBE16(glyphData->xMin);
   1.933 +        rect.fMinY = SkEndian_SwapBE16(glyphData->yMin);
   1.934 +        rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax);
   1.935 +        rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax);
   1.936 +    }
   1.937 +
   1.938 +    return true;
   1.939 +}
   1.940 +
   1.941 +unsigned SkScalerContext_Mac::generateGlyphCount(void) {
   1.942 +    return fGlyphCount;
   1.943 +}
   1.944 +
   1.945 +uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) {
   1.946 +    CGGlyph cgGlyph[2];
   1.947 +    UniChar theChar[2]; // UniChar is a UTF-16 16-bit code unit.
   1.948 +
   1.949 +    // Get the glyph
   1.950 +    size_t numUniChar = SkUTF16_FromUnichar(uni, theChar);
   1.951 +    SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t));
   1.952 +
   1.953 +    // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
   1.954 +    // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
   1.955 +    // It is documented that if a mapping is unavailable, the glyph will be set to 0.
   1.956 +    CTFontGetGlyphsForCharacters(fCTFont, theChar, cgGlyph, numUniChar);
   1.957 +    return cgGlyph[0];
   1.958 +}
   1.959 +
   1.960 +void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
   1.961 +    this->generateMetrics(glyph);
   1.962 +}
   1.963 +
   1.964 +void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
   1.965 +    const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount);
   1.966 +    glyph->zeroMetrics();
   1.967 +
   1.968 +    // The following block produces cgAdvance in CG units (pixels, y up).
   1.969 +    CGSize cgAdvance;
   1.970 +    if (fVertical) {
   1.971 +        CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation,
   1.972 +                                   &cgGlyph, &cgAdvance, 1);
   1.973 +    } else {
   1.974 +        CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation,
   1.975 +                                   &cgGlyph, &cgAdvance, 1);
   1.976 +    }
   1.977 +    glyph->fAdvanceX =  SkFloatToFixed_Check(cgAdvance.width);
   1.978 +    glyph->fAdvanceY = -SkFloatToFixed_Check(cgAdvance.height);
   1.979 +
   1.980 +    // The following produces skBounds in SkGlyph units (pixels, y down),
   1.981 +    // or returns early if skBounds would be empty.
   1.982 +    SkRect skBounds;
   1.983 +
   1.984 +    // On Mountain Lion, CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation and
   1.985 +    // CTFontGetVerticalTranslationsForGlyphs do not agree when using OTF CFF fonts.
   1.986 +    // For TTF fonts these two do agree and we can use CTFontGetBoundingRectsForGlyphs to get
   1.987 +    // the bounding box and CTFontGetVerticalTranslationsForGlyphs to then draw the glyph
   1.988 +    // inside that bounding box. However, with OTF CFF fonts this does not work. It appears that
   1.989 +    // CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation on OTF CFF fonts tries
   1.990 +    // to center the glyph along the vertical baseline and also perform some mysterious shift
   1.991 +    // along the baseline. CTFontGetVerticalTranslationsForGlyphs does not appear to perform
   1.992 +    // these steps.
   1.993 +    //
   1.994 +    // It is not known which is correct (or if either is correct). However, we must always draw
   1.995 +    // from the horizontal origin and must use CTFontGetVerticalTranslationsForGlyphs to draw.
   1.996 +    // As a result, we do not call CTFontGetBoundingRectsForGlyphs for vertical glyphs.
   1.997 +
   1.998 +    // On Snow Leopard, CTFontGetBoundingRectsForGlyphs ignores kCTFontVerticalOrientation and
   1.999 +    // returns horizontal bounds.
  1.1000 +
  1.1001 +    // On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
  1.1002 +    // return a bad value in cgBounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
  1.1003 +    // less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
  1.1004 +    // font directly.
  1.1005 +    if ((isLion() || isMountainLion()) &&
  1.1006 +        (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && generateBBoxes()))
  1.1007 +    {
  1.1008 +        const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphOffset];
  1.1009 +        if (gRect.fMinX >= gRect.fMaxX || gRect.fMinY >= gRect.fMaxY) {
  1.1010 +            return;
  1.1011 +        }
  1.1012 +        skBounds = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY);
  1.1013 +        // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
  1.1014 +        fFUnitMatrix.mapRect(&skBounds);
  1.1015 +
  1.1016 +    } else {
  1.1017 +        // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up).
  1.1018 +        CGRect cgBounds;
  1.1019 +        CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation,
  1.1020 +                                        &cgGlyph, &cgBounds, 1);
  1.1021 +
  1.1022 +        // BUG?
  1.1023 +        // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when
  1.1024 +        // it should be empty. So, if we see a zero-advance, we check if it has an
  1.1025 +        // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance
  1.1026 +        // is rare, so we won't incur a big performance cost for this extra check.
  1.1027 +        if (0 == cgAdvance.width && 0 == cgAdvance.height) {
  1.1028 +            AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL));
  1.1029 +            if (NULL == path || CGPathIsEmpty(path)) {
  1.1030 +                return;
  1.1031 +            }
  1.1032 +        }
  1.1033 +
  1.1034 +        if (CGRectIsEmpty_inline(cgBounds)) {
  1.1035 +            return;
  1.1036 +        }
  1.1037 +
  1.1038 +        // Convert cgBounds to SkGlyph units (pixels, y down).
  1.1039 +        skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height,
  1.1040 +                                    cgBounds.size.width, cgBounds.size.height);
  1.1041 +    }
  1.1042 +
  1.1043 +    if (fVertical) {
  1.1044 +        // Due to all of the vertical bounds bugs, skBounds is always the horizontal bounds.
  1.1045 +        // Convert these horizontal bounds into vertical bounds.
  1.1046 +        SkPoint offset;
  1.1047 +        getVerticalOffset(cgGlyph, &offset);
  1.1048 +        skBounds.offset(offset);
  1.1049 +    }
  1.1050 +
  1.1051 +    // Currently the bounds are based on being rendered at (0,0).
  1.1052 +    // The top left must not move, since that is the base from which subpixel positioning is offset.
  1.1053 +    if (fDoSubPosition) {
  1.1054 +        skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed());
  1.1055 +        skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed());
  1.1056 +    }
  1.1057 +
  1.1058 +    SkIRect skIBounds;
  1.1059 +    skBounds.roundOut(&skIBounds);
  1.1060 +    // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
  1.1061 +    // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
  1.1062 +    // is not currently known, as CG dilates the outlines by some percentage.
  1.1063 +    // Note that if this context is A8 and not back-forming from LCD, there is no need to outset.
  1.1064 +    skIBounds.outset(1, 1);
  1.1065 +    glyph->fLeft = SkToS16(skIBounds.fLeft);
  1.1066 +    glyph->fTop = SkToS16(skIBounds.fTop);
  1.1067 +    glyph->fWidth = SkToU16(skIBounds.width());
  1.1068 +    glyph->fHeight = SkToU16(skIBounds.height());
  1.1069 +
  1.1070 +#ifdef HACK_COLORGLYPHS
  1.1071 +    glyph->fMaskFormat = SkMask::kARGB32_Format;
  1.1072 +#endif
  1.1073 +}
  1.1074 +
  1.1075 +#include "SkColorPriv.h"
  1.1076 +
  1.1077 +static void build_power_table(uint8_t table[], float ee) {
  1.1078 +    for (int i = 0; i < 256; i++) {
  1.1079 +        float x = i / 255.f;
  1.1080 +        x = sk_float_pow(x, ee);
  1.1081 +        int xx = SkScalarRoundToInt(x * 255);
  1.1082 +        table[i] = SkToU8(xx);
  1.1083 +    }
  1.1084 +}
  1.1085 +
  1.1086 +/**
  1.1087 + *  This will invert the gamma applied by CoreGraphics, so we can get linear
  1.1088 + *  values.
  1.1089 + *
  1.1090 + *  CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value.
  1.1091 + *  The color space used does not appear to affect this choice.
  1.1092 + */
  1.1093 +static const uint8_t* getInverseGammaTableCoreGraphicSmoothing() {
  1.1094 +    static bool gInited;
  1.1095 +    static uint8_t gTableCoreGraphicsSmoothing[256];
  1.1096 +    if (!gInited) {
  1.1097 +        build_power_table(gTableCoreGraphicsSmoothing, 2.0f);
  1.1098 +        gInited = true;
  1.1099 +    }
  1.1100 +    return gTableCoreGraphicsSmoothing;
  1.1101 +}
  1.1102 +
  1.1103 +static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
  1.1104 +    while (count > 0) {
  1.1105 +        uint8_t mask = 0;
  1.1106 +        for (int i = 7; i >= 0; --i) {
  1.1107 +            mask |= (CGRGBPixel_getAlpha(*src++) >> 7) << i;
  1.1108 +            if (0 == --count) {
  1.1109 +                break;
  1.1110 +            }
  1.1111 +        }
  1.1112 +        *dst++ = mask;
  1.1113 +    }
  1.1114 +}
  1.1115 +
  1.1116 +template<bool APPLY_PREBLEND>
  1.1117 +static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) {
  1.1118 +    U8CPU r = (rgb >> 16) & 0xFF;
  1.1119 +    U8CPU g = (rgb >>  8) & 0xFF;
  1.1120 +    U8CPU b = (rgb >>  0) & 0xFF;
  1.1121 +    return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
  1.1122 +}
  1.1123 +template<bool APPLY_PREBLEND>
  1.1124 +static void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes,
  1.1125 +                      const SkGlyph& glyph, const uint8_t* table8) {
  1.1126 +    const int width = glyph.fWidth;
  1.1127 +    size_t dstRB = glyph.rowBytes();
  1.1128 +    uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
  1.1129 +
  1.1130 +    for (int y = 0; y < glyph.fHeight; y++) {
  1.1131 +        for (int i = 0; i < width; ++i) {
  1.1132 +            dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8);
  1.1133 +        }
  1.1134 +        cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
  1.1135 +        dst += dstRB;
  1.1136 +    }
  1.1137 +}
  1.1138 +
  1.1139 +template<bool APPLY_PREBLEND>
  1.1140 +static inline uint16_t rgb_to_lcd16(CGRGBPixel rgb, const uint8_t* tableR,
  1.1141 +                                                    const uint8_t* tableG,
  1.1142 +                                                    const uint8_t* tableB) {
  1.1143 +    U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
  1.1144 +    U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
  1.1145 +    U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
  1.1146 +    return SkPack888ToRGB16(r, g, b);
  1.1147 +}
  1.1148 +template<bool APPLY_PREBLEND>
  1.1149 +static void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
  1.1150 +                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
  1.1151 +    const int width = glyph.fWidth;
  1.1152 +    size_t dstRB = glyph.rowBytes();
  1.1153 +    uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage;
  1.1154 +
  1.1155 +    for (int y = 0; y < glyph.fHeight; y++) {
  1.1156 +        for (int i = 0; i < width; i++) {
  1.1157 +            dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
  1.1158 +        }
  1.1159 +        cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
  1.1160 +        dst = (uint16_t*)((char*)dst + dstRB);
  1.1161 +    }
  1.1162 +}
  1.1163 +
  1.1164 +template<bool APPLY_PREBLEND>
  1.1165 +static inline uint32_t rgb_to_lcd32(CGRGBPixel rgb, const uint8_t* tableR,
  1.1166 +                                                    const uint8_t* tableG,
  1.1167 +                                                    const uint8_t* tableB) {
  1.1168 +    U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
  1.1169 +    U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
  1.1170 +    U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
  1.1171 +    return SkPackARGB32(0xFF, r, g, b);
  1.1172 +}
  1.1173 +template<bool APPLY_PREBLEND>
  1.1174 +static void rgb_to_lcd32(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
  1.1175 +                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
  1.1176 +    const int width = glyph.fWidth;
  1.1177 +    size_t dstRB = glyph.rowBytes();
  1.1178 +    uint32_t* SK_RESTRICT dst = (uint32_t*)glyph.fImage;
  1.1179 +    for (int y = 0; y < glyph.fHeight; y++) {
  1.1180 +        for (int i = 0; i < width; i++) {
  1.1181 +            dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
  1.1182 +        }
  1.1183 +        cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
  1.1184 +        dst = (uint32_t*)((char*)dst + dstRB);
  1.1185 +    }
  1.1186 +}
  1.1187 +
  1.1188 +#ifdef HACK_COLORGLYPHS
  1.1189 +// hack to colorize the output for testing kARGB32_Format
  1.1190 +static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb, const SkGlyph& glyph,
  1.1191 +                                     int x, int y) {
  1.1192 +    U8CPU r = (rgb >> 16) & 0xFF;
  1.1193 +    U8CPU g = (rgb >>  8) & 0xFF;
  1.1194 +    U8CPU b = (rgb >>  0) & 0xFF;
  1.1195 +    unsigned a = SkComputeLuminance(r, g, b);
  1.1196 +
  1.1197 +    // compute gradient from x,y
  1.1198 +    r = x * 255 / glyph.fWidth;
  1.1199 +    g = 0;
  1.1200 +    b = (glyph.fHeight - y) * 255 / glyph.fHeight;
  1.1201 +    return SkPreMultiplyARGB(a, r, g, b);    // red
  1.1202 +}
  1.1203 +#endif
  1.1204 +
  1.1205 +template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
  1.1206 +    return (T*)((char*)ptr + byteOffset);
  1.1207 +}
  1.1208 +
  1.1209 +void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
  1.1210 +    CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
  1.1211 +
  1.1212 +    // FIXME: lcd smoothed un-hinted rasterization unsupported.
  1.1213 +    bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting;
  1.1214 +
  1.1215 +    // Draw the glyph
  1.1216 +    size_t cgRowBytes;
  1.1217 +    CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, generateA8FromLCD);
  1.1218 +    if (cgPixels == NULL) {
  1.1219 +        return;
  1.1220 +    }
  1.1221 +
  1.1222 +    //TODO: see if drawing black on white and inverting is faster (at least in
  1.1223 +    //lcd case) as core graphics appears to have special case code for drawing
  1.1224 +    //black text.
  1.1225 +
  1.1226 +    // Fix the glyph
  1.1227 +    const bool isLCD = isLCDFormat(glyph.fMaskFormat);
  1.1228 +    if (isLCD || (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD)) {
  1.1229 +        const uint8_t* table = getInverseGammaTableCoreGraphicSmoothing();
  1.1230 +
  1.1231 +        //Note that the following cannot really be integrated into the
  1.1232 +        //pre-blend, since we may not be applying the pre-blend; when we aren't
  1.1233 +        //applying the pre-blend it means that a filter wants linear anyway.
  1.1234 +        //Other code may also be applying the pre-blend, so we'd need another
  1.1235 +        //one with this and one without.
  1.1236 +        CGRGBPixel* addr = cgPixels;
  1.1237 +        for (int y = 0; y < glyph.fHeight; ++y) {
  1.1238 +            for (int x = 0; x < glyph.fWidth; ++x) {
  1.1239 +                int r = (addr[x] >> 16) & 0xFF;
  1.1240 +                int g = (addr[x] >>  8) & 0xFF;
  1.1241 +                int b = (addr[x] >>  0) & 0xFF;
  1.1242 +                addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
  1.1243 +            }
  1.1244 +            addr = SkTAddByteOffset(addr, cgRowBytes);
  1.1245 +        }
  1.1246 +    }
  1.1247 +
  1.1248 +    // Convert glyph to mask
  1.1249 +    switch (glyph.fMaskFormat) {
  1.1250 +        case SkMask::kLCD32_Format: {
  1.1251 +            if (fPreBlend.isApplicable()) {
  1.1252 +                rgb_to_lcd32<true>(cgPixels, cgRowBytes, glyph,
  1.1253 +                                   fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1.1254 +            } else {
  1.1255 +                rgb_to_lcd32<false>(cgPixels, cgRowBytes, glyph,
  1.1256 +                                    fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1.1257 +            }
  1.1258 +        } break;
  1.1259 +        case SkMask::kLCD16_Format: {
  1.1260 +            if (fPreBlend.isApplicable()) {
  1.1261 +                rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph,
  1.1262 +                                   fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1.1263 +            } else {
  1.1264 +                rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph,
  1.1265 +                                    fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1.1266 +            }
  1.1267 +        } break;
  1.1268 +        case SkMask::kA8_Format: {
  1.1269 +            if (fPreBlend.isApplicable()) {
  1.1270 +                rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
  1.1271 +            } else {
  1.1272 +                rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
  1.1273 +            }
  1.1274 +        } break;
  1.1275 +        case SkMask::kBW_Format: {
  1.1276 +            const int width = glyph.fWidth;
  1.1277 +            size_t dstRB = glyph.rowBytes();
  1.1278 +            uint8_t* dst = (uint8_t*)glyph.fImage;
  1.1279 +            for (int y = 0; y < glyph.fHeight; y++) {
  1.1280 +                cgpixels_to_bits(dst, cgPixels, width);
  1.1281 +                cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
  1.1282 +                dst += dstRB;
  1.1283 +            }
  1.1284 +        } break;
  1.1285 +#ifdef HACK_COLORGLYPHS
  1.1286 +        case SkMask::kARGB32_Format: {
  1.1287 +            const int width = glyph.fWidth;
  1.1288 +            size_t dstRB = glyph.rowBytes();
  1.1289 +            SkPMColor* dst = (SkPMColor*)glyph.fImage;
  1.1290 +            for (int y = 0; y < glyph.fHeight; y++) {
  1.1291 +                for (int x = 0; x < width; ++x) {
  1.1292 +                    dst[x] = cgpixels_to_pmcolor(cgPixels[x], glyph, x, y);
  1.1293 +                }
  1.1294 +                cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
  1.1295 +                dst = (SkPMColor*)((char*)dst + dstRB);
  1.1296 +            }
  1.1297 +        } break;
  1.1298 +#endif
  1.1299 +        default:
  1.1300 +            SkDEBUGFAIL("unexpected mask format");
  1.1301 +            break;
  1.1302 +    }
  1.1303 +}
  1.1304 +
  1.1305 +/*
  1.1306 + *  Our subpixel resolution is only 2 bits in each direction, so a scale of 4
  1.1307 + *  seems sufficient, and possibly even correct, to allow the hinted outline
  1.1308 + *  to be subpixel positioned.
  1.1309 + */
  1.1310 +#define kScaleForSubPixelPositionHinting (4.0f)
  1.1311 +
  1.1312 +void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) {
  1.1313 +    CTFontRef font = fCTFont;
  1.1314 +    SkScalar scaleX = SK_Scalar1;
  1.1315 +    SkScalar scaleY = SK_Scalar1;
  1.1316 +
  1.1317 +    /*
  1.1318 +     *  For subpixel positioning, we want to return an unhinted outline, so it
  1.1319 +     *  can be positioned nicely at fractional offsets. However, we special-case
  1.1320 +     *  if the baseline of the (horizontal) text is axis-aligned. In those cases
  1.1321 +     *  we want to retain hinting in the direction orthogonal to the baseline.
  1.1322 +     *  e.g. for horizontal baseline, we want to retain hinting in Y.
  1.1323 +     *  The way we remove hinting is to scale the font by some value (4) in that
  1.1324 +     *  direction, ask for the path, and then scale the path back down.
  1.1325 +     */
  1.1326 +    if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
  1.1327 +        SkMatrix m;
  1.1328 +        fRec.getSingleMatrix(&m);
  1.1329 +
  1.1330 +        // start out by assuming that we want no hining in X and Y
  1.1331 +        scaleX = scaleY = kScaleForSubPixelPositionHinting;
  1.1332 +        // now see if we need to restore hinting for axis-aligned baselines
  1.1333 +        switch (SkComputeAxisAlignmentForHText(m)) {
  1.1334 +            case kX_SkAxisAlignment:
  1.1335 +                scaleY = SK_Scalar1; // want hinting in the Y direction
  1.1336 +                break;
  1.1337 +            case kY_SkAxisAlignment:
  1.1338 +                scaleX = SK_Scalar1; // want hinting in the X direction
  1.1339 +                break;
  1.1340 +            default:
  1.1341 +                break;
  1.1342 +        }
  1.1343 +
  1.1344 +        CGAffineTransform xform = MatrixToCGAffineTransform(m, scaleX, scaleY);
  1.1345 +        // need to release font when we're done
  1.1346 +        font = CTFontCreateCopyWithAttributes(fCTFont, 1, &xform, NULL);
  1.1347 +    }
  1.1348 +
  1.1349 +    CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount);
  1.1350 +    AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL));
  1.1351 +
  1.1352 +    path->reset();
  1.1353 +    if (cgPath != NULL) {
  1.1354 +        CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement);
  1.1355 +    }
  1.1356 +
  1.1357 +    if (fDoSubPosition) {
  1.1358 +        SkMatrix m;
  1.1359 +        m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY));
  1.1360 +        path->transform(m);
  1.1361 +        // balance the call to CTFontCreateCopyWithAttributes
  1.1362 +        CFSafeRelease(font);
  1.1363 +    }
  1.1364 +    if (fVertical) {
  1.1365 +        SkPoint offset;
  1.1366 +        getVerticalOffset(cgGlyph, &offset);
  1.1367 +        path->offset(offset.fX, offset.fY);
  1.1368 +    }
  1.1369 +}
  1.1370 +
  1.1371 +void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
  1.1372 +                                              SkPaint::FontMetrics* my) {
  1.1373 +    CGRect theBounds = CTFontGetBoundingBox(fCTFont);
  1.1374 +
  1.1375 +    SkPaint::FontMetrics theMetrics;
  1.1376 +    theMetrics.fTop          = CGToScalar(-CGRectGetMaxY_inline(theBounds));
  1.1377 +    theMetrics.fAscent       = CGToScalar(-CTFontGetAscent(fCTFont));
  1.1378 +    theMetrics.fDescent      = CGToScalar( CTFontGetDescent(fCTFont));
  1.1379 +    theMetrics.fBottom       = CGToScalar(-CGRectGetMinY_inline(theBounds));
  1.1380 +    theMetrics.fLeading      = CGToScalar( CTFontGetLeading(fCTFont));
  1.1381 +    theMetrics.fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds));
  1.1382 +    theMetrics.fXMin         = CGToScalar( CGRectGetMinX_inline(theBounds));
  1.1383 +    theMetrics.fXMax         = CGToScalar( CGRectGetMaxX_inline(theBounds));
  1.1384 +    theMetrics.fXHeight      = CGToScalar( CTFontGetXHeight(fCTFont));
  1.1385 +    theMetrics.fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont));
  1.1386 +    theMetrics.fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont));
  1.1387 +
  1.1388 +    theMetrics.fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
  1.1389 +    theMetrics.fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
  1.1390 +
  1.1391 +    if (mx != NULL) {
  1.1392 +        *mx = theMetrics;
  1.1393 +    }
  1.1394 +    if (my != NULL) {
  1.1395 +        *my = theMetrics;
  1.1396 +    }
  1.1397 +}
  1.1398 +
  1.1399 +void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) {
  1.1400 +    SkPath* skPath = (SkPath*)info;
  1.1401 +
  1.1402 +    // Process the path element
  1.1403 +    switch (element->type) {
  1.1404 +        case kCGPathElementMoveToPoint:
  1.1405 +            skPath->moveTo(element->points[0].x, -element->points[0].y);
  1.1406 +            break;
  1.1407 +
  1.1408 +        case kCGPathElementAddLineToPoint:
  1.1409 +            skPath->lineTo(element->points[0].x, -element->points[0].y);
  1.1410 +            break;
  1.1411 +
  1.1412 +        case kCGPathElementAddQuadCurveToPoint:
  1.1413 +            skPath->quadTo(element->points[0].x, -element->points[0].y,
  1.1414 +                           element->points[1].x, -element->points[1].y);
  1.1415 +            break;
  1.1416 +
  1.1417 +        case kCGPathElementAddCurveToPoint:
  1.1418 +            skPath->cubicTo(element->points[0].x, -element->points[0].y,
  1.1419 +                            element->points[1].x, -element->points[1].y,
  1.1420 +                            element->points[2].x, -element->points[2].y);
  1.1421 +            break;
  1.1422 +
  1.1423 +        case kCGPathElementCloseSubpath:
  1.1424 +            skPath->close();
  1.1425 +            break;
  1.1426 +
  1.1427 +        default:
  1.1428 +            SkDEBUGFAIL("Unknown path element!");
  1.1429 +            break;
  1.1430 +        }
  1.1431 +}
  1.1432 +
  1.1433 +
  1.1434 +///////////////////////////////////////////////////////////////////////////////
  1.1435 +
  1.1436 +// Returns NULL on failure
  1.1437 +// Call must still manage its ownership of provider
  1.1438 +static SkTypeface* create_from_dataProvider(CGDataProviderRef provider) {
  1.1439 +    AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider));
  1.1440 +    if (NULL == cg) {
  1.1441 +        return NULL;
  1.1442 +    }
  1.1443 +    CTFontRef ct = CTFontCreateWithGraphicsFont(cg, 0, NULL, NULL);
  1.1444 +    return cg ? SkCreateTypefaceFromCTFont(ct) : NULL;
  1.1445 +}
  1.1446 +
  1.1447 +// Web fonts added to the the CTFont registry do not return their character set.
  1.1448 +// Iterate through the font in this case. The existing caller caches the result,
  1.1449 +// so the performance impact isn't too bad.
  1.1450 +static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
  1.1451 +                                           SkTDArray<SkUnichar>* glyphToUnicode) {
  1.1452 +    glyphToUnicode->setCount(SkToInt(glyphCount));
  1.1453 +    SkUnichar* out = glyphToUnicode->begin();
  1.1454 +    sk_bzero(out, glyphCount * sizeof(SkUnichar));
  1.1455 +    UniChar unichar = 0;
  1.1456 +    while (glyphCount > 0) {
  1.1457 +        CGGlyph glyph;
  1.1458 +        if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
  1.1459 +            out[glyph] = unichar;
  1.1460 +            --glyphCount;
  1.1461 +        }
  1.1462 +        if (++unichar == 0) {
  1.1463 +            break;
  1.1464 +        }
  1.1465 +    }
  1.1466 +}
  1.1467 +
  1.1468 +// Construct Glyph to Unicode table.
  1.1469 +// Unicode code points that require conjugate pairs in utf16 are not
  1.1470 +// supported.
  1.1471 +static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
  1.1472 +                                      SkTDArray<SkUnichar>* glyphToUnicode) {
  1.1473 +    AutoCFRelease<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
  1.1474 +    if (!charSet) {
  1.1475 +        populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
  1.1476 +        return;
  1.1477 +    }
  1.1478 +
  1.1479 +    AutoCFRelease<CFDataRef> bitmap(CFCharacterSetCreateBitmapRepresentation(kCFAllocatorDefault,
  1.1480 +                                                                             charSet));
  1.1481 +    if (!bitmap) {
  1.1482 +        return;
  1.1483 +    }
  1.1484 +    CFIndex length = CFDataGetLength(bitmap);
  1.1485 +    if (!length) {
  1.1486 +        return;
  1.1487 +    }
  1.1488 +    if (length > 8192) {
  1.1489 +        // TODO: Add support for Unicode above 0xFFFF
  1.1490 +        // Consider only the BMP portion of the Unicode character points.
  1.1491 +        // The bitmap may contain other planes, up to plane 16.
  1.1492 +        // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html
  1.1493 +        length = 8192;
  1.1494 +    }
  1.1495 +    const UInt8* bits = CFDataGetBytePtr(bitmap);
  1.1496 +    glyphToUnicode->setCount(SkToInt(glyphCount));
  1.1497 +    SkUnichar* out = glyphToUnicode->begin();
  1.1498 +    sk_bzero(out, glyphCount * sizeof(SkUnichar));
  1.1499 +    for (int i = 0; i < length; i++) {
  1.1500 +        int mask = bits[i];
  1.1501 +        if (!mask) {
  1.1502 +            continue;
  1.1503 +        }
  1.1504 +        for (int j = 0; j < 8; j++) {
  1.1505 +            CGGlyph glyph;
  1.1506 +            UniChar unichar = static_cast<UniChar>((i << 3) + j);
  1.1507 +            if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
  1.1508 +                out[glyph] = unichar;
  1.1509 +            }
  1.1510 +        }
  1.1511 +    }
  1.1512 +}
  1.1513 +
  1.1514 +static bool getWidthAdvance(CTFontRef ctFont, int gId, int16_t* data) {
  1.1515 +    CGSize advance;
  1.1516 +    advance.width = 0;
  1.1517 +    CGGlyph glyph = gId;
  1.1518 +    CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &glyph, &advance, 1);
  1.1519 +    *data = sk_float_round2int(advance.width);
  1.1520 +    return true;
  1.1521 +}
  1.1522 +
  1.1523 +// we might move this into our CGUtils...
  1.1524 +static void CFStringToSkString(CFStringRef src, SkString* dst) {
  1.1525 +    // Reserve enough room for the worst-case string,
  1.1526 +    // plus 1 byte for the trailing null.
  1.1527 +    CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src),
  1.1528 +                                                       kCFStringEncodingUTF8) + 1;
  1.1529 +    dst->resize(length);
  1.1530 +    CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8);
  1.1531 +    // Resize to the actual UTF-8 length used, stripping the null character.
  1.1532 +    dst->resize(strlen(dst->c_str()));
  1.1533 +}
  1.1534 +
  1.1535 +SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics(
  1.1536 +        SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
  1.1537 +        const uint32_t* glyphIDs,
  1.1538 +        uint32_t glyphIDsCount) const {
  1.1539 +
  1.1540 +    CTFontRef originalCTFont = fFontRef.get();
  1.1541 +    AutoCFRelease<CTFontRef> ctFont(CTFontCreateCopyWithAttributes(
  1.1542 +            originalCTFont, CTFontGetUnitsPerEm(originalCTFont), NULL, NULL));
  1.1543 +    SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
  1.1544 +
  1.1545 +    {
  1.1546 +        AutoCFRelease<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont));
  1.1547 +        CFStringToSkString(fontName, &info->fFontName);
  1.1548 +    }
  1.1549 +
  1.1550 +    info->fMultiMaster = false;
  1.1551 +    CFIndex glyphCount = CTFontGetGlyphCount(ctFont);
  1.1552 +    info->fLastGlyphID = SkToU16(glyphCount - 1);
  1.1553 +    info->fEmSize = CTFontGetUnitsPerEm(ctFont);
  1.1554 +
  1.1555 +    if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
  1.1556 +        populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode);
  1.1557 +    }
  1.1558 +
  1.1559 +    info->fStyle = 0;
  1.1560 +
  1.1561 +    // If it's not a truetype font, mark it as 'other'. Assume that TrueType
  1.1562 +    // fonts always have both glyf and loca tables. At the least, this is what
  1.1563 +    // sfntly needs to subset the font. CTFontCopyAttribute() does not always
  1.1564 +    // succeed in determining this directly.
  1.1565 +    if (!this->getTableSize('glyf') || !this->getTableSize('loca')) {
  1.1566 +        info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
  1.1567 +        info->fItalicAngle = 0;
  1.1568 +        info->fAscent = 0;
  1.1569 +        info->fDescent = 0;
  1.1570 +        info->fStemV = 0;
  1.1571 +        info->fCapHeight = 0;
  1.1572 +        info->fBBox = SkIRect::MakeEmpty();
  1.1573 +        return info;
  1.1574 +    }
  1.1575 +
  1.1576 +    info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
  1.1577 +    CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont);
  1.1578 +    if (symbolicTraits & kCTFontMonoSpaceTrait) {
  1.1579 +        info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
  1.1580 +    }
  1.1581 +    if (symbolicTraits & kCTFontItalicTrait) {
  1.1582 +        info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
  1.1583 +    }
  1.1584 +    CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
  1.1585 +    if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
  1.1586 +        info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
  1.1587 +    } else if (stylisticClass & kCTFontScriptsClass) {
  1.1588 +        info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
  1.1589 +    }
  1.1590 +    info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont);
  1.1591 +    info->fAscent = (int16_t) CTFontGetAscent(ctFont);
  1.1592 +    info->fDescent = (int16_t) CTFontGetDescent(ctFont);
  1.1593 +    info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont);
  1.1594 +    CGRect bbox = CTFontGetBoundingBox(ctFont);
  1.1595 +
  1.1596 +    SkRect r;
  1.1597 +    r.set( CGToScalar(CGRectGetMinX_inline(bbox)),   // Left
  1.1598 +           CGToScalar(CGRectGetMaxY_inline(bbox)),   // Top
  1.1599 +           CGToScalar(CGRectGetMaxX_inline(bbox)),   // Right
  1.1600 +           CGToScalar(CGRectGetMinY_inline(bbox)));  // Bottom
  1.1601 +
  1.1602 +    r.roundOut(&(info->fBBox));
  1.1603 +
  1.1604 +    // Figure out a good guess for StemV - Min width of i, I, !, 1.
  1.1605 +    // This probably isn't very good with an italic font.
  1.1606 +    int16_t min_width = SHRT_MAX;
  1.1607 +    info->fStemV = 0;
  1.1608 +    static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
  1.1609 +    const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
  1.1610 +    CGGlyph glyphs[count];
  1.1611 +    CGRect boundingRects[count];
  1.1612 +    if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) {
  1.1613 +        CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation,
  1.1614 +                                        glyphs, boundingRects, count);
  1.1615 +        for (size_t i = 0; i < count; i++) {
  1.1616 +            int16_t width = (int16_t) boundingRects[i].size.width;
  1.1617 +            if (width > 0 && width < min_width) {
  1.1618 +                min_width = width;
  1.1619 +                info->fStemV = min_width;
  1.1620 +            }
  1.1621 +        }
  1.1622 +    }
  1.1623 +
  1.1624 +    if (false) { // TODO: haven't figured out how to know if font is embeddable
  1.1625 +        // (information is in the OS/2 table)
  1.1626 +        info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
  1.1627 +    } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
  1.1628 +        if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
  1.1629 +            skia_advanced_typeface_metrics_utils::appendRange(&info->fGlyphWidths, 0);
  1.1630 +            info->fGlyphWidths->fAdvance.append(1, &min_width);
  1.1631 +            skia_advanced_typeface_metrics_utils::finishRange(info->fGlyphWidths.get(), 0,
  1.1632 +                        SkAdvancedTypefaceMetrics::WidthRange::kDefault);
  1.1633 +        } else {
  1.1634 +            info->fGlyphWidths.reset(
  1.1635 +                skia_advanced_typeface_metrics_utils::getAdvanceData(ctFont.get(),
  1.1636 +                               SkToInt(glyphCount),
  1.1637 +                               glyphIDs,
  1.1638 +                               glyphIDsCount,
  1.1639 +                               &getWidthAdvance));
  1.1640 +        }
  1.1641 +    }
  1.1642 +    return info;
  1.1643 +}
  1.1644 +
  1.1645 +///////////////////////////////////////////////////////////////////////////////
  1.1646 +
  1.1647 +static SK_SFNT_ULONG get_font_type_tag(const SkTypeface_Mac* typeface) {
  1.1648 +    CTFontRef ctFont = typeface->fFontRef.get();
  1.1649 +    AutoCFRelease<CFNumberRef> fontFormatRef(
  1.1650 +            static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
  1.1651 +    if (!fontFormatRef) {
  1.1652 +        return 0;
  1.1653 +    }
  1.1654 +
  1.1655 +    SInt32 fontFormatValue;
  1.1656 +    if (!CFNumberGetValue(fontFormatRef, kCFNumberSInt32Type, &fontFormatValue)) {
  1.1657 +        return 0;
  1.1658 +    }
  1.1659 +
  1.1660 +    switch (fontFormatValue) {
  1.1661 +        case kCTFontFormatOpenTypePostScript:
  1.1662 +            return SkSFNTHeader::fontType_OpenTypeCFF::TAG;
  1.1663 +        case kCTFontFormatOpenTypeTrueType:
  1.1664 +            return SkSFNTHeader::fontType_WindowsTrueType::TAG;
  1.1665 +        case kCTFontFormatTrueType:
  1.1666 +            return SkSFNTHeader::fontType_MacTrueType::TAG;
  1.1667 +        case kCTFontFormatPostScript:
  1.1668 +            return SkSFNTHeader::fontType_PostScript::TAG;
  1.1669 +        case kCTFontFormatBitmap:
  1.1670 +            return SkSFNTHeader::fontType_MacTrueType::TAG;
  1.1671 +        case kCTFontFormatUnrecognized:
  1.1672 +        default:
  1.1673 +            //CT seems to be unreliable in being able to obtain the type,
  1.1674 +            //even if all we want is the first four bytes of the font resource.
  1.1675 +            //Just the presence of the FontForge 'FFTM' table seems to throw it off.
  1.1676 +            return SkSFNTHeader::fontType_WindowsTrueType::TAG;
  1.1677 +    }
  1.1678 +}
  1.1679 +
  1.1680 +SkStream* SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
  1.1681 +    SK_SFNT_ULONG fontType = get_font_type_tag(this);
  1.1682 +    if (0 == fontType) {
  1.1683 +        return NULL;
  1.1684 +    }
  1.1685 +
  1.1686 +    // get table tags
  1.1687 +    int numTables = this->countTables();
  1.1688 +    SkTDArray<SkFontTableTag> tableTags;
  1.1689 +    tableTags.setCount(numTables);
  1.1690 +    this->getTableTags(tableTags.begin());
  1.1691 +
  1.1692 +    // calc total size for font, save sizes
  1.1693 +    SkTDArray<size_t> tableSizes;
  1.1694 +    size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
  1.1695 +    for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
  1.1696 +        size_t tableSize = this->getTableSize(tableTags[tableIndex]);
  1.1697 +        totalSize += (tableSize + 3) & ~3;
  1.1698 +        *tableSizes.append() = tableSize;
  1.1699 +    }
  1.1700 +
  1.1701 +    // reserve memory for stream, and zero it (tables must be zero padded)
  1.1702 +    SkMemoryStream* stream = new SkMemoryStream(totalSize);
  1.1703 +    char* dataStart = (char*)stream->getMemoryBase();
  1.1704 +    sk_bzero(dataStart, totalSize);
  1.1705 +    char* dataPtr = dataStart;
  1.1706 +
  1.1707 +    // compute font header entries
  1.1708 +    uint16_t entrySelector = 0;
  1.1709 +    uint16_t searchRange = 1;
  1.1710 +    while (searchRange < numTables >> 1) {
  1.1711 +        entrySelector++;
  1.1712 +        searchRange <<= 1;
  1.1713 +    }
  1.1714 +    searchRange <<= 4;
  1.1715 +    uint16_t rangeShift = (numTables << 4) - searchRange;
  1.1716 +
  1.1717 +    // write font header
  1.1718 +    SkSFNTHeader* header = (SkSFNTHeader*)dataPtr;
  1.1719 +    header->fontType = fontType;
  1.1720 +    header->numTables = SkEndian_SwapBE16(numTables);
  1.1721 +    header->searchRange = SkEndian_SwapBE16(searchRange);
  1.1722 +    header->entrySelector = SkEndian_SwapBE16(entrySelector);
  1.1723 +    header->rangeShift = SkEndian_SwapBE16(rangeShift);
  1.1724 +    dataPtr += sizeof(SkSFNTHeader);
  1.1725 +
  1.1726 +    // write tables
  1.1727 +    SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr;
  1.1728 +    dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
  1.1729 +    for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
  1.1730 +        size_t tableSize = tableSizes[tableIndex];
  1.1731 +        this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
  1.1732 +        entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]);
  1.1733 +        entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr,
  1.1734 +                                                                         tableSize));
  1.1735 +        entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart));
  1.1736 +        entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize));
  1.1737 +
  1.1738 +        dataPtr += (tableSize + 3) & ~3;
  1.1739 +        ++entry;
  1.1740 +    }
  1.1741 +
  1.1742 +    return stream;
  1.1743 +}
  1.1744 +
  1.1745 +///////////////////////////////////////////////////////////////////////////////
  1.1746 +///////////////////////////////////////////////////////////////////////////////
  1.1747 +
  1.1748 +int SkTypeface_Mac::onGetUPEM() const {
  1.1749 +    AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef, NULL));
  1.1750 +    return CGFontGetUnitsPerEm(cgFont);
  1.1751 +}
  1.1752 +
  1.1753 +SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const {
  1.1754 +    SkTypeface::LocalizedStrings* nameIter =
  1.1755 +        SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
  1.1756 +    if (NULL == nameIter) {
  1.1757 +        AutoCFRelease<CFStringRef> cfLanguage;
  1.1758 +        AutoCFRelease<CFStringRef> cfFamilyName(
  1.1759 +            CTFontCopyLocalizedName(fFontRef, kCTFontFamilyNameKey, &cfLanguage));
  1.1760 +
  1.1761 +        SkString skLanguage;
  1.1762 +        SkString skFamilyName;
  1.1763 +        if (cfLanguage.get()) {
  1.1764 +            CFStringToSkString(cfLanguage.get(), &skLanguage);
  1.1765 +        } else {
  1.1766 +            skLanguage = "und"; //undetermined
  1.1767 +        }
  1.1768 +        if (cfFamilyName.get()) {
  1.1769 +            CFStringToSkString(cfFamilyName.get(), &skFamilyName);
  1.1770 +        }
  1.1771 +
  1.1772 +        nameIter = new SkOTUtils::LocalizedStrings_SingleName(skFamilyName, skLanguage);
  1.1773 +    }
  1.1774 +    return nameIter;
  1.1775 +}
  1.1776 +
  1.1777 +// If, as is the case with web fonts, the CTFont data isn't available,
  1.1778 +// the CGFont data may work. While the CGFont may always provide the
  1.1779 +// right result, leave the CTFont code path to minimize disruption.
  1.1780 +static CFDataRef copyTableFromFont(CTFontRef ctFont, SkFontTableTag tag) {
  1.1781 +    CFDataRef data = CTFontCopyTable(ctFont, (CTFontTableTag) tag,
  1.1782 +                                     kCTFontTableOptionNoOptions);
  1.1783 +    if (NULL == data) {
  1.1784 +        AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, NULL));
  1.1785 +        data = CGFontCopyTableForTag(cgFont, tag);
  1.1786 +    }
  1.1787 +    return data;
  1.1788 +}
  1.1789 +
  1.1790 +int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
  1.1791 +    AutoCFRelease<CFArrayRef> cfArray(CTFontCopyAvailableTables(fFontRef,
  1.1792 +                                                kCTFontTableOptionNoOptions));
  1.1793 +    if (NULL == cfArray) {
  1.1794 +        return 0;
  1.1795 +    }
  1.1796 +    int count = SkToInt(CFArrayGetCount(cfArray));
  1.1797 +    if (tags) {
  1.1798 +        for (int i = 0; i < count; ++i) {
  1.1799 +            uintptr_t fontTag = reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(cfArray, i));
  1.1800 +            tags[i] = static_cast<SkFontTableTag>(fontTag);
  1.1801 +        }
  1.1802 +    }
  1.1803 +    return count;
  1.1804 +}
  1.1805 +
  1.1806 +size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset,
  1.1807 +                                      size_t length, void* dstData) const {
  1.1808 +    AutoCFRelease<CFDataRef> srcData(copyTableFromFont(fFontRef, tag));
  1.1809 +    if (NULL == srcData) {
  1.1810 +        return 0;
  1.1811 +    }
  1.1812 +
  1.1813 +    size_t srcSize = CFDataGetLength(srcData);
  1.1814 +    if (offset >= srcSize) {
  1.1815 +        return 0;
  1.1816 +    }
  1.1817 +    if (length > srcSize - offset) {
  1.1818 +        length = srcSize - offset;
  1.1819 +    }
  1.1820 +    if (dstData) {
  1.1821 +        memcpy(dstData, CFDataGetBytePtr(srcData) + offset, length);
  1.1822 +    }
  1.1823 +    return length;
  1.1824 +}
  1.1825 +
  1.1826 +SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkDescriptor* desc) const {
  1.1827 +    return new SkScalerContext_Mac(const_cast<SkTypeface_Mac*>(this), desc);
  1.1828 +}
  1.1829 +
  1.1830 +void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
  1.1831 +    if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
  1.1832 +        rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
  1.1833 +    {
  1.1834 +        rec->fMaskFormat = SkMask::kA8_Format;
  1.1835 +        // Render the glyphs as close as possible to what was requested.
  1.1836 +        // The above turns off subpixel rendering, but the user requested it.
  1.1837 +        // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks.
  1.1838 +        // See comments below for more details.
  1.1839 +        rec->setHinting(SkPaint::kNormal_Hinting);
  1.1840 +    }
  1.1841 +
  1.1842 +    unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag  |
  1.1843 +                                  SkScalerContext::kForceAutohinting_Flag  |
  1.1844 +                                  SkScalerContext::kLCD_BGROrder_Flag |
  1.1845 +                                  SkScalerContext::kLCD_Vertical_Flag;
  1.1846 +
  1.1847 +    rec->fFlags &= ~flagsWeDontSupport;
  1.1848 +
  1.1849 +    bool lcdSupport = supports_LCD();
  1.1850 +
  1.1851 +    // Only two levels of hinting are supported.
  1.1852 +    // kNo_Hinting means avoid CoreGraphics outline dilation.
  1.1853 +    // kNormal_Hinting means CoreGraphics outline dilation is allowed.
  1.1854 +    // If there is no lcd support, hinting (dilation) cannot be supported.
  1.1855 +    SkPaint::Hinting hinting = rec->getHinting();
  1.1856 +    if (SkPaint::kSlight_Hinting == hinting || !lcdSupport) {
  1.1857 +        hinting = SkPaint::kNo_Hinting;
  1.1858 +    } else if (SkPaint::kFull_Hinting == hinting) {
  1.1859 +        hinting = SkPaint::kNormal_Hinting;
  1.1860 +    }
  1.1861 +    rec->setHinting(hinting);
  1.1862 +
  1.1863 +    // FIXME: lcd smoothed un-hinted rasterization unsupported.
  1.1864 +    // Tracked by http://code.google.com/p/skia/issues/detail?id=915 .
  1.1865 +    // There is no current means to honor a request for unhinted lcd,
  1.1866 +    // so arbitrarilly ignore the hinting request and honor lcd.
  1.1867 +
  1.1868 +    // Hinting and smoothing should be orthogonal, but currently they are not.
  1.1869 +    // CoreGraphics has no API to influence hinting. However, its lcd smoothed
  1.1870 +    // output is drawn from auto-dilated outlines (the amount of which is
  1.1871 +    // determined by AppleFontSmoothing). Its regular anti-aliased output is
  1.1872 +    // drawn from un-dilated outlines.
  1.1873 +
  1.1874 +    // The behavior of Skia is as follows:
  1.1875 +    // [AA][no-hint]: generate AA using CoreGraphic's AA output.
  1.1876 +    // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single
  1.1877 +    // channel. This matches [LCD][yes-hint] in weight.
  1.1878 +    // [LCD][no-hint]: curently unable to honor, and must pick which to respect.
  1.1879 +    // Currenly side with LCD, effectively ignoring the hinting setting.
  1.1880 +    // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output.
  1.1881 +
  1.1882 +    if (isLCDFormat(rec->fMaskFormat)) {
  1.1883 +        if (lcdSupport) {
  1.1884 +            //CoreGraphics creates 555 masks for smoothed text anyway.
  1.1885 +            rec->fMaskFormat = SkMask::kLCD16_Format;
  1.1886 +            rec->setHinting(SkPaint::kNormal_Hinting);
  1.1887 +        } else {
  1.1888 +            rec->fMaskFormat = SkMask::kA8_Format;
  1.1889 +        }
  1.1890 +    }
  1.1891 +
  1.1892 +    // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
  1.1893 +    // All other masks can use regular gamma.
  1.1894 +    if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hinting) {
  1.1895 +#ifndef SK_GAMMA_APPLY_TO_A8
  1.1896 +        rec->ignorePreBlend();
  1.1897 +#endif
  1.1898 +    } else {
  1.1899 +        //CoreGraphics dialates smoothed text as needed.
  1.1900 +        rec->setContrast(0);
  1.1901 +    }
  1.1902 +}
  1.1903 +
  1.1904 +// we take ownership of the ref
  1.1905 +static const char* get_str(CFStringRef ref, SkString* str) {
  1.1906 +    CFStringToSkString(ref, str);
  1.1907 +    CFSafeRelease(ref);
  1.1908 +    return str->c_str();
  1.1909 +}
  1.1910 +
  1.1911 +void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc,
  1.1912 +                                         bool* isLocalStream) const {
  1.1913 +    SkString tmpStr;
  1.1914 +
  1.1915 +    desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef), &tmpStr));
  1.1916 +    desc->setFullName(get_str(CTFontCopyFullName(fFontRef), &tmpStr));
  1.1917 +    desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef), &tmpStr));
  1.1918 +    // TODO: need to add support for local-streams (here and openStream)
  1.1919 +    *isLocalStream = false;
  1.1920 +}
  1.1921 +
  1.1922 +int SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding,
  1.1923 +                                    uint16_t glyphs[], int glyphCount) const
  1.1924 +{
  1.1925 +    // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
  1.1926 +    // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
  1.1927 +    // It is documented that if a mapping is unavailable, the glyph will be set to 0.
  1.1928 +
  1.1929 +    SkAutoSTMalloc<1024, UniChar> charStorage;
  1.1930 +    const UniChar* src; // UniChar is a UTF-16 16-bit code unit.
  1.1931 +    int srcCount;
  1.1932 +    switch (encoding) {
  1.1933 +        case kUTF8_Encoding: {
  1.1934 +            const char* utf8 = reinterpret_cast<const char*>(chars);
  1.1935 +            UniChar* utf16 = charStorage.reset(2 * glyphCount);
  1.1936 +            src = utf16;
  1.1937 +            for (int i = 0; i < glyphCount; ++i) {
  1.1938 +                SkUnichar uni = SkUTF8_NextUnichar(&utf8);
  1.1939 +                utf16 += SkUTF16_FromUnichar(uni, utf16);
  1.1940 +            }
  1.1941 +            srcCount = SkToInt(utf16 - src);
  1.1942 +            break;
  1.1943 +        }
  1.1944 +        case kUTF16_Encoding: {
  1.1945 +            src = reinterpret_cast<const UniChar*>(chars);
  1.1946 +            int extra = 0;
  1.1947 +            for (int i = 0; i < glyphCount; ++i) {
  1.1948 +                if (SkUTF16_IsHighSurrogate(src[i + extra])) {
  1.1949 +                    ++extra;
  1.1950 +                }
  1.1951 +            }
  1.1952 +            srcCount = glyphCount + extra;
  1.1953 +            break;
  1.1954 +        }
  1.1955 +        case kUTF32_Encoding: {
  1.1956 +            const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(chars);
  1.1957 +            UniChar* utf16 = charStorage.reset(2 * glyphCount);
  1.1958 +            src = utf16;
  1.1959 +            for (int i = 0; i < glyphCount; ++i) {
  1.1960 +                utf16 += SkUTF16_FromUnichar(utf32[i], utf16);
  1.1961 +            }
  1.1962 +            srcCount = SkToInt(utf16 - src);
  1.1963 +            break;
  1.1964 +        }
  1.1965 +    }
  1.1966 +
  1.1967 +    // If glyphs is NULL, CT still needs glyph storage for finding the first failure.
  1.1968 +    // Also, if there are any non-bmp code points, the provided 'glyphs' storage will be inadequate.
  1.1969 +    SkAutoSTMalloc<1024, uint16_t> glyphStorage;
  1.1970 +    uint16_t* macGlyphs = glyphs;
  1.1971 +    if (NULL == macGlyphs || srcCount > glyphCount) {
  1.1972 +        macGlyphs = glyphStorage.reset(srcCount);
  1.1973 +    }
  1.1974 +
  1.1975 +    bool allEncoded = CTFontGetGlyphsForCharacters(fFontRef, src, macGlyphs, srcCount);
  1.1976 +
  1.1977 +    // If there were any non-bmp, then copy and compact.
  1.1978 +    // If 'glyphs' is NULL, then compact glyphStorage in-place.
  1.1979 +    // If all are bmp and 'glyphs' is non-NULL, 'glyphs' already contains the compact glyphs.
  1.1980 +    // If some are non-bmp and 'glyphs' is non-NULL, copy and compact into 'glyphs'.
  1.1981 +    uint16_t* compactedGlyphs = glyphs;
  1.1982 +    if (NULL == compactedGlyphs) {
  1.1983 +        compactedGlyphs = macGlyphs;
  1.1984 +    }
  1.1985 +    if (srcCount > glyphCount) {
  1.1986 +        int extra = 0;
  1.1987 +        for (int i = 0; i < glyphCount; ++i) {
  1.1988 +            if (SkUTF16_IsHighSurrogate(src[i + extra])) {
  1.1989 +                ++extra;
  1.1990 +            }
  1.1991 +            compactedGlyphs[i] = macGlyphs[i + extra];
  1.1992 +        }
  1.1993 +    }
  1.1994 +
  1.1995 +    if (allEncoded) {
  1.1996 +        return glyphCount;
  1.1997 +    }
  1.1998 +
  1.1999 +    // If we got false, then we need to manually look for first failure.
  1.2000 +    for (int i = 0; i < glyphCount; ++i) {
  1.2001 +        if (0 == compactedGlyphs[i]) {
  1.2002 +            return i;
  1.2003 +        }
  1.2004 +    }
  1.2005 +    // Odd to get here, as we expected CT to have returned true up front.
  1.2006 +    return glyphCount;
  1.2007 +}
  1.2008 +
  1.2009 +int SkTypeface_Mac::onCountGlyphs() const {
  1.2010 +    return SkToInt(CTFontGetGlyphCount(fFontRef));
  1.2011 +}
  1.2012 +
  1.2013 +///////////////////////////////////////////////////////////////////////////////
  1.2014 +///////////////////////////////////////////////////////////////////////////////
  1.2015 +#if 1
  1.2016 +
  1.2017 +static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
  1.2018 +    AutoCFRelease<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
  1.2019 +    if (NULL == ref.get()) {
  1.2020 +        return false;
  1.2021 +    }
  1.2022 +    CFStringToSkString(ref, value);
  1.2023 +    return true;
  1.2024 +}
  1.2025 +
  1.2026 +static bool find_dict_float(CFDictionaryRef dict, CFStringRef name, float* value) {
  1.2027 +    CFNumberRef num;
  1.2028 +    return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num)
  1.2029 +    && CFNumberIsFloatType(num)
  1.2030 +    && CFNumberGetValue(num, kCFNumberFloatType, value);
  1.2031 +}
  1.2032 +
  1.2033 +#include "SkFontMgr.h"
  1.2034 +
  1.2035 +static int unit_weight_to_fontstyle(float unit) {
  1.2036 +    float value;
  1.2037 +    if (unit < 0) {
  1.2038 +        value = 100 + (1 + unit) * 300;
  1.2039 +    } else {
  1.2040 +        value = 400 + unit * 500;
  1.2041 +    }
  1.2042 +    return sk_float_round2int(value);
  1.2043 +}
  1.2044 +
  1.2045 +static int unit_width_to_fontstyle(float unit) {
  1.2046 +    float value;
  1.2047 +    if (unit < 0) {
  1.2048 +        value = 1 + (1 + unit) * 4;
  1.2049 +    } else {
  1.2050 +        value = 5 + unit * 4;
  1.2051 +    }
  1.2052 +    return sk_float_round2int(value);
  1.2053 +}
  1.2054 +
  1.2055 +static inline int sqr(int value) {
  1.2056 +    SkASSERT(SkAbs32(value) < 0x7FFF);  // check for overflow
  1.2057 +    return value * value;
  1.2058 +}
  1.2059 +
  1.2060 +// We normalize each axis (weight, width, italic) to be base-900
  1.2061 +static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
  1.2062 +    return sqr(a.weight() - b.weight()) +
  1.2063 +           sqr((a.width() - b.width()) * 100) +
  1.2064 +           sqr((a.isItalic() != b.isItalic()) * 900);
  1.2065 +}
  1.2066 +
  1.2067 +static SkFontStyle desc2fontstyle(CTFontDescriptorRef desc) {
  1.2068 +    AutoCFRelease<CFDictionaryRef> dict(
  1.2069 +        (CFDictionaryRef)CTFontDescriptorCopyAttribute(desc,
  1.2070 +                                                       kCTFontTraitsAttribute));
  1.2071 +    if (NULL == dict.get()) {
  1.2072 +        return SkFontStyle();
  1.2073 +    }
  1.2074 +
  1.2075 +    float weight, width, slant;
  1.2076 +    if (!find_dict_float(dict, kCTFontWeightTrait, &weight)) {
  1.2077 +        weight = 0;
  1.2078 +    }
  1.2079 +    if (!find_dict_float(dict, kCTFontWidthTrait, &width)) {
  1.2080 +        width = 0;
  1.2081 +    }
  1.2082 +    if (!find_dict_float(dict, kCTFontSlantTrait, &slant)) {
  1.2083 +        slant = 0;
  1.2084 +    }
  1.2085 +
  1.2086 +    return SkFontStyle(unit_weight_to_fontstyle(weight),
  1.2087 +                       unit_width_to_fontstyle(width),
  1.2088 +                       slant ? SkFontStyle::kItalic_Slant
  1.2089 +                       : SkFontStyle::kUpright_Slant);
  1.2090 +}
  1.2091 +
  1.2092 +struct NameFontStyleRec {
  1.2093 +    SkString    fFamilyName;
  1.2094 +    SkFontStyle fFontStyle;
  1.2095 +};
  1.2096 +
  1.2097 +static bool nameFontStyleProc(SkTypeface* face, SkTypeface::Style,
  1.2098 +                              void* ctx) {
  1.2099 +    SkTypeface_Mac* macFace = (SkTypeface_Mac*)face;
  1.2100 +    const NameFontStyleRec* rec = (const NameFontStyleRec*)ctx;
  1.2101 +
  1.2102 +    return macFace->fFontStyle == rec->fFontStyle &&
  1.2103 +           macFace->fName == rec->fFamilyName;
  1.2104 +}
  1.2105 +
  1.2106 +static SkTypeface* createFromDesc(CFStringRef cfFamilyName,
  1.2107 +                                  CTFontDescriptorRef desc) {
  1.2108 +    NameFontStyleRec rec;
  1.2109 +    CFStringToSkString(cfFamilyName, &rec.fFamilyName);
  1.2110 +    rec.fFontStyle = desc2fontstyle(desc);
  1.2111 +
  1.2112 +    SkTypeface* face = SkTypefaceCache::FindByProcAndRef(nameFontStyleProc,
  1.2113 +                                                         &rec);
  1.2114 +    if (face) {
  1.2115 +        return face;
  1.2116 +    }
  1.2117 +
  1.2118 +    AutoCFRelease<CFDictionaryRef> fontFamilyNameDictionary(
  1.2119 +        CFDictionaryCreate(kCFAllocatorDefault,
  1.2120 +                           (const void**)&kCTFontFamilyNameAttribute, (const void**)&cfFamilyName,
  1.2121 +                           1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
  1.2122 +    AutoCFRelease<CTFontDescriptorRef> fontDescriptor(
  1.2123 +        CTFontDescriptorCreateWithAttributes(fontFamilyNameDictionary));
  1.2124 +    AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithFontDescriptor(fontDescriptor, 0, NULL));
  1.2125 +    CTFontRef ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL, desc);
  1.2126 +    if (NULL == ctFont) {
  1.2127 +        return NULL;
  1.2128 +    }
  1.2129 +
  1.2130 +    SkString str;
  1.2131 +    CFStringToSkString(cfFamilyName, &str);
  1.2132 +
  1.2133 +    bool isFixedPitch;
  1.2134 +    (void)computeStyleBits(ctFont, &isFixedPitch);
  1.2135 +    SkFontID fontID = CTFontRef_to_SkFontID(ctFont);
  1.2136 +
  1.2137 +    face = SkNEW_ARGS(SkTypeface_Mac, (rec.fFontStyle, fontID, isFixedPitch,
  1.2138 +                                       ctFont, str.c_str()));
  1.2139 +    SkTypefaceCache::Add(face, face->style());
  1.2140 +    return face;
  1.2141 +}
  1.2142 +
  1.2143 +class SkFontStyleSet_Mac : public SkFontStyleSet {
  1.2144 +public:
  1.2145 +    SkFontStyleSet_Mac(CFStringRef familyName, CTFontDescriptorRef desc)
  1.2146 +        : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, NULL))
  1.2147 +        , fFamilyName(familyName)
  1.2148 +        , fCount(0) {
  1.2149 +        CFRetain(familyName);
  1.2150 +        if (NULL == fArray) {
  1.2151 +            fArray = CFArrayCreate(NULL, NULL, 0, NULL);
  1.2152 +        }
  1.2153 +        fCount = SkToInt(CFArrayGetCount(fArray));
  1.2154 +    }
  1.2155 +
  1.2156 +    virtual ~SkFontStyleSet_Mac() {
  1.2157 +        CFRelease(fArray);
  1.2158 +        CFRelease(fFamilyName);
  1.2159 +    }
  1.2160 +
  1.2161 +    virtual int count() SK_OVERRIDE {
  1.2162 +        return fCount;
  1.2163 +    }
  1.2164 +
  1.2165 +    virtual void getStyle(int index, SkFontStyle* style,
  1.2166 +                          SkString* name) SK_OVERRIDE {
  1.2167 +        SkASSERT((unsigned)index < (unsigned)fCount);
  1.2168 +        CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
  1.2169 +        if (style) {
  1.2170 +            *style = desc2fontstyle(desc);
  1.2171 +        }
  1.2172 +        if (name) {
  1.2173 +            if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
  1.2174 +                name->reset();
  1.2175 +            }
  1.2176 +        }
  1.2177 +    }
  1.2178 +
  1.2179 +    virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
  1.2180 +        SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray));
  1.2181 +        CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
  1.2182 +
  1.2183 +        return createFromDesc(fFamilyName, desc);
  1.2184 +    }
  1.2185 +
  1.2186 +    virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
  1.2187 +        if (0 == fCount) {
  1.2188 +            return NULL;
  1.2189 +        }
  1.2190 +        return createFromDesc(fFamilyName, findMatchingDesc(pattern));
  1.2191 +    }
  1.2192 +
  1.2193 +private:
  1.2194 +    CFArrayRef  fArray;
  1.2195 +    CFStringRef fFamilyName;
  1.2196 +    int         fCount;
  1.2197 +
  1.2198 +    CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
  1.2199 +        int bestMetric = SK_MaxS32;
  1.2200 +        CTFontDescriptorRef bestDesc = NULL;
  1.2201 +
  1.2202 +        for (int i = 0; i < fCount; ++i) {
  1.2203 +            CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, i);
  1.2204 +            int metric = compute_metric(pattern, desc2fontstyle(desc));
  1.2205 +            if (0 == metric) {
  1.2206 +                return desc;
  1.2207 +            }
  1.2208 +            if (metric < bestMetric) {
  1.2209 +                bestMetric = metric;
  1.2210 +                bestDesc = desc;
  1.2211 +            }
  1.2212 +        }
  1.2213 +        SkASSERT(bestDesc);
  1.2214 +        return bestDesc;
  1.2215 +    }
  1.2216 +};
  1.2217 +
  1.2218 +class SkFontMgr_Mac : public SkFontMgr {
  1.2219 +    CFArrayRef  fNames;
  1.2220 +    int         fCount;
  1.2221 +
  1.2222 +    CFStringRef stringAt(int index) const {
  1.2223 +        SkASSERT((unsigned)index < (unsigned)fCount);
  1.2224 +        return (CFStringRef)CFArrayGetValueAtIndex(fNames, index);
  1.2225 +    }
  1.2226 +
  1.2227 +    static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) {
  1.2228 +        AutoCFRelease<CFMutableDictionaryRef> cfAttr(
  1.2229 +                 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
  1.2230 +                                           &kCFTypeDictionaryKeyCallBacks,
  1.2231 +                                           &kCFTypeDictionaryValueCallBacks));
  1.2232 +
  1.2233 +        CFDictionaryAddValue(cfAttr, kCTFontFamilyNameAttribute, cfFamilyName);
  1.2234 +
  1.2235 +        AutoCFRelease<CTFontDescriptorRef> desc(
  1.2236 +                                CTFontDescriptorCreateWithAttributes(cfAttr));
  1.2237 +        return SkNEW_ARGS(SkFontStyleSet_Mac, (cfFamilyName, desc));
  1.2238 +    }
  1.2239 +
  1.2240 +public:
  1.2241 +    SkFontMgr_Mac()
  1.2242 +        : fNames(SkCTFontManagerCopyAvailableFontFamilyNames())
  1.2243 +        , fCount(fNames ? SkToInt(CFArrayGetCount(fNames)) : 0) {}
  1.2244 +
  1.2245 +    virtual ~SkFontMgr_Mac() {
  1.2246 +        CFSafeRelease(fNames);
  1.2247 +    }
  1.2248 +
  1.2249 +protected:
  1.2250 +    virtual int onCountFamilies() const SK_OVERRIDE {
  1.2251 +        return fCount;
  1.2252 +    }
  1.2253 +
  1.2254 +    virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
  1.2255 +        if ((unsigned)index < (unsigned)fCount) {
  1.2256 +            CFStringToSkString(this->stringAt(index), familyName);
  1.2257 +        } else {
  1.2258 +            familyName->reset();
  1.2259 +        }
  1.2260 +    }
  1.2261 +
  1.2262 +    virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
  1.2263 +        if ((unsigned)index >= (unsigned)fCount) {
  1.2264 +            return NULL;
  1.2265 +        }
  1.2266 +        return CreateSet(this->stringAt(index));
  1.2267 +    }
  1.2268 +
  1.2269 +    virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
  1.2270 +        AutoCFRelease<CFStringRef> cfName(make_CFString(familyName));
  1.2271 +        return CreateSet(cfName);
  1.2272 +    }
  1.2273 +
  1.2274 +    virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
  1.2275 +                                           const SkFontStyle&) const SK_OVERRIDE {
  1.2276 +        return NULL;
  1.2277 +    }
  1.2278 +
  1.2279 +    virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
  1.2280 +                                         const SkFontStyle&) const SK_OVERRIDE {
  1.2281 +        return NULL;
  1.2282 +    }
  1.2283 +
  1.2284 +    virtual SkTypeface* onCreateFromData(SkData* data,
  1.2285 +                                         int ttcIndex) const SK_OVERRIDE {
  1.2286 +        AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromData(data));
  1.2287 +        if (NULL == pr) {
  1.2288 +            return NULL;
  1.2289 +        }
  1.2290 +        return create_from_dataProvider(pr);
  1.2291 +    }
  1.2292 +
  1.2293 +    virtual SkTypeface* onCreateFromStream(SkStream* stream,
  1.2294 +                                           int ttcIndex) const SK_OVERRIDE {
  1.2295 +        AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromStream(stream));
  1.2296 +        if (NULL == pr) {
  1.2297 +            return NULL;
  1.2298 +        }
  1.2299 +        return create_from_dataProvider(pr);
  1.2300 +    }
  1.2301 +
  1.2302 +    virtual SkTypeface* onCreateFromFile(const char path[],
  1.2303 +                                         int ttcIndex) const SK_OVERRIDE {
  1.2304 +        AutoCFRelease<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path));
  1.2305 +        if (NULL == pr) {
  1.2306 +            return NULL;
  1.2307 +        }
  1.2308 +        return create_from_dataProvider(pr);
  1.2309 +    }
  1.2310 +
  1.2311 +    virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
  1.2312 +                                               unsigned styleBits) const SK_OVERRIDE {
  1.2313 +        return create_typeface(NULL, familyName, (SkTypeface::Style)styleBits);
  1.2314 +    }
  1.2315 +};
  1.2316 +
  1.2317 +///////////////////////////////////////////////////////////////////////////////
  1.2318 +
  1.2319 +SkFontMgr* SkFontMgr::Factory() {
  1.2320 +    return SkNEW(SkFontMgr_Mac);
  1.2321 +}
  1.2322 +#endif
  1.2323 +
  1.2324 +SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
  1.2325 +                                       const char famillyName[],
  1.2326 +                                       SkTypeface::Style style)
  1.2327 +{
  1.2328 +    SkDEBUGFAIL("SkFontHost::FindTypeface unimplemented");
  1.2329 +    return NULL;
  1.2330 +}
  1.2331 +
  1.2332 +SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream*)
  1.2333 +{
  1.2334 +    SkDEBUGFAIL("SkFontHost::CreateTypeface unimplemented");
  1.2335 +    return NULL;
  1.2336 +}
  1.2337 +
  1.2338 +SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*)
  1.2339 +{
  1.2340 +    SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
  1.2341 +    return NULL;
  1.2342 +}
  1.2343 +

mercurial