1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
20680d6c7caa9c2d4b1e5ee49e5816b96be0cc7bfreed@android.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
9b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include <vector>
10b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#ifdef SK_BUILD_FOR_MAC
11b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#import <ApplicationServices/ApplicationServices.h>
12b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#endif
13b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
14b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#ifdef SK_BUILD_FOR_IOS
15b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include <CoreText/CoreText.h>
163dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.com#include <CoreText/CTFontManager.h>
17b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include <CoreGraphics/CoreGraphics.h>
18b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include <CoreFoundation/CoreFoundation.h>
19b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#endif
200680d6c7caa9c2d4b1e5ee49e5816b96be0cc7bfreed@android.com
21b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkFontHost.h"
22b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkCGUtils.h"
23b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkColorPriv.h"
24b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkDescriptor.h"
25b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkEndian.h"
26b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkFontDescriptor.h"
27b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkFloatingPoint.h"
28b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkGlyph.h"
29b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkMaskGamma.h"
30b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkSFNTHeader.h"
31b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkOTTable_glyf.h"
32b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkOTTable_head.h"
33b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkOTTable_hhea.h"
34b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkOTTable_loca.h"
35b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkOTUtils.h"
36b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkPaint.h"
37b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkPath.h"
38b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkString.h"
39b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkStream.h"
40b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkThread.h"
41b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkTypeface_mac.h"
42b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkUtils.h"
43b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkTypefaceCache.h"
44ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com#include "SkFontMgr.h"
45bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com#include "SkUtils.h"
460680d6c7caa9c2d4b1e5ee49e5816b96be0cc7bfreed@android.com
47f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com//#define HACK_COLORGLYPHS
48f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com
49b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgclass SkScalerContext_Mac;
50b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
513dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.com// CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we
523dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.com// provide a wrapper here that will return an empty array if need be.
533dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.comstatic CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() {
543dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.com#ifdef SK_BUILD_FOR_IOS
553dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.com    return CFArrayCreate(NULL, NULL, 0, NULL);
563dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.com#else
573dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.com    return CTFontManagerCopyAvailableFontFamilyNames();
583dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.com#endif
593dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.com}
603dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.com
613dcbd4673d7ee03ded1c08e6d58713cb07e9d1f1reed@google.com
62b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// Being templated and taking const T* prevents calling
63b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// CFSafeRelease(autoCFRelease) through implicit conversion.
64b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtemplate <typename T> static void CFSafeRelease(/*CFTypeRef*/const T* cfTypeRef) {
65b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (cfTypeRef) {
66b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CFRelease(cfTypeRef);
67b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
68b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
69b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
70b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// Being templated and taking const T* prevents calling
71b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// CFSafeRetain(autoCFRelease) through implicit conversion.
72b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtemplate <typename T> static void CFSafeRetain(/*CFTypeRef*/const T* cfTypeRef) {
73b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (cfTypeRef) {
74b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CFRetain(cfTypeRef);
75b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
76b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
77b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
78b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org/** Acts like a CFRef, but calls CFSafeRelease when it goes out of scope. */
79b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtemplate<typename CFRef> class AutoCFRelease : private SkNoncopyable {
80b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgpublic:
81b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    explicit AutoCFRelease(CFRef cfRef = NULL) : fCFRef(cfRef) { }
82b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    ~AutoCFRelease() { CFSafeRelease(fCFRef); }
83b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
84b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    void reset(CFRef that = NULL) {
85b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CFSafeRetain(that);
86b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CFSafeRelease(fCFRef);
87b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        fCFRef = that;
88b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
89b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
90b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease& operator =(CFRef that) {
91b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        reset(that);
92b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return *this;
93b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
94b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
95b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    operator CFRef() const { return fCFRef; }
96b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CFRef get() const { return fCFRef; }
97b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
98a980269c2498836101146adc729ef780fb89824ebungeman@google.com    CFRef* operator&() { SkASSERT(fCFRef == NULL); return &fCFRef; }
99b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgprivate:
100b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CFRef fCFRef;
101b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org};
102b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
103964988f0e93f4a559b7e41db53d70d0282527350reed@google.comstatic CFStringRef make_CFString(const char str[]) {
104964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    return CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
105964988f0e93f4a559b7e41db53d70d0282527350reed@google.com}
106964988f0e93f4a559b7e41db53d70d0282527350reed@google.com
107b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtemplate<typename T> class AutoCGTable : SkNoncopyable {
108b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgpublic:
109b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCGTable(CGFontRef font)
110b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    //Undocumented: the tag parameter in this call is expected in machine order and not BE order.
111b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    : fCFData(CGFontCopyTableForTag(font, SkSetFourByteTag(T::TAG0, T::TAG1, T::TAG2, T::TAG3)))
112b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    , fData(fCFData ? reinterpret_cast<const T*>(CFDataGetBytePtr(fCFData)) : NULL)
113b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    { }
114b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
115b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const T* operator->() const { return fData; }
116b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
117b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgprivate:
118b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CFDataRef> fCFData;
119b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgpublic:
120b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const T* fData;
121b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org};
122b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
123b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// inline versions of these rect helpers
124b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
125b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic bool CGRectIsEmpty_inline(const CGRect& rect) {
126b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return rect.size.width <= 0 || rect.size.height <= 0;
127b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
128b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
129b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic CGFloat CGRectGetMinX_inline(const CGRect& rect) {
130b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return rect.origin.x;
131b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
132b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
133b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic CGFloat CGRectGetMaxX_inline(const CGRect& rect) {
134b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return rect.origin.x + rect.size.width;
135b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
136b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
137b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic CGFloat CGRectGetMinY_inline(const CGRect& rect) {
138b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return rect.origin.y;
139b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
140b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
141b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic CGFloat CGRectGetMaxY_inline(const CGRect& rect) {
142b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return rect.origin.y + rect.size.height;
143b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
144b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
145b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic CGFloat CGRectGetWidth_inline(const CGRect& rect) {
146b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return rect.size.width;
147b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
148b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
149b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
150b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
151b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic void sk_memset_rect32(uint32_t* ptr, uint32_t value,
1527fa2a65c0cfc714364490cb715171461143024e0reed@google.com                             int width, int height, size_t rowBytes) {
153b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkASSERT(width);
154b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkASSERT(width * sizeof(uint32_t) <= rowBytes);
155b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
156b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (width >= 32) {
157b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        while (height) {
158b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            sk_memset32(ptr, value, width);
159b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            ptr = (uint32_t*)((char*)ptr + rowBytes);
160b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            height -= 1;
161b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
162b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return;
163b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
164b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
165b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    rowBytes -= width * sizeof(uint32_t);
166b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
167b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (width >= 8) {
168b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        while (height) {
169b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            int w = width;
170b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            do {
171b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                *ptr++ = value; *ptr++ = value;
172b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                *ptr++ = value; *ptr++ = value;
173b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                *ptr++ = value; *ptr++ = value;
174b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                *ptr++ = value; *ptr++ = value;
175b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                w -= 8;
176b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            } while (w >= 8);
177b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            while (--w >= 0) {
178b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                *ptr++ = value;
179b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            }
180b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            ptr = (uint32_t*)((char*)ptr + rowBytes);
181b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            height -= 1;
182b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
183b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    } else {
184b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        while (height) {
185b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            int w = width;
186b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            do {
187b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                *ptr++ = value;
188b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            } while (--w > 0);
189b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            ptr = (uint32_t*)((char*)ptr + rowBytes);
190b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            height -= 1;
191b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
192b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
193b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
194b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
195b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include <sys/utsname.h>
196b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
197b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtypedef uint32_t CGRGBPixel;
198b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
199b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) {
200b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return pixel & 0xFF;
201b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
202b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
203b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// The calls to support subpixel are present in 10.5, but are not included in
204b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// the 10.5 SDK. The needed calls have been extracted from the 10.6 SDK and are
205b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// included below. To verify that CGContextSetShouldSubpixelQuantizeFonts, for
206b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// instance, is present in the 10.5 CoreGraphics libary, use:
207b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org//   cd /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/
208b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org//   cd ApplicationServices.framework/Frameworks/CoreGraphics.framework/
209b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org//   nm CoreGraphics | grep CGContextSetShouldSubpixelQuantizeFonts
210b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
211b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#if !defined(MAC_OS_X_VERSION_10_6) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6)
212b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgCG_EXTERN void CGContextSetAllowsFontSmoothing(CGContextRef context, bool value);
213b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgCG_EXTERN void CGContextSetAllowsFontSubpixelPositioning(CGContextRef context, bool value);
214b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgCG_EXTERN void CGContextSetShouldSubpixelPositionFonts(CGContextRef context, bool value);
215b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgCG_EXTERN void CGContextSetAllowsFontSubpixelQuantization(CGContextRef context, bool value);
216b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgCG_EXTERN void CGContextSetShouldSubpixelQuantizeFonts(CGContextRef context, bool value);
21704225dcdec5a01bc9889b7fb03e7aceb87fccc6ereed@android.com#endif
2180bf64d48cc18d551dadc7cce0c990352e04f9af8reed@android.com
219b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic const char FONT_DEFAULT_NAME[] = "Lucida Sans";
220b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
221b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// See Source/WebKit/chromium/base/mac/mac_util.mm DarwinMajorVersionInternal for original source.
222b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic int readVersion() {
223b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    struct utsname info;
224b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (uname(&info) != 0) {
225b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkDebugf("uname failed\n");
226b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return 0;
227b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
228b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (strcmp(info.sysname, "Darwin") != 0) {
229b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkDebugf("unexpected uname sysname %s\n", info.sysname);
230b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return 0;
231b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
232b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    char* dot = strchr(info.release, '.');
233b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!dot) {
234b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkDebugf("expected dot in uname release %s\n", info.release);
235b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return 0;
236b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
237b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    int version = atoi(info.release);
238b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (version == 0) {
239b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkDebugf("could not parse uname release %s\n", info.release);
240b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
241b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return version;
242b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
243b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
244b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic int darwinVersion() {
245b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    static int darwin_version = readVersion();
246b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return darwin_version;
247b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
248b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
249b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic bool isSnowLeopard() {
250b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return darwinVersion() == 10;
251b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
252b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
253b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic bool isLion() {
254b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return darwinVersion() == 11;
255b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
256b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
257b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic bool isMountainLion() {
258b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return darwinVersion() == 12;
259b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
260b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
261b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic bool isLCDFormat(unsigned format) {
262b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return SkMask::kLCD16_Format == format || SkMask::kLCD32_Format == format;
263b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
264b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
265b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic CGFloat ScalarToCG(SkScalar scalar) {
266b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (sizeof(CGFloat) == sizeof(float)) {
267b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return SkScalarToFloat(scalar);
268b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    } else {
269b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkASSERT(sizeof(CGFloat) == sizeof(double));
270b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return (CGFloat) SkScalarToDouble(scalar);
271b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
272b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
273b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
274b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic SkScalar CGToScalar(CGFloat cgFloat) {
275b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (sizeof(CGFloat) == sizeof(float)) {
2764b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org        return cgFloat;
277b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    } else {
278b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkASSERT(sizeof(CGFloat) == sizeof(double));
279b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return SkDoubleToScalar(cgFloat);
280b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
281b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
282b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
283b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix,
284b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                                   SkScalar sx = SK_Scalar1,
285b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                                   SkScalar sy = SK_Scalar1) {
286b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx),
287b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                 -ScalarToCG(matrix[SkMatrix::kMSkewY]  * sy),
288b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                 -ScalarToCG(matrix[SkMatrix::kMSkewX]  * sx),
289b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                  ScalarToCG(matrix[SkMatrix::kMScaleY] * sy),
290b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                  ScalarToCG(matrix[SkMatrix::kMTransX] * sx),
291b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                  ScalarToCG(matrix[SkMatrix::kMTransY] * sy));
292b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
293b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
294b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
295b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
296b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
297b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#define BITMAP_INFO_GRAY (kCGImageAlphaNone)
298b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
299b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org/**
300b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org * There does not appear to be a publicly accessable API for determining if lcd
301b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org * font smoothing will be applied if we request it. The main issue is that if
302b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0.
303b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org */
304b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic bool supports_LCD() {
305b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    static int gSupportsLCD = -1;
306b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (gSupportsLCD >= 0) {
307b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return (bool) gSupportsLCD;
308b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
309b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint32_t rgb = 0;
310b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
311b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CGContextRef> cgContext(CGBitmapContextCreate(&rgb, 1, 1, 8, 4,
312b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                                                colorspace, BITMAP_INFO_RGB));
313b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGContextSelectFont(cgContext, "Helvetica", 16, kCGEncodingMacRoman);
314b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGContextSetShouldSmoothFonts(cgContext, true);
315b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGContextSetShouldAntialias(cgContext, true);
316b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGContextSetTextDrawingMode(cgContext, kCGTextFill);
317b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGContextSetGrayFillColor(cgContext, 1, 1);
318b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1);
319b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint32_t r = (rgb >> 16) & 0xFF;
320b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint32_t g = (rgb >>  8) & 0xFF;
321b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint32_t b = (rgb >>  0) & 0xFF;
322b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    gSupportsLCD = (r != g || r != b);
323b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return (bool) gSupportsLCD;
324b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
325b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
326b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgclass Offscreen {
327b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgpublic:
328b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    Offscreen();
329b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
330b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
331b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                      CGGlyph glyphID, size_t* rowBytesPtr,
332b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                      bool generateA8FromLCD);
333b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
334b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgprivate:
335b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    enum {
336b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        kSize = 32 * 32 * sizeof(CGRGBPixel)
337b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    };
338b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkAutoSMalloc<kSize> fImageStorage;
339b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CGColorSpaceRef> fRGBSpace;
340b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
341b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // cached state
342b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CGContextRef> fCG;
343b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkISize fSize;
344b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    bool fDoAA;
345b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    bool fDoLCD;
346b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
347b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    static int RoundSize(int dimension) {
348b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return SkNextPow2(dimension);
349b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
350b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org};
351b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
352d55846d100bb09448b398b41798bd4ab100a753askia.committer@gmail.comOffscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL),
35387379e17c5e95c6fe0d88b3b9ae134355cfafc66robertphillips@google.com                         fDoAA(false), fDoLCD(false) {
354b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    fSize.set(0, 0);
355b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
356b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
357b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
358b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
359fe74765f0d302669ae49e68074492bdfe0ce6e6fbungeman@google.comstatic SkTypeface::Style computeStyleBits(CTFontRef font, bool* isFixedPitch) {
360b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    unsigned style = SkTypeface::kNormal;
361b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font);
362b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
363b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (traits & kCTFontBoldTrait) {
364b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        style |= SkTypeface::kBold;
365b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
366b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (traits & kCTFontItalicTrait) {
367b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        style |= SkTypeface::kItalic;
368b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
369fe74765f0d302669ae49e68074492bdfe0ce6e6fbungeman@google.com    if (isFixedPitch) {
370fe74765f0d302669ae49e68074492bdfe0ce6e6fbungeman@google.com        *isFixedPitch = (traits & kCTFontMonoSpaceTrait) != 0;
371b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
372b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return (SkTypeface::Style)style;
373b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
374b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
375b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic SkFontID CTFontRef_to_SkFontID(CTFontRef fontRef) {
376b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkFontID id = 0;
377b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// CTFontGetPlatformFont and ATSFontRef are not supported on iOS, so we have to
378b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// bracket this to be Mac only.
379b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#ifdef SK_BUILD_FOR_MAC
380b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    ATSFontRef ats = CTFontGetPlatformFont(fontRef, NULL);
381b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    id = (SkFontID)ats;
382b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (id != 0) {
383b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        id &= 0x3FFFFFFF; // make top two bits 00
384b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return id;
385b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
386b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#endif
387b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // CTFontGetPlatformFont returns NULL if the font is local
388b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // (e.g., was created by a CSS3 @font-face rule).
389b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fontRef, NULL));
390b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCGTable<SkOTTableHead> headTable(cgFont);
391b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (headTable.fData) {
392b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        id = (SkFontID) headTable->checksumAdjustment;
393b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        id = (id & 0x3FFFFFFF) | 0x40000000; // make top two bits 01
394b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
395b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // well-formed fonts have checksums, but as a last resort, use the pointer.
396b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (id == 0) {
397b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        id = (SkFontID) (uintptr_t) fontRef;
398b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        id = (id & 0x3FFFFFFF) | 0x80000000; // make top two bits 10
399b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
400b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return id;
401b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
402b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
403ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.comstatic SkFontStyle stylebits2fontstyle(SkTypeface::Style styleBits) {
404ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    return SkFontStyle((styleBits & SkTypeface::kBold)
405ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com                           ? SkFontStyle::kBold_Weight
406ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com                           : SkFontStyle::kNormal_Weight,
407ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com                       SkFontStyle::kNormal_Width,
408ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com                       (styleBits & SkTypeface::kItalic)
409ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com                           ? SkFontStyle::kItalic_Slant
410ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com                           : SkFontStyle::kUpright_Slant);
411ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com}
412ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com
413ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com#define WEIGHT_THRESHOLD    ((SkFontStyle::kNormal_Weight + SkFontStyle::kBold_Weight)/2)
414ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com
415ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.comstatic SkTypeface::Style fontstyle2stylebits(const SkFontStyle& fs) {
416ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    unsigned style = 0;
417ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    if (fs.width() >= WEIGHT_THRESHOLD) {
418ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        style |= SkTypeface::kBold;
419ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    }
420ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    if (fs.isItalic()) {
421ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        style |= SkTypeface::kItalic;
422ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    }
423ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    return (SkTypeface::Style)style;
424ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com}
425ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com
426b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgclass SkTypeface_Mac : public SkTypeface {
427b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgpublic:
428fe74765f0d302669ae49e68074492bdfe0ce6e6fbungeman@google.com    SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isFixedPitch,
429b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                   CTFontRef fontRef, const char name[])
430ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        : SkTypeface(style, fontID, isFixedPitch)
431ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        , fName(name)
432ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        , fFontRef(fontRef) // caller has already called CFRetain for us
433ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        , fFontStyle(stylebits2fontstyle(style))
434b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    {
435b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkASSERT(fontRef);
436b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
43737cbc7fd014e3b35833523dbdbe3bc3ac52ecacdskia.committer@gmail.com
438ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    SkTypeface_Mac(const SkFontStyle& fs, SkFontID fontID, bool isFixedPitch,
439ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com                   CTFontRef fontRef, const char name[])
440ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        : SkTypeface(fontstyle2stylebits(fs), fontID, isFixedPitch)
441ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        , fName(name)
442ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        , fFontRef(fontRef) // caller has already called CFRetain for us
443ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        , fFontStyle(fs)
444ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    {
445ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        SkASSERT(fontRef);
446ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    }
44737cbc7fd014e3b35833523dbdbe3bc3ac52ecacdskia.committer@gmail.com
448b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkString fName;
449b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CTFontRef> fFontRef;
450ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    SkFontStyle fFontStyle;
451b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
452b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgprotected:
453b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    friend class SkFontHost;    // to access our protected members for deprecated methods
454b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
455b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    virtual int onGetUPEM() const SK_OVERRIDE;
456cc9aad5787b52216f46b9d6d95a781240e3e6b6breed@google.com    virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
457839702b61934914118ec557dd641be322eba3b5fbungeman@google.com    virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
458b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
459b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    virtual size_t onGetTableData(SkFontTableTag, size_t offset,
460b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                  size_t length, void* data) const SK_OVERRIDE;
461b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
462b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
4635526ede94a2fc58bcf6b578b12a29f6addad776dreed@google.com    virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
4642689f615e364dc48ad73826564f5b13d2329179dreed@google.com    virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
4652689f615e364dc48ad73826564f5b13d2329179dreed@google.com                                SkAdvancedTypefaceMetrics::PerGlyphInfo,
4662689f615e364dc48ad73826564f5b13d2329179dreed@google.com                                const uint32_t*, uint32_t) const SK_OVERRIDE;
467bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[],
468bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com                                int glyphCount) const SK_OVERRIDE;
469bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    virtual int onCountGlyphs() const SK_OVERRIDE;
470c1641fc92259a1ca5cfc32cd5c8c55ea316b2bd1skia.committer@gmail.com
471b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgprivate:
472ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com
473b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    typedef SkTypeface INHERITED;
474b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org};
475b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
476b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) {
477b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkASSERT(fontRef);
478fe74765f0d302669ae49e68074492bdfe0ce6e6fbungeman@google.com    bool isFixedPitch;
479fe74765f0d302669ae49e68074492bdfe0ce6e6fbungeman@google.com    SkTypeface::Style style = computeStyleBits(fontRef, &isFixedPitch);
480b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
481b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
482fe74765f0d302669ae49e68074492bdfe0ce6e6fbungeman@google.com    return new SkTypeface_Mac(style, fontID, isFixedPitch, fontRef, name);
483b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
484b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
485b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic SkTypeface* NewFromName(const char familyName[], SkTypeface::Style theStyle) {
486b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CTFontRef ctFont = NULL;
487b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
488b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CTFontSymbolicTraits ctFontTraits = 0;
489b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (theStyle & SkTypeface::kBold) {
490b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        ctFontTraits |= kCTFontBoldTrait;
491b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
492b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (theStyle & SkTypeface::kItalic) {
493b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        ctFontTraits |= kCTFontItalicTrait;
494b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
495b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
496b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Create the font info
497964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    AutoCFRelease<CFStringRef> cfFontName(make_CFString(familyName));
498b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
499b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CFNumberRef> cfFontTraits(
500b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits));
501b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
502b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CFMutableDictionaryRef> cfAttributes(
503b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
504b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                      &kCFTypeDictionaryKeyCallBacks,
505b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                      &kCFTypeDictionaryValueCallBacks));
506b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
507b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CFMutableDictionaryRef> cfTraits(
508b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
509b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                      &kCFTypeDictionaryKeyCallBacks,
510b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                      &kCFTypeDictionaryValueCallBacks));
511b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
512b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Create the font
513b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) {
514b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits);
515b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
516b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName);
517b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits);
518b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
519b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        AutoCFRelease<CTFontDescriptorRef> ctFontDesc(
520b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                CTFontDescriptorCreateWithAttributes(cfAttributes));
521b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
522b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        if (ctFontDesc != NULL) {
523cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com            ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL);
524b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
525b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
526b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
527b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return ctFont ? NewFromFontRef(ctFont, familyName) : NULL;
528b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
529b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
530b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic SkTypeface* GetDefaultFace() {
531b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SK_DECLARE_STATIC_MUTEX(gMutex);
532b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkAutoMutexAcquire ma(gMutex);
533b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
534b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    static SkTypeface* gDefaultFace;
535b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
536b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (NULL == gDefaultFace) {
537b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        gDefaultFace = NewFromName(FONT_DEFAULT_NAME, SkTypeface::kNormal);
538b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkTypefaceCache::Add(gDefaultFace, SkTypeface::kNormal);
539b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
540b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return gDefaultFace;
541b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
542b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
543b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
544b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
545b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgextern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face);
546b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgCTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) {
547b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const SkTypeface_Mac* macface = (const SkTypeface_Mac*)face;
548b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return macface ? macface->fFontRef.get() : NULL;
549b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
550b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
551b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org/*  This function is visible on the outside. It first searches the cache, and if
552b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org *  not found, returns a new entry (after adding it to the cache).
553b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org */
554b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgSkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) {
555b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
556b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkTypeface* face = SkTypefaceCache::FindByID(fontID);
557b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (face) {
558b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        face->ref();
559b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    } else {
560b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        face = NewFromFontRef(fontRef, NULL);
561b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkTypefaceCache::Add(face, face->style());
562b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // NewFromFontRef doesn't retain the parameter, but the typeface it
563b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // creates does release it in its destructor, so we balance that with
564b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // a retain call here.
565b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CFRetain(fontRef);
566b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
567b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkASSERT(face->getRefCnt() > 1);
568b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return face;
569b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
570b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
571b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstruct NameStyleRec {
572b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const char*         fName;
573b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkTypeface::Style   fStyle;
574b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org};
575b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
576b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style,
577b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                            void* ctx) {
578b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
579b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx);
580b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
581b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return rec->fStyle == style && mface->fName.equals(rec->fName);
582b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
583b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
584b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic const char* map_css_names(const char* name) {
585b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    static const struct {
586b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        const char* fFrom;  // name the caller specified
587b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        const char* fTo;    // "canonical" name we map to
588b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    } gPairs[] = {
589b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        { "sans-serif", "Helvetica" },
590b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        { "serif",      "Times"     },
591b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        { "monospace",  "Courier"   }
592b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    };
593b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
594b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
595b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        if (strcmp(name, gPairs[i].fFrom) == 0) {
596b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            return gPairs[i].fTo;
597b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
598b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
599b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return name;    // no change
600b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
601b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
6027fdcd444a1bd6a2f173c141e09e7ad9c11730ad2reed@google.comstatic SkTypeface* create_typeface(const SkTypeface* familyFace,
6037fdcd444a1bd6a2f173c141e09e7ad9c11730ad2reed@google.com                                   const char familyName[],
6047fdcd444a1bd6a2f173c141e09e7ad9c11730ad2reed@google.com                                   SkTypeface::Style style) {
605b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (familyName) {
606b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        familyName = map_css_names(familyName);
607b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
60876015b09536c664bd59b370be7691d4b69553d95skia.committer@gmail.com
609b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Clone an existing typeface
610b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // TODO: only clone if style matches the familyFace's style...
611b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (familyName == NULL && familyFace != NULL) {
612b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        familyFace->ref();
613b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return const_cast<SkTypeface*>(familyFace);
614b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
61576015b09536c664bd59b370be7691d4b69553d95skia.committer@gmail.com
616b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!familyName || !*familyName) {
617b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        familyName = FONT_DEFAULT_NAME;
618b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
61976015b09536c664bd59b370be7691d4b69553d95skia.committer@gmail.com
620b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    NameStyleRec rec = { familyName, style };
621b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByNameStyle, &rec);
62276015b09536c664bd59b370be7691d4b69553d95skia.committer@gmail.com
623b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (NULL == face) {
624b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        face = NewFromName(familyName, style);
625b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        if (face) {
626b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            SkTypefaceCache::Add(face, style);
627b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        } else {
628b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            face = GetDefaultFace();
629b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            face->ref();
630b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
631b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
632b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return face;
633b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
634b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
635b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
636b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
637cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com/** GlyphRect is in FUnits (em space, y up). */
638b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstruct GlyphRect {
639b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    int16_t fMinX;
640b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    int16_t fMinY;
641b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    int16_t fMaxX;
642b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    int16_t fMaxY;
643b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org};
644b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
645b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgclass SkScalerContext_Mac : public SkScalerContext {
646b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgpublic:
6470da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com    SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*);
648b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
649b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgprotected:
650b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    unsigned generateGlyphCount(void) SK_OVERRIDE;
651b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
652b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
653b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
654b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
655b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
656b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE;
657b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
658b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgprivate:
659b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    static void CTPathElement(void *info, const CGPathElement *element);
660539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
661cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */
662cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const;
663cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com
664cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    /** Initializes and returns the value of fFBoundingBoxesGlyphOffset.
665cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *
666cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  For use with (and must be called before) generateBBoxes.
667cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     */
668cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    uint16_t getFBoundingBoxesGlyphOffset();
669539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
670cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    /** Initializes fFBoundingBoxes and returns true on success.
671cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *
672cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
673cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  return a bad value in bounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
674cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
675cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  font directly.
676cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *
677cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  This routine initializes fFBoundingBoxes to an array of
678cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  fGlyphCount - fFBoundingBoxesGlyphOffset GlyphRects which contain the bounds in FUnits
679cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  (em space, y up) of glyphs with ids in the range [fFBoundingBoxesGlyphOffset, fGlyphCount).
680cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *
681cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  Returns true if fFBoundingBoxes is properly initialized. The table can only be properly
682cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  initialized for a TrueType font with 'head', 'loca', and 'glyf' tables.
683cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *
684cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  TODO: A future optimization will compute fFBoundingBoxes once per fCTFont.
685cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     */
686b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    bool generateBBoxes();
687b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
688cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down).
689cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *
690cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs.
691cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  Used on Lion to correct CTFontGetBoundingRectsForGlyphs.
692cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     */
693cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    SkMatrix fFUnitMatrix;
694539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
695b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    Offscreen fOffscreen;
696b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CTFontRef> fCTFont;
697539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
698cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    /** Vertical variant of fCTFont.
699cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *
700cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise.
701cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  This makes kCTFontDefaultOrientation dangerous, because the metrics from
702cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  kCTFontHorizontalOrientation are in a different space from kCTFontVerticalOrientation.
703cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     *  Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in the same space.
704cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com     */
705cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    AutoCFRelease<CTFontRef> fCTVerticalFont;
706539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
707b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CGFontRef> fCGFont;
708cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    SkAutoTMalloc<GlyphRect> fFBoundingBoxes;
709b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint16_t fFBoundingBoxesGlyphOffset;
710b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint16_t fGlyphCount;
711b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    bool fGeneratedFBoundingBoxes;
712cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    const bool fDoSubPosition;
713cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    const bool fVertical;
714cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com
715b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    friend class Offscreen;
7160da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com
7170da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com    typedef SkScalerContext INHERITED;
718b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org};
719b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
7200da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.comSkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
7210da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com                                         const SkDescriptor* desc)
7220da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com        : INHERITED(typeface, desc)
723cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        , fFBoundingBoxes()
724b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        , fFBoundingBoxesGlyphOffset(0)
725b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        , fGeneratedFBoundingBoxes(false)
726cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
727cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        , fVertical(SkToBool(fRec.fFlags & kVertical_Flag))
728cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com
729b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org{
7302689f615e364dc48ad73826564f5b13d2329179dreed@google.com    CTFontRef ctFont = typeface->fFontRef.get();
731b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
732cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
733cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    fGlyphCount = SkToU16(numGlyphs);
734539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
735cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    fRec.getSingleMatrix(&fFUnitMatrix);
736cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix);
737cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com
738b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
739b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (fVertical) {
740b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMutable(
741b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                kCFAllocatorDefault, 0,
742b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                &kCFTypeDictionaryKeyCallBacks,
743b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                &kCFTypeDictionaryValueCallBacks));
744b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        if (cfAttributes) {
745b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
746b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate(
747b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                    kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation));
748b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVertical);
749b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
750b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
751b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
752cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // Since our matrix includes everything, we pass 1 for size.
753cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, ctFontDesc);
754b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL);
755b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (fVertical) {
756b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
757b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        transform = CGAffineTransformConcat(rotateLeft, transform);
758cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, NULL);
759b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
760371add80f51205d53391840164f37ade6aff8012commit-bot@chromium.org
761cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFont)));
762cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit);
763b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
764b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
765b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgCGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
766b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                             CGGlyph glyphID, size_t* rowBytesPtr,
767b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                             bool generateA8FromLCD) {
768b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!fRGBSpace) {
769b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        //It doesn't appear to matter what color space is specified.
770b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        //Regular blends and antialiased text are always (s*a + d*(1-a))
771b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        //and smoothed text is always g=2.0.
772b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        fRGBSpace = CGColorSpaceCreateDeviceRGB();
773b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
774b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
775b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // default to kBW_Format
776b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    bool doAA = false;
777b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    bool doLCD = false;
778b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
779b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (SkMask::kBW_Format != glyph.fMaskFormat) {
780b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        doLCD = true;
781b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        doAA = true;
782b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
783b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
784b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // FIXME: lcd smoothed un-hinted rasterization unsupported.
785b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) {
786b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        doLCD = false;
787b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        doAA = true;
788b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
789b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
790b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
791b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
792b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        if (fSize.fWidth < glyph.fWidth) {
793b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            fSize.fWidth = RoundSize(glyph.fWidth);
794b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
795b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        if (fSize.fHeight < glyph.fHeight) {
796b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            fSize.fHeight = RoundSize(glyph.fHeight);
797b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
798b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
799b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
800b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
801b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
802b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                    rowBytes, fRGBSpace, BITMAP_INFO_RGB);
803b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
804b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // skia handles quantization itself, so we disable this for cg to get
805b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // full fractional data from them.
806b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGContextSetAllowsFontSubpixelQuantization(fCG, false);
807b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
808b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
809b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGContextSetTextDrawingMode(fCG, kCGTextFill);
810b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGContextSetFont(fCG, context.fCGFont);
811cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        CGContextSetFontSize(fCG, 1 /*CTFontGetSize(context.fCTFont)*/);
812cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
813b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
814cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // Because CG always draws from the horizontal baseline,
815cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // if there is a non-integral translation from the horizontal origin to the vertical origin,
816cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // then CG cannot draw the glyph in the correct location without subpixel positioning.
817cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical);
818cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || context.fVertical);
819b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
820b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // Draw white on black to create mask.
821b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // TODO: Draw black on white and invert, CG has a special case codepath.
822b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGContextSetGrayFillColor(fCG, 1.0f, 1.0f);
823b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
824b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // force our checks below to happen
825b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        fDoAA = !doAA;
826b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        fDoLCD = !doLCD;
827b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
828b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
829b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (fDoAA != doAA) {
830b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGContextSetShouldAntialias(fCG, doAA);
831b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        fDoAA = doAA;
832b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
833b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (fDoLCD != doLCD) {
834b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGContextSetShouldSmoothFonts(fCG, doLCD);
835b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        fDoLCD = doLCD;
836b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
837b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
838b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
839b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // skip rows based on the glyph's height
840b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
841b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
842b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // erase to black
843b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes);
844b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
845b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    float subX = 0;
846b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    float subY = 0;
847b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (context.fDoSubPosition) {
848b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        subX = SkFixedToFloat(glyph.getSubXFixed());
849b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        subY = SkFixedToFloat(glyph.getSubYFixed());
850b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
851539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
852cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // CGContextShowGlyphsAtPoint always draws using the horizontal baseline origin.
853b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (context.fVertical) {
854cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        SkPoint offset;
855b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        context.getVerticalOffset(glyphID, &offset);
856b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        subX += offset.fX;
857b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        subY += offset.fY;
858b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
859539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
860b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX,
861b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                               glyph.fTop + glyph.fHeight - subY,
862b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                               &glyphID, 1);
863b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
864b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkASSERT(rowBytesPtr);
865b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    *rowBytesPtr = rowBytes;
866b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return image;
867b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
868b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
869cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.comvoid SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const {
870cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up).
871cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // Lion and Leopard return cgVertOffset in CG units (pixels, y up).
872cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    CGSize cgVertOffset;
873cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1);
874cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com
875cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) };
876cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    if (isSnowLeopard()) {
877cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
878cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        fFUnitMatrix.mapPoints(&skVertOffset, 1);
879cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    } else {
880cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // From CG units (pixels, y up) to SkGlyph units (pixels, y down).
881cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        skVertOffset.fY = -skVertOffset.fY;
882cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    }
883539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
884cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    *offset = skVertOffset;
885cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com}
886b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
887b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orguint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() {
888b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (fFBoundingBoxesGlyphOffset) {
889b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return fFBoundingBoxesGlyphOffset;
890b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
891b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts
892b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont);
893b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (hheaTable.fData) {
894b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetrics);
895b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
896b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return fFBoundingBoxesGlyphOffset;
897b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
898b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
899b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgbool SkScalerContext_Mac::generateBBoxes() {
900b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (fGeneratedFBoundingBoxes) {
901cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        return NULL != fFBoundingBoxes.get();
902b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
903b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    fGeneratedFBoundingBoxes = true;
904b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
905b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCGTable<SkOTTableHead> headTable(fCGFont);
906b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!headTable.fData) {
907b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return false;
908b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
909b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
910b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCGTable<SkOTTableIndexToLocation> locaTable(fCGFont);
911b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!locaTable.fData) {
912b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return false;
913b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
914b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
915b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont);
916b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!glyfTable.fData) {
917b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return false;
918b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
919b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
920b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset;
921cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    fFBoundingBoxes.reset(entries);
922b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
923b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat;
924b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, locaFormat);
925b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    glyphDataIter.advance(fFBoundingBoxesGlyphOffset);
926b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundingBoxesIndex) {
927b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        const SkOTTableGlyphData* glyphData = glyphDataIter.next();
928b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex];
929b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        rect.fMinX = SkEndian_SwapBE16(glyphData->xMin);
930b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        rect.fMinY = SkEndian_SwapBE16(glyphData->yMin);
931b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax);
932b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax);
933b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
934371add80f51205d53391840164f37ade6aff8012commit-bot@chromium.org
935b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return true;
936b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
937b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
938b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgunsigned SkScalerContext_Mac::generateGlyphCount(void) {
939b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return fGlyphCount;
940b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
941b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
942b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orguint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) {
943fb1663a0a57656328277d02bef088d3afb695a7cbungeman@google.com    CGGlyph cgGlyph[2];
94472b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    UniChar theChar[2]; // UniChar is a UTF-16 16-bit code unit.
945b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
946b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Get the glyph
947fb1663a0a57656328277d02bef088d3afb695a7cbungeman@google.com    size_t numUniChar = SkUTF16_FromUnichar(uni, theChar);
948fb1663a0a57656328277d02bef088d3afb695a7cbungeman@google.com    SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t));
949b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
95072b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
95172b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
95272b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // It is documented that if a mapping is unavailable, the glyph will be set to 0.
95372b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    CTFontGetGlyphsForCharacters(fCTFont, theChar, cgGlyph, numUniChar);
954fb1663a0a57656328277d02bef088d3afb695a7cbungeman@google.com    return cgGlyph[0];
955b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
956b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
957b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgvoid SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
958b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    this->generateMetrics(glyph);
959b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
960b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
961cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.comvoid SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
962cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount);
963cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    glyph->zeroMetrics();
964539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
965cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // The following block produces cgAdvance in CG units (pixels, y up).
966cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    CGSize cgAdvance;
967cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    if (fVertical) {
968cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation,
969cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com                                   &cgGlyph, &cgAdvance, 1);
970cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    } else {
971cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation,
972cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com                                   &cgGlyph, &cgAdvance, 1);
973cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    }
974cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    glyph->fAdvanceX =  SkFloatToFixed_Check(cgAdvance.width);
975cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    glyph->fAdvanceY = -SkFloatToFixed_Check(cgAdvance.height);
976cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com
977cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // The following produces skBounds in SkGlyph units (pixels, y down),
978cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // or returns early if skBounds would be empty.
979cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    SkRect skBounds;
980539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
981cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // On Mountain Lion, CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation and
982cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // CTFontGetVerticalTranslationsForGlyphs do not agree when using OTF CFF fonts.
983cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // For TTF fonts these two do agree and we can use CTFontGetBoundingRectsForGlyphs to get
984cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // the bounding box and CTFontGetVerticalTranslationsForGlyphs to then draw the glyph
985cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // inside that bounding box. However, with OTF CFF fonts this does not work. It appears that
986cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation on OTF CFF fonts tries
987cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // to center the glyph along the vertical baseline and also perform some mysterious shift
988cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // along the baseline. CTFontGetVerticalTranslationsForGlyphs does not appear to perform
989cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // these steps.
990cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    //
991cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // It is not known which is correct (or if either is correct). However, we must always draw
992cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // from the horizontal origin and must use CTFontGetVerticalTranslationsForGlyphs to draw.
993cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // As a result, we do not call CTFontGetBoundingRectsForGlyphs for vertical glyphs.
994539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
995cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // On Snow Leopard, CTFontGetBoundingRectsForGlyphs ignores kCTFontVerticalOrientation and
996cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // returns horizontal bounds.
997539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
998cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
999cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // return a bad value in cgBounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
1000cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
1001cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // font directly.
1002cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    if ((isLion() || isMountainLion()) &&
1003cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && generateBBoxes()))
1004cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    {
1005cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphOffset];
1006cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        if (gRect.fMinX >= gRect.fMaxX || gRect.fMinY >= gRect.fMaxY) {
1007cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com            return;
1008cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        }
1009cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        skBounds = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY);
1010cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
1011cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        fFUnitMatrix.mapRect(&skBounds);
1012cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com
1013cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    } else {
1014cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up).
1015cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        CGRect cgBounds;
1016cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation,
1017cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com                                        &cgGlyph, &cgBounds, 1);
1018539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
1019cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // BUG?
1020cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when
1021cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // it should be empty. So, if we see a zero-advance, we check if it has an
1022cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance
1023cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // is rare, so we won't incur a big performance cost for this extra check.
1024cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        if (0 == cgAdvance.width && 0 == cgAdvance.height) {
1025cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com            AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL));
1026cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com            if (NULL == path || CGPathIsEmpty(path)) {
1027cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com                return;
1028cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com            }
1029cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        }
1030cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com
1031cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        if (CGRectIsEmpty_inline(cgBounds)) {
1032cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com            return;
1033cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        }
1034cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com
1035cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // Convert cgBounds to SkGlyph units (pixels, y down).
1036cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height,
1037cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com                                    cgBounds.size.width, cgBounds.size.height);
1038cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    }
1039cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com
1040cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    if (fVertical) {
1041cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // Due to all of the vertical bounds bugs, skBounds is always the horizontal bounds.
1042cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        // Convert these horizontal bounds into vertical bounds.
1043cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        SkPoint offset;
1044cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        getVerticalOffset(cgGlyph, &offset);
1045cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        skBounds.offset(offset);
1046cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    }
1047539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
1048cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // Currently the bounds are based on being rendered at (0,0).
1049cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // The top left must not move, since that is the base from which subpixel positioning is offset.
1050cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    if (fDoSubPosition) {
1051cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed());
1052cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed());
1053cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    }
1054539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
1055cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    SkIRect skIBounds;
1056cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    skBounds.roundOut(&skIBounds);
1057cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
1058cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
1059cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // is not currently known, as CG dilates the outlines by some percentage.
1060cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    // Note that if this context is A8 and not back-forming from LCD, there is no need to outset.
1061cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    skIBounds.outset(1, 1);
1062cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    glyph->fLeft = SkToS16(skIBounds.fLeft);
1063cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    glyph->fTop = SkToS16(skIBounds.fTop);
1064cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    glyph->fWidth = SkToU16(skIBounds.width());
1065cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    glyph->fHeight = SkToU16(skIBounds.height());
1066539f364e80a1e8ee35845b93fd6547e855380cadskia.committer@gmail.com
1067cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com#ifdef HACK_COLORGLYPHS
1068cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    glyph->fMaskFormat = SkMask::kARGB32_Format;
1069cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com#endif
1070cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com}
1071b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1072b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#include "SkColorPriv.h"
1073b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1074b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic void build_power_table(uint8_t table[], float ee) {
1075b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    for (int i = 0; i < 256; i++) {
1076b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        float x = i / 255.f;
1077b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        x = sk_float_pow(x, ee);
10784b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org        int xx = SkScalarRoundToInt(x * 255);
1079b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        table[i] = SkToU8(xx);
1080b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1081b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1082b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1083b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org/**
1084b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org *  This will invert the gamma applied by CoreGraphics, so we can get linear
1085b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org *  values.
1086b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org *
1087b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org *  CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value.
1088b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org *  The color space used does not appear to affect this choice.
1089b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org */
1090b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic const uint8_t* getInverseGammaTableCoreGraphicSmoothing() {
1091b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    static bool gInited;
1092b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    static uint8_t gTableCoreGraphicsSmoothing[256];
1093b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!gInited) {
1094b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        build_power_table(gTableCoreGraphicsSmoothing, 2.0f);
1095b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        gInited = true;
1096b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1097b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return gTableCoreGraphicsSmoothing;
1098b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1099b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1100b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
1101b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    while (count > 0) {
1102b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        uint8_t mask = 0;
1103b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        for (int i = 7; i >= 0; --i) {
1104b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            mask |= (CGRGBPixel_getAlpha(*src++) >> 7) << i;
1105b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            if (0 == --count) {
1106b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                break;
1107b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            }
1108b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1109b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        *dst++ = mask;
1110b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1111b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1112b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1113b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1114b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) {
1115b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    U8CPU r = (rgb >> 16) & 0xFF;
1116b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    U8CPU g = (rgb >>  8) & 0xFF;
1117b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    U8CPU b = (rgb >>  0) & 0xFF;
1118b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1119b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1120b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1121b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes,
1122b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                      const SkGlyph& glyph, const uint8_t* table8) {
1123b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const int width = glyph.fWidth;
1124b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    size_t dstRB = glyph.rowBytes();
1125b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
1126b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1127b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    for (int y = 0; y < glyph.fHeight; y++) {
1128b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        for (int i = 0; i < width; ++i) {
1129b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8);
1130b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1131b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1132b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        dst += dstRB;
1133b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1134b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1135b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1136b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1137b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic inline uint16_t rgb_to_lcd16(CGRGBPixel rgb, const uint8_t* tableR,
1138b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                                    const uint8_t* tableG,
1139b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                                    const uint8_t* tableB) {
1140b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1141b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
1142b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
1143b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return SkPack888ToRGB16(r, g, b);
1144b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1145b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1146b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
1147b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1148b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const int width = glyph.fWidth;
1149b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    size_t dstRB = glyph.rowBytes();
1150b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage;
1151b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1152b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    for (int y = 0; y < glyph.fHeight; y++) {
1153b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        for (int i = 0; i < width; i++) {
1154b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
1155b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1156b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1157b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        dst = (uint16_t*)((char*)dst + dstRB);
1158b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1159b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1160b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1161b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1162b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic inline uint32_t rgb_to_lcd32(CGRGBPixel rgb, const uint8_t* tableR,
1163b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                                    const uint8_t* tableG,
1164b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                                    const uint8_t* tableB) {
1165b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1166b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
1167b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
1168b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return SkPackARGB32(0xFF, r, g, b);
1169b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1170b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1171b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic void rgb_to_lcd32(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
1172b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1173b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const int width = glyph.fWidth;
1174b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    size_t dstRB = glyph.rowBytes();
1175b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint32_t* SK_RESTRICT dst = (uint32_t*)glyph.fImage;
1176b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    for (int y = 0; y < glyph.fHeight; y++) {
1177b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        for (int i = 0; i < width; i++) {
1178b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
1179b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1180b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1181b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        dst = (uint32_t*)((char*)dst + dstRB);
1182b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1183b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1184b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1185f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com#ifdef HACK_COLORGLYPHS
1186f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com// hack to colorize the output for testing kARGB32_Format
1187f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.comstatic SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb, const SkGlyph& glyph,
1188f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com                                     int x, int y) {
1189f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com    U8CPU r = (rgb >> 16) & 0xFF;
1190f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com    U8CPU g = (rgb >>  8) & 0xFF;
1191f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com    U8CPU b = (rgb >>  0) & 0xFF;
1192f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com    unsigned a = SkComputeLuminance(r, g, b);
11932fd42c471c77f54ace35c13975651e17d5b2e8c6skia.committer@gmail.com
1194f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com    // compute gradient from x,y
1195f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com    r = x * 255 / glyph.fWidth;
1196f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com    g = 0;
1197f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com    b = (glyph.fHeight - y) * 255 / glyph.fHeight;
1198f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com    return SkPreMultiplyARGB(a, r, g, b);    // red
1199f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com}
1200f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com#endif
1201f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com
1202b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgtemplate <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
1203b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return (T*)((char*)ptr + byteOffset);
1204b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1205b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1206b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgvoid SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
1207b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
1208b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1209b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // FIXME: lcd smoothed un-hinted rasterization unsupported.
1210b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting;
1211b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1212b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Draw the glyph
1213b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    size_t cgRowBytes;
1214b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, generateA8FromLCD);
1215b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (cgPixels == NULL) {
1216b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return;
1217b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1218b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1219b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    //TODO: see if drawing black on white and inverting is faster (at least in
1220b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    //lcd case) as core graphics appears to have special case code for drawing
1221b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    //black text.
1222b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1223b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Fix the glyph
1224b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const bool isLCD = isLCDFormat(glyph.fMaskFormat);
1225b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (isLCD || (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD)) {
1226b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        const uint8_t* table = getInverseGammaTableCoreGraphicSmoothing();
1227b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1228b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        //Note that the following cannot really be integrated into the
1229b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        //pre-blend, since we may not be applying the pre-blend; when we aren't
1230b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        //applying the pre-blend it means that a filter wants linear anyway.
1231b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        //Other code may also be applying the pre-blend, so we'd need another
1232b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        //one with this and one without.
1233b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGRGBPixel* addr = cgPixels;
1234b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        for (int y = 0; y < glyph.fHeight; ++y) {
1235b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            for (int x = 0; x < glyph.fWidth; ++x) {
1236b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                int r = (addr[x] >> 16) & 0xFF;
1237b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                int g = (addr[x] >>  8) & 0xFF;
1238b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                int b = (addr[x] >>  0) & 0xFF;
1239b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1240b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            }
1241b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            addr = SkTAddByteOffset(addr, cgRowBytes);
1242b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1243b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1244b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1245b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Convert glyph to mask
1246b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    switch (glyph.fMaskFormat) {
1247b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case SkMask::kLCD32_Format: {
1248b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            if (fPreBlend.isApplicable()) {
1249b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                rgb_to_lcd32<true>(cgPixels, cgRowBytes, glyph,
1250b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                   fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1251b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            } else {
1252b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                rgb_to_lcd32<false>(cgPixels, cgRowBytes, glyph,
1253b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                    fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1254b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            }
1255b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        } break;
1256b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case SkMask::kLCD16_Format: {
1257b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            if (fPreBlend.isApplicable()) {
1258b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph,
1259b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                   fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1260b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            } else {
1261b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph,
1262b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                    fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1263b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            }
1264b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        } break;
1265b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case SkMask::kA8_Format: {
1266b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            if (fPreBlend.isApplicable()) {
1267b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1268b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            } else {
1269b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1270b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            }
1271b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        } break;
1272b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case SkMask::kBW_Format: {
1273b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            const int width = glyph.fWidth;
1274b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            size_t dstRB = glyph.rowBytes();
1275b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            uint8_t* dst = (uint8_t*)glyph.fImage;
1276b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            for (int y = 0; y < glyph.fHeight; y++) {
1277b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                cgpixels_to_bits(dst, cgPixels, width);
1278b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1279b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                dst += dstRB;
1280b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            }
1281b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        } break;
1282f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com#ifdef HACK_COLORGLYPHS
1283f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com        case SkMask::kARGB32_Format: {
1284f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com            const int width = glyph.fWidth;
1285f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com            size_t dstRB = glyph.rowBytes();
1286f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com            SkPMColor* dst = (SkPMColor*)glyph.fImage;
1287f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com            for (int y = 0; y < glyph.fHeight; y++) {
1288f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com                for (int x = 0; x < width; ++x) {
1289f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com                    dst[x] = cgpixels_to_pmcolor(cgPixels[x], glyph, x, y);
1290f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com                }
1291f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com                cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1292f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com                dst = (SkPMColor*)((char*)dst + dstRB);
1293f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com            }
1294f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com        } break;
1295f77b35d86ad439917bda78334deb31fbcc16cdaereed@google.com#endif
1296b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        default:
1297b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            SkDEBUGFAIL("unexpected mask format");
1298b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            break;
1299b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1300b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1301b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1302b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org/*
1303b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org *  Our subpixel resolution is only 2 bits in each direction, so a scale of 4
1304b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org *  seems sufficient, and possibly even correct, to allow the hinted outline
1305b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org *  to be subpixel positioned.
1306b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org */
1307b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#define kScaleForSubPixelPositionHinting (4.0f)
1308b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1309b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgvoid SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) {
1310b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CTFontRef font = fCTFont;
1311b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkScalar scaleX = SK_Scalar1;
1312b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkScalar scaleY = SK_Scalar1;
1313b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1314b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    /*
1315b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org     *  For subpixel positioning, we want to return an unhinted outline, so it
1316b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org     *  can be positioned nicely at fractional offsets. However, we special-case
1317b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org     *  if the baseline of the (horizontal) text is axis-aligned. In those cases
1318b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org     *  we want to retain hinting in the direction orthogonal to the baseline.
1319b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org     *  e.g. for horizontal baseline, we want to retain hinting in Y.
1320b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org     *  The way we remove hinting is to scale the font by some value (4) in that
1321b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org     *  direction, ask for the path, and then scale the path back down.
1322b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org     */
1323b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
1324b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkMatrix m;
1325b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        fRec.getSingleMatrix(&m);
1326b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1327b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // start out by assuming that we want no hining in X and Y
13284b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org        scaleX = scaleY = kScaleForSubPixelPositionHinting;
1329b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // now see if we need to restore hinting for axis-aligned baselines
1330b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        switch (SkComputeAxisAlignmentForHText(m)) {
1331b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            case kX_SkAxisAlignment:
1332b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                scaleY = SK_Scalar1; // want hinting in the Y direction
1333b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                break;
1334b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            case kY_SkAxisAlignment:
1335b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                scaleX = SK_Scalar1; // want hinting in the X direction
1336b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                break;
1337b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            default:
1338b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                break;
1339b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1340b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1341b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGAffineTransform xform = MatrixToCGAffineTransform(m, scaleX, scaleY);
1342b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // need to release font when we're done
1343b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        font = CTFontCreateCopyWithAttributes(fCTFont, 1, &xform, NULL);
1344b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1345b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1346b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount);
1347b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL));
1348b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1349b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    path->reset();
1350b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (cgPath != NULL) {
1351b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement);
1352b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1353b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1354cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    if (fDoSubPosition) {
1355b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkMatrix m;
1356b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY));
1357b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        path->transform(m);
1358b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // balance the call to CTFontCreateCopyWithAttributes
1359b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CFSafeRelease(font);
1360b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1361cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com    if (fVertical) {
1362cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        SkPoint offset;
1363cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        getVerticalOffset(cgGlyph, &offset);
1364cefd981a4c4e90be33d1433592f11f84a102d2e0bungeman@google.com        path->offset(offset.fX, offset.fY);
1365b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1366b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1367b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1368b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgvoid SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
1369b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                              SkPaint::FontMetrics* my) {
1370b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGRect theBounds = CTFontGetBoundingBox(fCTFont);
1371b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1372b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkPaint::FontMetrics theMetrics;
1373b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    theMetrics.fTop          = CGToScalar(-CGRectGetMaxY_inline(theBounds));
1374b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    theMetrics.fAscent       = CGToScalar(-CTFontGetAscent(fCTFont));
1375b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    theMetrics.fDescent      = CGToScalar( CTFontGetDescent(fCTFont));
1376b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    theMetrics.fBottom       = CGToScalar(-CGRectGetMinY_inline(theBounds));
1377b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    theMetrics.fLeading      = CGToScalar( CTFontGetLeading(fCTFont));
1378b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    theMetrics.fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds));
1379b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    theMetrics.fXMin         = CGToScalar( CGRectGetMinX_inline(theBounds));
1380b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    theMetrics.fXMax         = CGToScalar( CGRectGetMaxX_inline(theBounds));
1381b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    theMetrics.fXHeight      = CGToScalar( CTFontGetXHeight(fCTFont));
13820bc406df48ac6f358ab8dcff08f71fe9c32b79decommit-bot@chromium.org    theMetrics.fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont));
13830bc406df48ac6f358ab8dcff08f71fe9c32b79decommit-bot@chromium.org    theMetrics.fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont));
13840bc406df48ac6f358ab8dcff08f71fe9c32b79decommit-bot@chromium.org
13850bc406df48ac6f358ab8dcff08f71fe9c32b79decommit-bot@chromium.org    theMetrics.fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
13860bc406df48ac6f358ab8dcff08f71fe9c32b79decommit-bot@chromium.org    theMetrics.fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
1387b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1388b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (mx != NULL) {
1389b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        *mx = theMetrics;
1390b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1391b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (my != NULL) {
1392b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        *my = theMetrics;
1393b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1394b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1395b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1396b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgvoid SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) {
1397b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkPath* skPath = (SkPath*)info;
1398b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1399b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Process the path element
1400b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    switch (element->type) {
1401b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case kCGPathElementMoveToPoint:
1402b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            skPath->moveTo(element->points[0].x, -element->points[0].y);
1403b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            break;
1404b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1405b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case kCGPathElementAddLineToPoint:
1406b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            skPath->lineTo(element->points[0].x, -element->points[0].y);
1407b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            break;
1408b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1409b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case kCGPathElementAddQuadCurveToPoint:
1410b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            skPath->quadTo(element->points[0].x, -element->points[0].y,
1411b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                           element->points[1].x, -element->points[1].y);
1412b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            break;
1413b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1414b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case kCGPathElementAddCurveToPoint:
1415b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            skPath->cubicTo(element->points[0].x, -element->points[0].y,
1416b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                            element->points[1].x, -element->points[1].y,
1417b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                            element->points[2].x, -element->points[2].y);
1418b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            break;
1419b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1420b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case kCGPathElementCloseSubpath:
1421b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            skPath->close();
1422b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            break;
1423b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1424b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        default:
1425b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            SkDEBUGFAIL("Unknown path element!");
1426b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            break;
1427b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1428b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1429b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1430b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1431b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
1432b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1433b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// Returns NULL on failure
1434b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// Call must still manage its ownership of provider
1435b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic SkTypeface* create_from_dataProvider(CGDataProviderRef provider) {
1436b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider));
1437b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (NULL == cg) {
1438b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return NULL;
1439b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1440b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CTFontRef ct = CTFontCreateWithGraphicsFont(cg, 0, NULL, NULL);
1441b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return cg ? SkCreateTypefaceFromCTFont(ct) : NULL;
1442b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1443b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1444b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// Web fonts added to the the CTFont registry do not return their character set.
1445b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// Iterate through the font in this case. The existing caller caches the result,
1446b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// so the performance impact isn't too bad.
1447b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
1448b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                           SkTDArray<SkUnichar>* glyphToUnicode) {
14497fa2a65c0cfc714364490cb715171461143024e0reed@google.com    glyphToUnicode->setCount(SkToInt(glyphCount));
1450b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkUnichar* out = glyphToUnicode->begin();
1451b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    sk_bzero(out, glyphCount * sizeof(SkUnichar));
1452b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    UniChar unichar = 0;
1453b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    while (glyphCount > 0) {
1454b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CGGlyph glyph;
1455b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1456b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            out[glyph] = unichar;
1457b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            --glyphCount;
1458b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1459b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        if (++unichar == 0) {
1460b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            break;
1461b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1462b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1463b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1464b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1465b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// Construct Glyph to Unicode table.
1466b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// Unicode code points that require conjugate pairs in utf16 are not
1467b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// supported.
1468b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
1469b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                      SkTDArray<SkUnichar>* glyphToUnicode) {
1470b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
1471b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!charSet) {
1472b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
1473b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return;
1474b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1475b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1476b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CFDataRef> bitmap(CFCharacterSetCreateBitmapRepresentation(kCFAllocatorDefault,
1477b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                                                             charSet));
1478b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!bitmap) {
1479b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return;
1480b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1481b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CFIndex length = CFDataGetLength(bitmap);
1482b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!length) {
1483b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return;
1484b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1485b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (length > 8192) {
1486b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // TODO: Add support for Unicode above 0xFFFF
1487b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // Consider only the BMP portion of the Unicode character points.
1488b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // The bitmap may contain other planes, up to plane 16.
1489b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html
1490b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        length = 8192;
1491b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1492b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const UInt8* bits = CFDataGetBytePtr(bitmap);
14937fa2a65c0cfc714364490cb715171461143024e0reed@google.com    glyphToUnicode->setCount(SkToInt(glyphCount));
1494b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkUnichar* out = glyphToUnicode->begin();
1495b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    sk_bzero(out, glyphCount * sizeof(SkUnichar));
1496b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    for (int i = 0; i < length; i++) {
1497b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        int mask = bits[i];
1498b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        if (!mask) {
1499b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            continue;
1500b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1501b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        for (int j = 0; j < 8; j++) {
1502b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            CGGlyph glyph;
1503b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            UniChar unichar = static_cast<UniChar>((i << 3) + j);
1504b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1505b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                out[glyph] = unichar;
1506b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            }
1507b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1508b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1509b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1510b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1511b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic bool getWidthAdvance(CTFontRef ctFont, int gId, int16_t* data) {
1512b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGSize advance;
1513b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    advance.width = 0;
1514b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGGlyph glyph = gId;
1515b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &glyph, &advance, 1);
1516b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    *data = sk_float_round2int(advance.width);
1517b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return true;
1518b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1519b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1520b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// we might move this into our CGUtils...
1521b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic void CFStringToSkString(CFStringRef src, SkString* dst) {
1522b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Reserve enough room for the worst-case string,
1523b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // plus 1 byte for the trailing null.
1524b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src),
1525b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                                       kCFStringEncodingUTF8) + 1;
1526b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    dst->resize(length);
1527b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8);
1528b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Resize to the actual UTF-8 length used, stripping the null character.
1529b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    dst->resize(strlen(dst->c_str()));
1530b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1531b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
15322689f615e364dc48ad73826564f5b13d2329179dreed@google.comSkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics(
1533b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1534b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        const uint32_t* glyphIDs,
15352689f615e364dc48ad73826564f5b13d2329179dreed@google.com        uint32_t glyphIDsCount) const {
15362689f615e364dc48ad73826564f5b13d2329179dreed@google.com
15372689f615e364dc48ad73826564f5b13d2329179dreed@google.com    CTFontRef originalCTFont = fFontRef.get();
1538b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CTFontRef> ctFont(CTFontCreateCopyWithAttributes(
1539b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            originalCTFont, CTFontGetUnitsPerEm(originalCTFont), NULL, NULL));
1540b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
1541b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1542b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    {
1543b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        AutoCFRelease<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont));
1544b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CFStringToSkString(fontName, &info->fFontName);
1545b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1546b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1547b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CFIndex glyphCount = CTFontGetGlyphCount(ctFont);
1548b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    info->fLastGlyphID = SkToU16(glyphCount - 1);
1549b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    info->fEmSize = CTFontGetUnitsPerEm(ctFont);
15500f9bad01b0e7ad592ffb342dcf1d238b15329be1vandebo    info->fFlags = SkAdvancedTypefaceMetrics::kEmpty_FontFlag;
15510f9bad01b0e7ad592ffb342dcf1d238b15329be1vandebo    info->fStyle = 0;
1552b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1553b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1554b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode);
1555b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1556b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1557b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // If it's not a truetype font, mark it as 'other'. Assume that TrueType
1558b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // fonts always have both glyf and loca tables. At the least, this is what
1559b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // sfntly needs to subset the font. CTFontCopyAttribute() does not always
1560b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // succeed in determining this directly.
15612689f615e364dc48ad73826564f5b13d2329179dreed@google.com    if (!this->getTableSize('glyf') || !this->getTableSize('loca')) {
1562b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1563b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        info->fItalicAngle = 0;
1564b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        info->fAscent = 0;
1565b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        info->fDescent = 0;
1566b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        info->fStemV = 0;
1567b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        info->fCapHeight = 0;
1568b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        info->fBBox = SkIRect::MakeEmpty();
1569b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return info;
1570b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1571b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1572b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1573b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont);
1574b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (symbolicTraits & kCTFontMonoSpaceTrait) {
1575b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1576b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1577b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (symbolicTraits & kCTFontItalicTrait) {
1578b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1579b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1580b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
1581b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
1582b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1583b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    } else if (stylisticClass & kCTFontScriptsClass) {
1584b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1585b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1586b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont);
1587b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    info->fAscent = (int16_t) CTFontGetAscent(ctFont);
1588b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    info->fDescent = (int16_t) CTFontGetDescent(ctFont);
1589b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont);
1590b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGRect bbox = CTFontGetBoundingBox(ctFont);
1591b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1592b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkRect r;
1593b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    r.set( CGToScalar(CGRectGetMinX_inline(bbox)),   // Left
1594b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org           CGToScalar(CGRectGetMaxY_inline(bbox)),   // Top
1595b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org           CGToScalar(CGRectGetMaxX_inline(bbox)),   // Right
1596b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org           CGToScalar(CGRectGetMinY_inline(bbox)));  // Bottom
1597b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1598b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    r.roundOut(&(info->fBBox));
1599b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1600b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Figure out a good guess for StemV - Min width of i, I, !, 1.
1601b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // This probably isn't very good with an italic font.
1602b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    int16_t min_width = SHRT_MAX;
1603b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    info->fStemV = 0;
1604b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
1605b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
1606b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGGlyph glyphs[count];
1607b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CGRect boundingRects[count];
1608b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) {
1609b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation,
1610b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                        glyphs, boundingRects, count);
1611b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        for (size_t i = 0; i < count; i++) {
1612b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            int16_t width = (int16_t) boundingRects[i].size.width;
1613b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            if (width > 0 && width < min_width) {
1614b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                min_width = width;
1615b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                info->fStemV = min_width;
1616b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            }
1617b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1618b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1619b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
16200f9bad01b0e7ad592ffb342dcf1d238b15329be1vandebo    if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1621b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1622b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            skia_advanced_typeface_metrics_utils::appendRange(&info->fGlyphWidths, 0);
1623b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            info->fGlyphWidths->fAdvance.append(1, &min_width);
1624b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            skia_advanced_typeface_metrics_utils::finishRange(info->fGlyphWidths.get(), 0,
1625b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                        SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1626b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        } else {
1627b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            info->fGlyphWidths.reset(
1628b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                skia_advanced_typeface_metrics_utils::getAdvanceData(ctFont.get(),
16297fa2a65c0cfc714364490cb715171461143024e0reed@google.com                               SkToInt(glyphCount),
1630b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                               glyphIDs,
1631b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                               glyphIDsCount,
1632b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                               &getWidthAdvance));
1633b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1634b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1635b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return info;
1636b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1637b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1638b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
1639b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1640cc9aad5787b52216f46b9d6d95a781240e3e6b6breed@google.comstatic SK_SFNT_ULONG get_font_type_tag(const SkTypeface_Mac* typeface) {
1641cc9aad5787b52216f46b9d6d95a781240e3e6b6breed@google.com    CTFontRef ctFont = typeface->fFontRef.get();
1642b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CFNumberRef> fontFormatRef(
1643b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
1644b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!fontFormatRef) {
1645b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return 0;
1646b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1647b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1648b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SInt32 fontFormatValue;
1649b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (!CFNumberGetValue(fontFormatRef, kCFNumberSInt32Type, &fontFormatValue)) {
1650b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return 0;
1651b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1652b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1653b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    switch (fontFormatValue) {
1654b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case kCTFontFormatOpenTypePostScript:
1655b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            return SkSFNTHeader::fontType_OpenTypeCFF::TAG;
1656b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case kCTFontFormatOpenTypeTrueType:
1657b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1658b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case kCTFontFormatTrueType:
1659b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            return SkSFNTHeader::fontType_MacTrueType::TAG;
1660b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case kCTFontFormatPostScript:
1661b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            return SkSFNTHeader::fontType_PostScript::TAG;
1662b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case kCTFontFormatBitmap:
1663b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            return SkSFNTHeader::fontType_MacTrueType::TAG;
1664b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        case kCTFontFormatUnrecognized:
1665b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        default:
1666b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            //CT seems to be unreliable in being able to obtain the type,
1667b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            //even if all we want is the first four bytes of the font resource.
1668b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            //Just the presence of the FontForge 'FFTM' table seems to throw it off.
1669b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1670b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1671b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1672b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1673cc9aad5787b52216f46b9d6d95a781240e3e6b6breed@google.comSkStream* SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
1674cc9aad5787b52216f46b9d6d95a781240e3e6b6breed@google.com    SK_SFNT_ULONG fontType = get_font_type_tag(this);
1675b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (0 == fontType) {
1676b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return NULL;
1677b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1678b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1679b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // get table tags
1680cc9aad5787b52216f46b9d6d95a781240e3e6b6breed@google.com    int numTables = this->countTables();
1681b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkTDArray<SkFontTableTag> tableTags;
1682b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    tableTags.setCount(numTables);
1683cc9aad5787b52216f46b9d6d95a781240e3e6b6breed@google.com    this->getTableTags(tableTags.begin());
1684b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1685b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // calc total size for font, save sizes
1686b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkTDArray<size_t> tableSizes;
1687b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1688b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1689cc9aad5787b52216f46b9d6d95a781240e3e6b6breed@google.com        size_t tableSize = this->getTableSize(tableTags[tableIndex]);
1690b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        totalSize += (tableSize + 3) & ~3;
1691b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        *tableSizes.append() = tableSize;
1692b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1693b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1694b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // reserve memory for stream, and zero it (tables must be zero padded)
1695b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkMemoryStream* stream = new SkMemoryStream(totalSize);
1696b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    char* dataStart = (char*)stream->getMemoryBase();
1697b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    sk_bzero(dataStart, totalSize);
1698b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    char* dataPtr = dataStart;
1699b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1700b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // compute font header entries
1701b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint16_t entrySelector = 0;
1702b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint16_t searchRange = 1;
1703b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    while (searchRange < numTables >> 1) {
1704b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        entrySelector++;
1705b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        searchRange <<= 1;
1706b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1707b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    searchRange <<= 4;
1708b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    uint16_t rangeShift = (numTables << 4) - searchRange;
1709b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1710b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // write font header
1711b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkSFNTHeader* header = (SkSFNTHeader*)dataPtr;
1712b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    header->fontType = fontType;
1713b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    header->numTables = SkEndian_SwapBE16(numTables);
1714b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    header->searchRange = SkEndian_SwapBE16(searchRange);
1715b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    header->entrySelector = SkEndian_SwapBE16(entrySelector);
1716b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    header->rangeShift = SkEndian_SwapBE16(rangeShift);
1717b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    dataPtr += sizeof(SkSFNTHeader);
1718b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1719b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // write tables
1720b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr;
1721b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1722b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1723b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        size_t tableSize = tableSizes[tableIndex];
1724cc9aad5787b52216f46b9d6d95a781240e3e6b6breed@google.com        this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
1725b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]);
1726b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr,
1727b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                                                         tableSize));
17287fa2a65c0cfc714364490cb715171461143024e0reed@google.com        entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart));
17297fa2a65c0cfc714364490cb715171461143024e0reed@google.com        entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize));
1730b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1731b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        dataPtr += (tableSize + 3) & ~3;
1732b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        ++entry;
1733b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1734b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1735b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return stream;
1736b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1737b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1738b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
1739b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
1740b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1741b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgint SkTypeface_Mac::onGetUPEM() const {
1742b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef, NULL));
1743b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return CGFontGetUnitsPerEm(cgFont);
1744b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1745b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1746839702b61934914118ec557dd641be322eba3b5fbungeman@google.comSkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const {
1747a980269c2498836101146adc729ef780fb89824ebungeman@google.com    SkTypeface::LocalizedStrings* nameIter =
1748a980269c2498836101146adc729ef780fb89824ebungeman@google.com        SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
1749a980269c2498836101146adc729ef780fb89824ebungeman@google.com    if (NULL == nameIter) {
1750a980269c2498836101146adc729ef780fb89824ebungeman@google.com        AutoCFRelease<CFStringRef> cfLanguage;
1751a980269c2498836101146adc729ef780fb89824ebungeman@google.com        AutoCFRelease<CFStringRef> cfFamilyName(
1752a980269c2498836101146adc729ef780fb89824ebungeman@google.com            CTFontCopyLocalizedName(fFontRef, kCTFontFamilyNameKey, &cfLanguage));
1753a980269c2498836101146adc729ef780fb89824ebungeman@google.com
1754a980269c2498836101146adc729ef780fb89824ebungeman@google.com        SkString skLanguage;
1755a980269c2498836101146adc729ef780fb89824ebungeman@google.com        SkString skFamilyName;
1756a980269c2498836101146adc729ef780fb89824ebungeman@google.com        if (cfLanguage.get()) {
1757a980269c2498836101146adc729ef780fb89824ebungeman@google.com            CFStringToSkString(cfLanguage.get(), &skLanguage);
1758a980269c2498836101146adc729ef780fb89824ebungeman@google.com        } else {
1759a980269c2498836101146adc729ef780fb89824ebungeman@google.com            skLanguage = "und"; //undetermined
1760a980269c2498836101146adc729ef780fb89824ebungeman@google.com        }
1761a980269c2498836101146adc729ef780fb89824ebungeman@google.com        if (cfFamilyName.get()) {
1762a980269c2498836101146adc729ef780fb89824ebungeman@google.com            CFStringToSkString(cfFamilyName.get(), &skFamilyName);
1763a980269c2498836101146adc729ef780fb89824ebungeman@google.com        }
1764a980269c2498836101146adc729ef780fb89824ebungeman@google.com
1765a980269c2498836101146adc729ef780fb89824ebungeman@google.com        nameIter = new SkOTUtils::LocalizedStrings_SingleName(skFamilyName, skLanguage);
1766a980269c2498836101146adc729ef780fb89824ebungeman@google.com    }
1767a980269c2498836101146adc729ef780fb89824ebungeman@google.com    return nameIter;
1768a980269c2498836101146adc729ef780fb89824ebungeman@google.com}
1769a980269c2498836101146adc729ef780fb89824ebungeman@google.com
1770b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// If, as is the case with web fonts, the CTFont data isn't available,
1771b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// the CGFont data may work. While the CGFont may always provide the
1772b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// right result, leave the CTFont code path to minimize disruption.
1773b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic CFDataRef copyTableFromFont(CTFontRef ctFont, SkFontTableTag tag) {
1774b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CFDataRef data = CTFontCopyTable(ctFont, (CTFontTableTag) tag,
1775b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                     kCTFontTableOptionNoOptions);
1776b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (NULL == data) {
1777b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, NULL));
1778b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        data = CGFontCopyTableForTag(cgFont, tag);
1779b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1780b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return data;
1781b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1782b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1783b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgint SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
1784b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CFArrayRef> cfArray(CTFontCopyAvailableTables(fFontRef,
1785b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                                kCTFontTableOptionNoOptions));
1786b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (NULL == cfArray) {
1787b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return 0;
1788b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
17897fa2a65c0cfc714364490cb715171461143024e0reed@google.com    int count = SkToInt(CFArrayGetCount(cfArray));
1790b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (tags) {
1791b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        for (int i = 0; i < count; ++i) {
1792b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            uintptr_t fontTag = reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(cfArray, i));
1793b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            tags[i] = static_cast<SkFontTableTag>(fontTag);
1794b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1795b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1796b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return count;
1797b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1798b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1799b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgsize_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset,
1800b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org                                      size_t length, void* dstData) const {
1801b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    AutoCFRelease<CFDataRef> srcData(copyTableFromFont(fFontRef, tag));
1802b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (NULL == srcData) {
1803b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return 0;
1804b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1805b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1806b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    size_t srcSize = CFDataGetLength(srcData);
1807b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (offset >= srcSize) {
1808b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        return 0;
1809b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1810b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (length > srcSize - offset) {
1811b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        length = srcSize - offset;
1812b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1813b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (dstData) {
1814b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        memcpy(dstData, CFDataGetBytePtr(srcData) + offset, length);
1815b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1816b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return length;
1817b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1818b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1819b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgSkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkDescriptor* desc) const {
18200da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com    return new SkScalerContext_Mac(const_cast<SkTypeface_Mac*>(this), desc);
1821b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1822b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1823b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgvoid SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
1824c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org    if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
1825c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org        rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
1826c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org    {
1827c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org        rec->fMaskFormat = SkMask::kA8_Format;
1828c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org        // Render the glyphs as close as possible to what was requested.
1829c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org        // The above turns off subpixel rendering, but the user requested it.
1830c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org        // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks.
1831c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org        // See comments below for more details.
1832c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org        rec->setHinting(SkPaint::kNormal_Hinting);
1833c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org    }
1834e944de7523ddd0ffffdc423c0b99a83fe83c5d5askia.committer@gmail.com
1835c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org    unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag  |
1836f6f56878bc96386882721b15ba610984185d3dc9bungeman@google.com                                  SkScalerContext::kForceAutohinting_Flag  |
1837c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org                                  SkScalerContext::kLCD_BGROrder_Flag |
1838c5fd46171841711973b9433c726ff8608335940ccommit-bot@chromium.org                                  SkScalerContext::kLCD_Vertical_Flag;
18390c23faf222c24529781139495a5f4f4ab61f7cb2skia.committer@gmail.com
1840b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    rec->fFlags &= ~flagsWeDontSupport;
18410c23faf222c24529781139495a5f4f4ab61f7cb2skia.committer@gmail.com
1842b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    bool lcdSupport = supports_LCD();
18430c23faf222c24529781139495a5f4f4ab61f7cb2skia.committer@gmail.com
1844b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Only two levels of hinting are supported.
1845b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // kNo_Hinting means avoid CoreGraphics outline dilation.
1846b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // kNormal_Hinting means CoreGraphics outline dilation is allowed.
1847b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // If there is no lcd support, hinting (dilation) cannot be supported.
1848b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkPaint::Hinting hinting = rec->getHinting();
1849b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (SkPaint::kSlight_Hinting == hinting || !lcdSupport) {
1850b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        hinting = SkPaint::kNo_Hinting;
1851b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    } else if (SkPaint::kFull_Hinting == hinting) {
1852b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        hinting = SkPaint::kNormal_Hinting;
1853b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1854b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    rec->setHinting(hinting);
18550c23faf222c24529781139495a5f4f4ab61f7cb2skia.committer@gmail.com
1856b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // FIXME: lcd smoothed un-hinted rasterization unsupported.
1857b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Tracked by http://code.google.com/p/skia/issues/detail?id=915 .
1858b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // There is no current means to honor a request for unhinted lcd,
1859b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // so arbitrarilly ignore the hinting request and honor lcd.
18600c23faf222c24529781139495a5f4f4ab61f7cb2skia.committer@gmail.com
1861b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Hinting and smoothing should be orthogonal, but currently they are not.
1862b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // CoreGraphics has no API to influence hinting. However, its lcd smoothed
1863b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // output is drawn from auto-dilated outlines (the amount of which is
1864b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // determined by AppleFontSmoothing). Its regular anti-aliased output is
1865b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // drawn from un-dilated outlines.
18660c23faf222c24529781139495a5f4f4ab61f7cb2skia.committer@gmail.com
1867b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // The behavior of Skia is as follows:
1868b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // [AA][no-hint]: generate AA using CoreGraphic's AA output.
1869b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single
1870b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // channel. This matches [LCD][yes-hint] in weight.
1871b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // [LCD][no-hint]: curently unable to honor, and must pick which to respect.
1872b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Currenly side with LCD, effectively ignoring the hinting setting.
1873b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output.
18740c23faf222c24529781139495a5f4f4ab61f7cb2skia.committer@gmail.com
1875b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (isLCDFormat(rec->fMaskFormat)) {
1876b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        if (lcdSupport) {
1877b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            //CoreGraphics creates 555 masks for smoothed text anyway.
1878b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            rec->fMaskFormat = SkMask::kLCD16_Format;
1879b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            rec->setHinting(SkPaint::kNormal_Hinting);
1880b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        } else {
1881b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org            rec->fMaskFormat = SkMask::kA8_Format;
1882b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        }
1883b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
18840c23faf222c24529781139495a5f4f4ab61f7cb2skia.committer@gmail.com
1885b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
1886b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    // All other masks can use regular gamma.
1887b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hinting) {
1888b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org#ifndef SK_GAMMA_APPLY_TO_A8
1889b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        rec->ignorePreBlend();
1890feda2f90a4ad9625e14d8cb02a90b9644d803dd4reed@android.com#endif
1891b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    } else {
1892b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        //CoreGraphics dialates smoothed text as needed.
1893b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org        rec->setContrast(0);
1894b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    }
1895b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1896b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
1897b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org// we take ownership of the ref
1898b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.orgstatic const char* get_str(CFStringRef ref, SkString* str) {
1899b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CFStringToSkString(ref, str);
1900b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    CFSafeRelease(ref);
1901b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    return str->c_str();
1902b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
1903b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org
19045526ede94a2fc58bcf6b578b12a29f6addad776dreed@google.comvoid SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc,
19055526ede94a2fc58bcf6b578b12a29f6addad776dreed@google.com                                         bool* isLocalStream) const {
1906b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    SkString tmpStr;
19070c23faf222c24529781139495a5f4f4ab61f7cb2skia.committer@gmail.com
1908b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef), &tmpStr));
1909b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    desc->setFullName(get_str(CTFontCopyFullName(fFontRef), &tmpStr));
1910b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org    desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef), &tmpStr));
19115526ede94a2fc58bcf6b578b12a29f6addad776dreed@google.com    // TODO: need to add support for local-streams (here and openStream)
19125526ede94a2fc58bcf6b578b12a29f6addad776dreed@google.com    *isLocalStream = false;
1913b103ed4e39613cac823b94df3e5b0e92857d3b4dmike@reedtribe.org}
19145526ede94a2fc58bcf6b578b12a29f6addad776dreed@google.com
1915bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.comint SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding,
191672b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com                                    uint16_t glyphs[], int glyphCount) const
191772b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com{
191872b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
191972b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
192072b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // It is documented that if a mapping is unavailable, the glyph will be set to 0.
19210673efeea2be3b6b6198ddbac7217d7ab30fe59cskia.committer@gmail.com
1922bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    SkAutoSTMalloc<1024, UniChar> charStorage;
192372b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    const UniChar* src; // UniChar is a UTF-16 16-bit code unit.
192472b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    int srcCount;
1925bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    switch (encoding) {
1926bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com        case kUTF8_Encoding: {
192772b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            const char* utf8 = reinterpret_cast<const char*>(chars);
192872b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            UniChar* utf16 = charStorage.reset(2 * glyphCount);
192972b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            src = utf16;
1930bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com            for (int i = 0; i < glyphCount; ++i) {
193172b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com                SkUnichar uni = SkUTF8_NextUnichar(&utf8);
193272b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com                utf16 += SkUTF16_FromUnichar(uni, utf16);
1933bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com            }
19347fa2a65c0cfc714364490cb715171461143024e0reed@google.com            srcCount = SkToInt(utf16 - src);
1935bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com            break;
1936bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com        }
193772b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com        case kUTF16_Encoding: {
193872b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            src = reinterpret_cast<const UniChar*>(chars);
193972b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            int extra = 0;
194072b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            for (int i = 0; i < glyphCount; ++i) {
194172b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com                if (SkUTF16_IsHighSurrogate(src[i + extra])) {
194272b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com                    ++extra;
194372b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com                }
194472b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            }
194572b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            srcCount = glyphCount + extra;
1946bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com            break;
194772b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com        }
1948bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com        case kUTF32_Encoding: {
194972b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(chars);
195072b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            UniChar* utf16 = charStorage.reset(2 * glyphCount);
195172b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            src = utf16;
1952bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com            for (int i = 0; i < glyphCount; ++i) {
195372b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com                utf16 += SkUTF16_FromUnichar(utf32[i], utf16);
1954bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com            }
19557fa2a65c0cfc714364490cb715171461143024e0reed@google.com            srcCount = SkToInt(utf16 - src);
1956bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com            break;
1957bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com        }
1958bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    }
1959bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com
196072b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // If glyphs is NULL, CT still needs glyph storage for finding the first failure.
196172b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // Also, if there are any non-bmp code points, the provided 'glyphs' storage will be inadequate.
1962bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    SkAutoSTMalloc<1024, uint16_t> glyphStorage;
1963bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    uint16_t* macGlyphs = glyphs;
196472b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    if (NULL == macGlyphs || srcCount > glyphCount) {
196572b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com        macGlyphs = glyphStorage.reset(srcCount);
1966bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    }
1967bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com
196872b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    bool allEncoded = CTFontGetGlyphsForCharacters(fFontRef, src, macGlyphs, srcCount);
196972b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com
197072b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // If there were any non-bmp, then copy and compact.
197172b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // If 'glyphs' is NULL, then compact glyphStorage in-place.
197272b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // If all are bmp and 'glyphs' is non-NULL, 'glyphs' already contains the compact glyphs.
197372b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // If some are non-bmp and 'glyphs' is non-NULL, copy and compact into 'glyphs'.
197472b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    uint16_t* compactedGlyphs = glyphs;
197572b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    if (NULL == compactedGlyphs) {
197672b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com        compactedGlyphs = macGlyphs;
197772b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    }
197872b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    if (srcCount > glyphCount) {
197972b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com        int extra = 0;
198072b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com        for (int i = 0; i < glyphCount; ++i) {
198172b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            if (SkUTF16_IsHighSurrogate(src[i + extra])) {
198272b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com                ++extra;
198372b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            }
198472b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com            compactedGlyphs[i] = macGlyphs[i + extra];
198572b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com        }
198672b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    }
198772b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com
198872b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    if (allEncoded) {
1989bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com        return glyphCount;
1990bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    }
199172b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com
199272b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // If we got false, then we need to manually look for first failure.
1993bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    for (int i = 0; i < glyphCount; ++i) {
199472b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com        if (0 == compactedGlyphs[i]) {
1995bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com            return i;
1996bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com        }
1997bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    }
199872b8cb2320dddc6e006a2857746014e607e9e151bungeman@google.com    // Odd to get here, as we expected CT to have returned true up front.
1999bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com    return glyphCount;
2000bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com}
2001bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com
2002bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.comint SkTypeface_Mac::onCountGlyphs() const {
20037fa2a65c0cfc714364490cb715171461143024e0reed@google.com    return SkToInt(CTFontGetGlyphCount(fFontRef));
2004bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com}
2005bcb42aecf1bdb9ae80d766d203b4f636b954cf03reed@google.com
200695625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com///////////////////////////////////////////////////////////////////////////////
200795625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com///////////////////////////////////////////////////////////////////////////////
200895625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com#if 1
200983787c55db37e382ae36231a7b9458991228c10areed@google.com
201083787c55db37e382ae36231a7b9458991228c10areed@google.comstatic bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
201183787c55db37e382ae36231a7b9458991228c10areed@google.com    AutoCFRelease<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
201283787c55db37e382ae36231a7b9458991228c10areed@google.com    if (NULL == ref.get()) {
201383787c55db37e382ae36231a7b9458991228c10areed@google.com        return false;
201483787c55db37e382ae36231a7b9458991228c10areed@google.com    }
201583787c55db37e382ae36231a7b9458991228c10areed@google.com    CFStringToSkString(ref, value);
201683787c55db37e382ae36231a7b9458991228c10areed@google.com    return true;
201783787c55db37e382ae36231a7b9458991228c10areed@google.com}
201883787c55db37e382ae36231a7b9458991228c10areed@google.com
201983787c55db37e382ae36231a7b9458991228c10areed@google.comstatic bool find_dict_float(CFDictionaryRef dict, CFStringRef name, float* value) {
202083787c55db37e382ae36231a7b9458991228c10areed@google.com    CFNumberRef num;
202183787c55db37e382ae36231a7b9458991228c10areed@google.com    return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num)
202283787c55db37e382ae36231a7b9458991228c10areed@google.com    && CFNumberIsFloatType(num)
202383787c55db37e382ae36231a7b9458991228c10areed@google.com    && CFNumberGetValue(num, kCFNumberFloatType, value);
202483787c55db37e382ae36231a7b9458991228c10areed@google.com}
202583787c55db37e382ae36231a7b9458991228c10areed@google.com
202695625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com#include "SkFontMgr.h"
202795625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com
202883787c55db37e382ae36231a7b9458991228c10areed@google.comstatic int unit_weight_to_fontstyle(float unit) {
202983787c55db37e382ae36231a7b9458991228c10areed@google.com    float value;
203083787c55db37e382ae36231a7b9458991228c10areed@google.com    if (unit < 0) {
203183787c55db37e382ae36231a7b9458991228c10areed@google.com        value = 100 + (1 + unit) * 300;
203283787c55db37e382ae36231a7b9458991228c10areed@google.com    } else {
203383787c55db37e382ae36231a7b9458991228c10areed@google.com        value = 400 + unit * 500;
203483787c55db37e382ae36231a7b9458991228c10areed@google.com    }
203583787c55db37e382ae36231a7b9458991228c10areed@google.com    return sk_float_round2int(value);
203683787c55db37e382ae36231a7b9458991228c10areed@google.com}
203783787c55db37e382ae36231a7b9458991228c10areed@google.com
203883787c55db37e382ae36231a7b9458991228c10areed@google.comstatic int unit_width_to_fontstyle(float unit) {
203983787c55db37e382ae36231a7b9458991228c10areed@google.com    float value;
204083787c55db37e382ae36231a7b9458991228c10areed@google.com    if (unit < 0) {
204183787c55db37e382ae36231a7b9458991228c10areed@google.com        value = 1 + (1 + unit) * 4;
204283787c55db37e382ae36231a7b9458991228c10areed@google.com    } else {
204383787c55db37e382ae36231a7b9458991228c10areed@google.com        value = 5 + unit * 4;
204483787c55db37e382ae36231a7b9458991228c10areed@google.com    }
204583787c55db37e382ae36231a7b9458991228c10areed@google.com    return sk_float_round2int(value);
204683787c55db37e382ae36231a7b9458991228c10areed@google.com}
204783787c55db37e382ae36231a7b9458991228c10areed@google.com
2048964988f0e93f4a559b7e41db53d70d0282527350reed@google.comstatic inline int sqr(int value) {
2049964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    SkASSERT(SkAbs32(value) < 0x7FFF);  // check for overflow
2050964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    return value * value;
2051964988f0e93f4a559b7e41db53d70d0282527350reed@google.com}
2052964988f0e93f4a559b7e41db53d70d0282527350reed@google.com
2053964988f0e93f4a559b7e41db53d70d0282527350reed@google.com// We normalize each axis (weight, width, italic) to be base-900
2054964988f0e93f4a559b7e41db53d70d0282527350reed@google.comstatic int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
2055964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    return sqr(a.weight() - b.weight()) +
2056964988f0e93f4a559b7e41db53d70d0282527350reed@google.com           sqr((a.width() - b.width()) * 100) +
2057964988f0e93f4a559b7e41db53d70d0282527350reed@google.com           sqr((a.isItalic() != b.isItalic()) * 900);
2058964988f0e93f4a559b7e41db53d70d0282527350reed@google.com}
2059964988f0e93f4a559b7e41db53d70d0282527350reed@google.com
206083787c55db37e382ae36231a7b9458991228c10areed@google.comstatic SkFontStyle desc2fontstyle(CTFontDescriptorRef desc) {
206183787c55db37e382ae36231a7b9458991228c10areed@google.com    AutoCFRelease<CFDictionaryRef> dict(
206283787c55db37e382ae36231a7b9458991228c10areed@google.com        (CFDictionaryRef)CTFontDescriptorCopyAttribute(desc,
206383787c55db37e382ae36231a7b9458991228c10areed@google.com                                                       kCTFontTraitsAttribute));
206483787c55db37e382ae36231a7b9458991228c10areed@google.com    if (NULL == dict.get()) {
206583787c55db37e382ae36231a7b9458991228c10areed@google.com        return SkFontStyle();
206683787c55db37e382ae36231a7b9458991228c10areed@google.com    }
206783787c55db37e382ae36231a7b9458991228c10areed@google.com
206883787c55db37e382ae36231a7b9458991228c10areed@google.com    float weight, width, slant;
206983787c55db37e382ae36231a7b9458991228c10areed@google.com    if (!find_dict_float(dict, kCTFontWeightTrait, &weight)) {
207083787c55db37e382ae36231a7b9458991228c10areed@google.com        weight = 0;
207183787c55db37e382ae36231a7b9458991228c10areed@google.com    }
207283787c55db37e382ae36231a7b9458991228c10areed@google.com    if (!find_dict_float(dict, kCTFontWidthTrait, &width)) {
207383787c55db37e382ae36231a7b9458991228c10areed@google.com        width = 0;
207483787c55db37e382ae36231a7b9458991228c10areed@google.com    }
207583787c55db37e382ae36231a7b9458991228c10areed@google.com    if (!find_dict_float(dict, kCTFontSlantTrait, &slant)) {
207683787c55db37e382ae36231a7b9458991228c10areed@google.com        slant = 0;
207783787c55db37e382ae36231a7b9458991228c10areed@google.com    }
207837cbc7fd014e3b35833523dbdbe3bc3ac52ecacdskia.committer@gmail.com
207983787c55db37e382ae36231a7b9458991228c10areed@google.com    return SkFontStyle(unit_weight_to_fontstyle(weight),
208083787c55db37e382ae36231a7b9458991228c10areed@google.com                       unit_width_to_fontstyle(width),
208183787c55db37e382ae36231a7b9458991228c10areed@google.com                       slant ? SkFontStyle::kItalic_Slant
208283787c55db37e382ae36231a7b9458991228c10areed@google.com                       : SkFontStyle::kUpright_Slant);
208383787c55db37e382ae36231a7b9458991228c10areed@google.com}
208483787c55db37e382ae36231a7b9458991228c10areed@google.com
2085dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.comstruct NameFontStyleRec {
2086dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    SkString    fFamilyName;
2087dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    SkFontStyle fFontStyle;
2088dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com};
2089dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com
2090dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.comstatic bool nameFontStyleProc(SkTypeface* face, SkTypeface::Style,
2091dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com                              void* ctx) {
2092dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    SkTypeface_Mac* macFace = (SkTypeface_Mac*)face;
2093dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    const NameFontStyleRec* rec = (const NameFontStyleRec*)ctx;
2094dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com
2095dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    return macFace->fFontStyle == rec->fFontStyle &&
2096dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com           macFace->fName == rec->fFamilyName;
2097dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com}
2098dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com
2099ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.comstatic SkTypeface* createFromDesc(CFStringRef cfFamilyName,
2100ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com                                  CTFontDescriptorRef desc) {
2101dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    NameFontStyleRec rec;
2102dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    CFStringToSkString(cfFamilyName, &rec.fFamilyName);
2103dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    rec.fFontStyle = desc2fontstyle(desc);
2104dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com
2105dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    SkTypeface* face = SkTypefaceCache::FindByProcAndRef(nameFontStyleProc,
2106dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com                                                         &rec);
2107dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    if (face) {
2108dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com        return face;
2109dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    }
2110dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com
211145dfe6bb55828b8e819933279edc815f2fd6229acommit-bot@chromium.org    AutoCFRelease<CFDictionaryRef> fontFamilyNameDictionary(
211245dfe6bb55828b8e819933279edc815f2fd6229acommit-bot@chromium.org        CFDictionaryCreate(kCFAllocatorDefault,
211345dfe6bb55828b8e819933279edc815f2fd6229acommit-bot@chromium.org                           (const void**)&kCTFontFamilyNameAttribute, (const void**)&cfFamilyName,
211445dfe6bb55828b8e819933279edc815f2fd6229acommit-bot@chromium.org                           1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
211545dfe6bb55828b8e819933279edc815f2fd6229acommit-bot@chromium.org    AutoCFRelease<CTFontDescriptorRef> fontDescriptor(
211645dfe6bb55828b8e819933279edc815f2fd6229acommit-bot@chromium.org        CTFontDescriptorCreateWithAttributes(fontFamilyNameDictionary));
211745dfe6bb55828b8e819933279edc815f2fd6229acommit-bot@chromium.org    AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithFontDescriptor(fontDescriptor, 0, NULL));
2118ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    CTFontRef ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL, desc);
2119ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    if (NULL == ctFont) {
2120ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com        return NULL;
2121ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    }
212237cbc7fd014e3b35833523dbdbe3bc3ac52ecacdskia.committer@gmail.com
2123ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    SkString str;
2124ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    CFStringToSkString(cfFamilyName, &str);
212537cbc7fd014e3b35833523dbdbe3bc3ac52ecacdskia.committer@gmail.com
2126ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    bool isFixedPitch;
2127ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    (void)computeStyleBits(ctFont, &isFixedPitch);
2128ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com    SkFontID fontID = CTFontRef_to_SkFontID(ctFont);
212937cbc7fd014e3b35833523dbdbe3bc3ac52ecacdskia.committer@gmail.com
2130dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    face = SkNEW_ARGS(SkTypeface_Mac, (rec.fFontStyle, fontID, isFixedPitch,
2131dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com                                       ctFont, str.c_str()));
2132dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    SkTypefaceCache::Add(face, face->style());
2133dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    return face;
2134ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com}
2135ce8b3de6058eae07ddc2eed6f96701e009bb91ecreed@google.com
213683787c55db37e382ae36231a7b9458991228c10areed@google.comclass SkFontStyleSet_Mac : public SkFontStyleSet {
213783787c55db37e382ae36231a7b9458991228c10areed@google.compublic:
213883787c55db37e382ae36231a7b9458991228c10areed@google.com    SkFontStyleSet_Mac(CFStringRef familyName, CTFontDescriptorRef desc)
213983787c55db37e382ae36231a7b9458991228c10areed@google.com        : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, NULL))
2140dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com        , fFamilyName(familyName)
2141dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com        , fCount(0) {
214283787c55db37e382ae36231a7b9458991228c10areed@google.com        CFRetain(familyName);
2143dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com        if (NULL == fArray) {
2144dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com            fArray = CFArrayCreate(NULL, NULL, 0, NULL);
2145dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com        }
21467fa2a65c0cfc714364490cb715171461143024e0reed@google.com        fCount = SkToInt(CFArrayGetCount(fArray));
214783787c55db37e382ae36231a7b9458991228c10areed@google.com    }
214837cbc7fd014e3b35833523dbdbe3bc3ac52ecacdskia.committer@gmail.com
214983787c55db37e382ae36231a7b9458991228c10areed@google.com    virtual ~SkFontStyleSet_Mac() {
2150dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com        CFRelease(fArray);
215183787c55db37e382ae36231a7b9458991228c10areed@google.com        CFRelease(fFamilyName);
215283787c55db37e382ae36231a7b9458991228c10areed@google.com    }
215383787c55db37e382ae36231a7b9458991228c10areed@google.com
215483787c55db37e382ae36231a7b9458991228c10areed@google.com    virtual int count() SK_OVERRIDE {
2155dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com        return fCount;
215683787c55db37e382ae36231a7b9458991228c10areed@google.com    }
215783787c55db37e382ae36231a7b9458991228c10areed@google.com
215883787c55db37e382ae36231a7b9458991228c10areed@google.com    virtual void getStyle(int index, SkFontStyle* style,
215983787c55db37e382ae36231a7b9458991228c10areed@google.com                          SkString* name) SK_OVERRIDE {
2160dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com        SkASSERT((unsigned)index < (unsigned)fCount);
216183787c55db37e382ae36231a7b9458991228c10areed@google.com        CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
216283787c55db37e382ae36231a7b9458991228c10areed@google.com        if (style) {
216383787c55db37e382ae36231a7b9458991228c10areed@google.com            *style = desc2fontstyle(desc);
216483787c55db37e382ae36231a7b9458991228c10areed@google.com        }
216583787c55db37e382ae36231a7b9458991228c10areed@google.com        if (name) {
216683787c55db37e382ae36231a7b9458991228c10areed@google.com            if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
216783787c55db37e382ae36231a7b9458991228c10areed@google.com                name->reset();
216883787c55db37e382ae36231a7b9458991228c10areed@google.com            }
216983787c55db37e382ae36231a7b9458991228c10areed@google.com        }
217083787c55db37e382ae36231a7b9458991228c10areed@google.com    }
217183787c55db37e382ae36231a7b9458991228c10areed@google.com
217283787c55db37e382ae36231a7b9458991228c10areed@google.com    virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
217383787c55db37e382ae36231a7b9458991228c10areed@google.com        SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray));
217483787c55db37e382ae36231a7b9458991228c10areed@google.com        CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
217537cbc7fd014e3b35833523dbdbe3bc3ac52ecacdskia.committer@gmail.com
217683787c55db37e382ae36231a7b9458991228c10areed@google.com        return createFromDesc(fFamilyName, desc);
217783787c55db37e382ae36231a7b9458991228c10areed@google.com    }
217837cbc7fd014e3b35833523dbdbe3bc3ac52ecacdskia.committer@gmail.com
2179964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
2180964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        if (0 == fCount) {
2181964988f0e93f4a559b7e41db53d70d0282527350reed@google.com            return NULL;
2182964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        }
2183964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        return createFromDesc(fFamilyName, findMatchingDesc(pattern));
2184964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    }
2185964988f0e93f4a559b7e41db53d70d0282527350reed@google.com
218683787c55db37e382ae36231a7b9458991228c10areed@google.comprivate:
218783787c55db37e382ae36231a7b9458991228c10areed@google.com    CFArrayRef  fArray;
218883787c55db37e382ae36231a7b9458991228c10areed@google.com    CFStringRef fFamilyName;
2189dea7ee04d31d0f269cdc8db49b9225fc937b9622reed@google.com    int         fCount;
2190964988f0e93f4a559b7e41db53d70d0282527350reed@google.com
2191964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
2192964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        int bestMetric = SK_MaxS32;
2193964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        CTFontDescriptorRef bestDesc = NULL;
2194d55846d100bb09448b398b41798bd4ab100a753askia.committer@gmail.com
2195964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        for (int i = 0; i < fCount; ++i) {
2196964988f0e93f4a559b7e41db53d70d0282527350reed@google.com            CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, i);
2197964988f0e93f4a559b7e41db53d70d0282527350reed@google.com            int metric = compute_metric(pattern, desc2fontstyle(desc));
2198964988f0e93f4a559b7e41db53d70d0282527350reed@google.com            if (0 == metric) {
2199964988f0e93f4a559b7e41db53d70d0282527350reed@google.com                return desc;
2200964988f0e93f4a559b7e41db53d70d0282527350reed@google.com            }
2201964988f0e93f4a559b7e41db53d70d0282527350reed@google.com            if (metric < bestMetric) {
2202964988f0e93f4a559b7e41db53d70d0282527350reed@google.com                bestMetric = metric;
2203964988f0e93f4a559b7e41db53d70d0282527350reed@google.com                bestDesc = desc;
2204964988f0e93f4a559b7e41db53d70d0282527350reed@google.com            }
2205964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        }
2206964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        SkASSERT(bestDesc);
2207964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        return bestDesc;
2208964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    }
220983787c55db37e382ae36231a7b9458991228c10areed@google.com};
221083787c55db37e382ae36231a7b9458991228c10areed@google.com
221195625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.comclass SkFontMgr_Mac : public SkFontMgr {
221283787c55db37e382ae36231a7b9458991228c10areed@google.com    CFArrayRef  fNames;
2213967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org    int         fCount;
221483787c55db37e382ae36231a7b9458991228c10areed@google.com
221583787c55db37e382ae36231a7b9458991228c10areed@google.com    CFStringRef stringAt(int index) const {
221683787c55db37e382ae36231a7b9458991228c10areed@google.com        SkASSERT((unsigned)index < (unsigned)fCount);
221783787c55db37e382ae36231a7b9458991228c10areed@google.com        return (CFStringRef)CFArrayGetValueAtIndex(fNames, index);
221883787c55db37e382ae36231a7b9458991228c10areed@google.com    }
221983787c55db37e382ae36231a7b9458991228c10areed@google.com
2220964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) {
2221964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        AutoCFRelease<CFMutableDictionaryRef> cfAttr(
2222964988f0e93f4a559b7e41db53d70d0282527350reed@google.com                 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2223964988f0e93f4a559b7e41db53d70d0282527350reed@google.com                                           &kCFTypeDictionaryKeyCallBacks,
2224964988f0e93f4a559b7e41db53d70d0282527350reed@google.com                                           &kCFTypeDictionaryValueCallBacks));
2225d55846d100bb09448b398b41798bd4ab100a753askia.committer@gmail.com
2226964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        CFDictionaryAddValue(cfAttr, kCTFontFamilyNameAttribute, cfFamilyName);
2227d55846d100bb09448b398b41798bd4ab100a753askia.committer@gmail.com
2228964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        AutoCFRelease<CTFontDescriptorRef> desc(
2229964988f0e93f4a559b7e41db53d70d0282527350reed@google.com                                CTFontDescriptorCreateWithAttributes(cfAttr));
2230964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        return SkNEW_ARGS(SkFontStyleSet_Mac, (cfFamilyName, desc));
2231964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    }
2232d55846d100bb09448b398b41798bd4ab100a753askia.committer@gmail.com
223395625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.compublic:
2234967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org    SkFontMgr_Mac()
2235967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org        : fNames(SkCTFontManagerCopyAvailableFontFamilyNames())
2236967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org        , fCount(fNames ? SkToInt(CFArrayGetCount(fNames)) : 0) {}
223783787c55db37e382ae36231a7b9458991228c10areed@google.com
223883787c55db37e382ae36231a7b9458991228c10areed@google.com    virtual ~SkFontMgr_Mac() {
223983787c55db37e382ae36231a7b9458991228c10areed@google.com        CFSafeRelease(fNames);
224083787c55db37e382ae36231a7b9458991228c10areed@google.com    }
224195625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com
224295625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.comprotected:
2243967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org    virtual int onCountFamilies() const SK_OVERRIDE {
224483787c55db37e382ae36231a7b9458991228c10areed@google.com        return fCount;
224595625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    }
224695625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com
2247967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org    virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
224883787c55db37e382ae36231a7b9458991228c10areed@google.com        if ((unsigned)index < (unsigned)fCount) {
224983787c55db37e382ae36231a7b9458991228c10areed@google.com            CFStringToSkString(this->stringAt(index), familyName);
225083787c55db37e382ae36231a7b9458991228c10areed@google.com        } else {
225183787c55db37e382ae36231a7b9458991228c10areed@google.com            familyName->reset();
225283787c55db37e382ae36231a7b9458991228c10areed@google.com        }
225395625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    }
225495625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com
2255967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org    virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
225683787c55db37e382ae36231a7b9458991228c10areed@google.com        if ((unsigned)index >= (unsigned)fCount) {
225783787c55db37e382ae36231a7b9458991228c10areed@google.com            return NULL;
225883787c55db37e382ae36231a7b9458991228c10areed@google.com        }
2259964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        return CreateSet(this->stringAt(index));
226095625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    }
2261d55846d100bb09448b398b41798bd4ab100a753askia.committer@gmail.com
2262967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org    virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
2263964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        AutoCFRelease<CFStringRef> cfName(make_CFString(familyName));
2264964988f0e93f4a559b7e41db53d70d0282527350reed@google.com        return CreateSet(cfName);
2265964988f0e93f4a559b7e41db53d70d0282527350reed@google.com    }
2266d55846d100bb09448b398b41798bd4ab100a753askia.committer@gmail.com
226795625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
2268967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org                                           const SkFontStyle&) const SK_OVERRIDE {
226995625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        return NULL;
227095625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    }
2271e60ed08a3568b5e253dfb5dec2b52d13a16fff1cskia.committer@gmail.com
227295625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2273967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org                                         const SkFontStyle&) const SK_OVERRIDE {
227495625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        return NULL;
227595625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    }
2276e60ed08a3568b5e253dfb5dec2b52d13a16fff1cskia.committer@gmail.com
227795625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    virtual SkTypeface* onCreateFromData(SkData* data,
2278967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org                                         int ttcIndex) const SK_OVERRIDE {
227995625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromData(data));
228095625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        if (NULL == pr) {
228195625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com            return NULL;
228295625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        }
228395625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        return create_from_dataProvider(pr);
228495625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    }
228595625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com
228695625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    virtual SkTypeface* onCreateFromStream(SkStream* stream,
2287967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org                                           int ttcIndex) const SK_OVERRIDE {
228895625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromStream(stream));
228995625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        if (NULL == pr) {
229095625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com            return NULL;
229195625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        }
229295625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        return create_from_dataProvider(pr);
229395625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    }
229495625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com
229595625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    virtual SkTypeface* onCreateFromFile(const char path[],
2296967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org                                         int ttcIndex) const SK_OVERRIDE {
229795625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        AutoCFRelease<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path));
229895625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        if (NULL == pr) {
229995625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com            return NULL;
230095625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        }
230195625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com        return create_from_dataProvider(pr);
230295625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    }
230376015b09536c664bd59b370be7691d4b69553d95skia.committer@gmail.com
23047fdcd444a1bd6a2f173c141e09e7ad9c11730ad2reed@google.com    virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
2305967dee32ef540b7c0fed6d0cd518d42b9b345c78commit-bot@chromium.org                                               unsigned styleBits) const SK_OVERRIDE {
23067fdcd444a1bd6a2f173c141e09e7ad9c11730ad2reed@google.com        return create_typeface(NULL, familyName, (SkTypeface::Style)styleBits);
23077fdcd444a1bd6a2f173c141e09e7ad9c11730ad2reed@google.com    }
230895625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com};
230995625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com
23107fdcd444a1bd6a2f173c141e09e7ad9c11730ad2reed@google.com///////////////////////////////////////////////////////////////////////////////
23117fdcd444a1bd6a2f173c141e09e7ad9c11730ad2reed@google.com
231295625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.comSkFontMgr* SkFontMgr::Factory() {
231395625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com    return SkNEW(SkFontMgr_Mac);
231495625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com}
231595625dbcb6b2960732bc27ad0dd0fc4adbb4f7c0reed@google.com#endif
2316