1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
23ee74d5653c16a5aa318f1d6274467a23f6049b5reed@android.com/*
3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2006 The Android Open Source Project
4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com *
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */
8685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
9e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include <vector>
10e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#ifdef SK_BUILD_FOR_MAC
11e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#import <ApplicationServices/ApplicationServices.h>
12e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#endif
13e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
14e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#ifdef SK_BUILD_FOR_IOS
15e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include <CoreText/CoreText.h>
169c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com#include <CoreText/CTFontManager.h>
17e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include <CoreGraphics/CoreGraphics.h>
18e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include <CoreFoundation/CoreFoundation.h>
19e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#endif
203ee74d5653c16a5aa318f1d6274467a23f6049b5reed@android.com
21e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkFontHost.h"
22e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkCGUtils.h"
23e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkColorPriv.h"
24e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkDescriptor.h"
25e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkEndian.h"
26e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkFontDescriptor.h"
27e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkFloatingPoint.h"
28e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkGlyph.h"
29e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkMaskGamma.h"
30e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkSFNTHeader.h"
31e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkOTTable_glyf.h"
32e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkOTTable_head.h"
33e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkOTTable_hhea.h"
34e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkOTTable_loca.h"
35e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkOTUtils.h"
36e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkPaint.h"
37e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkPath.h"
38e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkString.h"
39e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkStream.h"
40e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkThread.h"
41e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkTypeface_mac.h"
42e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkUtils.h"
43e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkTypefaceCache.h"
44b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com#include "SkFontMgr.h"
4548c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com#include "SkUtils.h"
463ee74d5653c16a5aa318f1d6274467a23f6049b5reed@android.com
471ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com//#define HACK_COLORGLYPHS
481ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com
49e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgclass SkScalerContext_Mac;
50e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
519c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com// CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we
529c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com// provide a wrapper here that will return an empty array if need be.
539c28f1149c205580cbb0f018b083d065a7ae9222reed@google.comstatic CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() {
549c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com#ifdef SK_BUILD_FOR_IOS
559c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com    return CFArrayCreate(NULL, NULL, 0, NULL);
569c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com#else
579c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com    return CTFontManagerCopyAvailableFontFamilyNames();
589c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com#endif
599c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com}
609c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com
619c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com
62e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// Being templated and taking const T* prevents calling
63e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// CFSafeRelease(autoCFRelease) through implicit conversion.
64e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtemplate <typename T> static void CFSafeRelease(/*CFTypeRef*/const T* cfTypeRef) {
65e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (cfTypeRef) {
66e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CFRelease(cfTypeRef);
67e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
68e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
69e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
70e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// Being templated and taking const T* prevents calling
71e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// CFSafeRetain(autoCFRelease) through implicit conversion.
72e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtemplate <typename T> static void CFSafeRetain(/*CFTypeRef*/const T* cfTypeRef) {
73e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (cfTypeRef) {
74e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CFRetain(cfTypeRef);
75e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
76e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
77e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
78e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org/** Acts like a CFRef, but calls CFSafeRelease when it goes out of scope. */
79e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtemplate<typename CFRef> class AutoCFRelease : private SkNoncopyable {
80e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgpublic:
81e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    explicit AutoCFRelease(CFRef cfRef = NULL) : fCFRef(cfRef) { }
82e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    ~AutoCFRelease() { CFSafeRelease(fCFRef); }
83e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
84e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    void reset(CFRef that = NULL) {
85e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CFSafeRetain(that);
86e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CFSafeRelease(fCFRef);
87e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        fCFRef = that;
88e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
89e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
90e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease& operator =(CFRef that) {
91e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        reset(that);
92e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return *this;
93e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
94e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
95e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    operator CFRef() const { return fCFRef; }
96e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CFRef get() const { return fCFRef; }
97e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
98ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com    CFRef* operator&() { SkASSERT(fCFRef == NULL); return &fCFRef; }
99e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgprivate:
100e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CFRef fCFRef;
101e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org};
102e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
103ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.comstatic CFStringRef make_CFString(const char str[]) {
104ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    return CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8);
105ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com}
106ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com
107e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtemplate<typename T> class AutoCGTable : SkNoncopyable {
108e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgpublic:
109e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCGTable(CGFontRef font)
110e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    //Undocumented: the tag parameter in this call is expected in machine order and not BE order.
111e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    : fCFData(CGFontCopyTableForTag(font, SkSetFourByteTag(T::TAG0, T::TAG1, T::TAG2, T::TAG3)))
112e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    , fData(fCFData ? reinterpret_cast<const T*>(CFDataGetBytePtr(fCFData)) : NULL)
113e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    { }
114e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
115e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const T* operator->() const { return fData; }
116e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
117e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgprivate:
118e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CFDataRef> fCFData;
119e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgpublic:
120e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const T* fData;
121e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org};
122e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
123e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// inline versions of these rect helpers
124e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
125e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic bool CGRectIsEmpty_inline(const CGRect& rect) {
126e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return rect.size.width <= 0 || rect.size.height <= 0;
127e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
128e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
129e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic CGFloat CGRectGetMinX_inline(const CGRect& rect) {
130e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return rect.origin.x;
131e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
132e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
133e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic CGFloat CGRectGetMaxX_inline(const CGRect& rect) {
134e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return rect.origin.x + rect.size.width;
135e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
136e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
137e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic CGFloat CGRectGetMinY_inline(const CGRect& rect) {
138e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return rect.origin.y;
139e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
140e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
141e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic CGFloat CGRectGetMaxY_inline(const CGRect& rect) {
142e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return rect.origin.y + rect.size.height;
143e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
144e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
145e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic CGFloat CGRectGetWidth_inline(const CGRect& rect) {
146e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return rect.size.width;
147e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
148e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
149e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
150e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
151e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic void sk_memset_rect32(uint32_t* ptr, uint32_t value,
152e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                             size_t width, size_t height, size_t rowBytes) {
153e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkASSERT(width);
154e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkASSERT(width * sizeof(uint32_t) <= rowBytes);
155e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
156e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (width >= 32) {
157e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        while (height) {
158e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            sk_memset32(ptr, value, width);
159e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            ptr = (uint32_t*)((char*)ptr + rowBytes);
160e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            height -= 1;
161e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
162e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return;
163e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
164e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
165e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    rowBytes -= width * sizeof(uint32_t);
166e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
167e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (width >= 8) {
168e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        while (height) {
169e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            int w = width;
170e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            do {
171e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                *ptr++ = value; *ptr++ = value;
172e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                *ptr++ = value; *ptr++ = value;
173e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                *ptr++ = value; *ptr++ = value;
174e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                *ptr++ = value; *ptr++ = value;
175e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                w -= 8;
176e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            } while (w >= 8);
177e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            while (--w >= 0) {
178e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                *ptr++ = value;
179e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            }
180e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            ptr = (uint32_t*)((char*)ptr + rowBytes);
181e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            height -= 1;
182e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
183e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    } else {
184e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        while (height) {
185e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            int w = width;
186e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            do {
187e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                *ptr++ = value;
188e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            } while (--w > 0);
189e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            ptr = (uint32_t*)((char*)ptr + rowBytes);
190e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            height -= 1;
191e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
192e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
193e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
194e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
195e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include <sys/utsname.h>
196e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
197e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtypedef uint32_t CGRGBPixel;
198e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
199e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) {
200e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return pixel & 0xFF;
201e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
202e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
203e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// The calls to support subpixel are present in 10.5, but are not included in
204e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// the 10.5 SDK. The needed calls have been extracted from the 10.6 SDK and are
205e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// included below. To verify that CGContextSetShouldSubpixelQuantizeFonts, for
206e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// instance, is present in the 10.5 CoreGraphics libary, use:
207e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org//   cd /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/
208e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org//   cd ApplicationServices.framework/Frameworks/CoreGraphics.framework/
209e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org//   nm CoreGraphics | grep CGContextSetShouldSubpixelQuantizeFonts
210e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
211e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#if !defined(MAC_OS_X_VERSION_10_6) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6)
212e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgCG_EXTERN void CGContextSetAllowsFontSmoothing(CGContextRef context, bool value);
213e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgCG_EXTERN void CGContextSetAllowsFontSubpixelPositioning(CGContextRef context, bool value);
214e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgCG_EXTERN void CGContextSetShouldSubpixelPositionFonts(CGContextRef context, bool value);
215e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgCG_EXTERN void CGContextSetAllowsFontSubpixelQuantization(CGContextRef context, bool value);
216e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgCG_EXTERN void CGContextSetShouldSubpixelQuantizeFonts(CGContextRef context, bool value);
217aa2f67cf5e22a8d3b7f86ba9be565ff94cf4e2b2reed@android.com#endif
21836a54d5bdd040d4df9c53c298bb0c3af26497e33reed@android.com
219e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic const char FONT_DEFAULT_NAME[] = "Lucida Sans";
220e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
221e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// See Source/WebKit/chromium/base/mac/mac_util.mm DarwinMajorVersionInternal for original source.
222e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic int readVersion() {
223e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    struct utsname info;
224e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (uname(&info) != 0) {
225e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkDebugf("uname failed\n");
226e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return 0;
227e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
228e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (strcmp(info.sysname, "Darwin") != 0) {
229e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkDebugf("unexpected uname sysname %s\n", info.sysname);
230e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return 0;
231e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
232e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    char* dot = strchr(info.release, '.');
233e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!dot) {
234e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkDebugf("expected dot in uname release %s\n", info.release);
235e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return 0;
236e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
237e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    int version = atoi(info.release);
238e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (version == 0) {
239e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkDebugf("could not parse uname release %s\n", info.release);
240e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
241e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return version;
242e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
243e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
244e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic int darwinVersion() {
245e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    static int darwin_version = readVersion();
246e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return darwin_version;
247e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
248e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
249e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic bool isSnowLeopard() {
250e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return darwinVersion() == 10;
251e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
252e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
253e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic bool isLion() {
254e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return darwinVersion() == 11;
255e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
256e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
257e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic bool isMountainLion() {
258e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return darwinVersion() == 12;
259e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
260e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
261e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic bool isLCDFormat(unsigned format) {
262e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return SkMask::kLCD16_Format == format || SkMask::kLCD32_Format == format;
263e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
264e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
265e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic CGFloat ScalarToCG(SkScalar scalar) {
266e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (sizeof(CGFloat) == sizeof(float)) {
267e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return SkScalarToFloat(scalar);
268e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    } else {
269e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkASSERT(sizeof(CGFloat) == sizeof(double));
270e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return (CGFloat) SkScalarToDouble(scalar);
271e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
272e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
273e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
274e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic SkScalar CGToScalar(CGFloat cgFloat) {
275e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (sizeof(CGFloat) == sizeof(float)) {
276e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return SkFloatToScalar(cgFloat);
277e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    } else {
278e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkASSERT(sizeof(CGFloat) == sizeof(double));
279e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return SkDoubleToScalar(cgFloat);
280e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
281e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
282e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
283e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix,
284e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                                   SkScalar sx = SK_Scalar1,
285e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                                   SkScalar sy = SK_Scalar1) {
286e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx),
287e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                 -ScalarToCG(matrix[SkMatrix::kMSkewY]  * sy),
288e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                 -ScalarToCG(matrix[SkMatrix::kMSkewX]  * sx),
289e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                  ScalarToCG(matrix[SkMatrix::kMScaleY] * sy),
290e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                  ScalarToCG(matrix[SkMatrix::kMTransX] * sx),
291e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                  ScalarToCG(matrix[SkMatrix::kMTransY] * sy));
292e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
293e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
294e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
295e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
296e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
297e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#define BITMAP_INFO_GRAY (kCGImageAlphaNone)
298e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
299e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org/**
300e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org * There does not appear to be a publicly accessable API for determining if lcd
301e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org * font smoothing will be applied if we request it. The main issue is that if
302e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0.
303e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org */
304e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic bool supports_LCD() {
305e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    static int gSupportsLCD = -1;
306e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (gSupportsLCD >= 0) {
307e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return (bool) gSupportsLCD;
308e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
309e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint32_t rgb = 0;
310e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
311e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CGContextRef> cgContext(CGBitmapContextCreate(&rgb, 1, 1, 8, 4,
312e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                                                colorspace, BITMAP_INFO_RGB));
313e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGContextSelectFont(cgContext, "Helvetica", 16, kCGEncodingMacRoman);
314e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGContextSetShouldSmoothFonts(cgContext, true);
315e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGContextSetShouldAntialias(cgContext, true);
316e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGContextSetTextDrawingMode(cgContext, kCGTextFill);
317e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGContextSetGrayFillColor(cgContext, 1, 1);
318e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1);
319e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint32_t r = (rgb >> 16) & 0xFF;
320e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint32_t g = (rgb >>  8) & 0xFF;
321e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint32_t b = (rgb >>  0) & 0xFF;
322e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    gSupportsLCD = (r != g || r != b);
323e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return (bool) gSupportsLCD;
324e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
325e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
326e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgclass Offscreen {
327e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgpublic:
328e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    Offscreen();
329e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
330e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
331e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                      CGGlyph glyphID, size_t* rowBytesPtr,
332e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                      bool generateA8FromLCD);
333e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
334e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgprivate:
335e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    enum {
336e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        kSize = 32 * 32 * sizeof(CGRGBPixel)
337e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    };
338e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkAutoSMalloc<kSize> fImageStorage;
339e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CGColorSpaceRef> fRGBSpace;
340e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
341e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // cached state
342e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CGContextRef> fCG;
343e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkISize fSize;
344e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    bool fDoAA;
345e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    bool fDoLCD;
346e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
347e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    static int RoundSize(int dimension) {
348e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return SkNextPow2(dimension);
349e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
350e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org};
351e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
352e0a1ec938fbf36150f4d0869cf95fb5b7e0edcceskia.committer@gmail.comOffscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL),
353bae2c4d75eabc19e9ce74ec250d1901c02bdb9derobertphillips@google.com                         fDoAA(false), fDoLCD(false) {
354e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    fSize.set(0, 0);
355e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
356e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
357e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
358e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
35902799b558fe28f9869ebb4291834e93101ef44f4bungeman@google.comstatic SkTypeface::Style computeStyleBits(CTFontRef font, bool* isFixedPitch) {
360e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    unsigned style = SkTypeface::kNormal;
361e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font);
362e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
363e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (traits & kCTFontBoldTrait) {
364e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        style |= SkTypeface::kBold;
365e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
366e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (traits & kCTFontItalicTrait) {
367e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        style |= SkTypeface::kItalic;
368e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
36902799b558fe28f9869ebb4291834e93101ef44f4bungeman@google.com    if (isFixedPitch) {
37002799b558fe28f9869ebb4291834e93101ef44f4bungeman@google.com        *isFixedPitch = (traits & kCTFontMonoSpaceTrait) != 0;
371e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
372e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return (SkTypeface::Style)style;
373e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
374e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
375e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic SkFontID CTFontRef_to_SkFontID(CTFontRef fontRef) {
376e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkFontID id = 0;
377e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// CTFontGetPlatformFont and ATSFontRef are not supported on iOS, so we have to
378e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// bracket this to be Mac only.
379e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#ifdef SK_BUILD_FOR_MAC
380e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    ATSFontRef ats = CTFontGetPlatformFont(fontRef, NULL);
381e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    id = (SkFontID)ats;
382e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (id != 0) {
383e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        id &= 0x3FFFFFFF; // make top two bits 00
384e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return id;
385e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
386e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#endif
387e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // CTFontGetPlatformFont returns NULL if the font is local
388e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // (e.g., was created by a CSS3 @font-face rule).
389e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fontRef, NULL));
390e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCGTable<SkOTTableHead> headTable(cgFont);
391e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (headTable.fData) {
392e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        id = (SkFontID) headTable->checksumAdjustment;
393e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        id = (id & 0x3FFFFFFF) | 0x40000000; // make top two bits 01
394e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
395e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // well-formed fonts have checksums, but as a last resort, use the pointer.
396e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (id == 0) {
397e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        id = (SkFontID) (uintptr_t) fontRef;
398e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        id = (id & 0x3FFFFFFF) | 0x80000000; // make top two bits 10
399e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
400e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return id;
401e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
402e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
403b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.comstatic SkFontStyle stylebits2fontstyle(SkTypeface::Style styleBits) {
404b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    return SkFontStyle((styleBits & SkTypeface::kBold)
405b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com                           ? SkFontStyle::kBold_Weight
406b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com                           : SkFontStyle::kNormal_Weight,
407b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com                       SkFontStyle::kNormal_Width,
408b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com                       (styleBits & SkTypeface::kItalic)
409b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com                           ? SkFontStyle::kItalic_Slant
410b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com                           : SkFontStyle::kUpright_Slant);
411b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com}
412b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com
413b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com#define WEIGHT_THRESHOLD    ((SkFontStyle::kNormal_Weight + SkFontStyle::kBold_Weight)/2)
414b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com
415b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.comstatic SkTypeface::Style fontstyle2stylebits(const SkFontStyle& fs) {
416b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    unsigned style = 0;
417b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    if (fs.width() >= WEIGHT_THRESHOLD) {
418b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        style |= SkTypeface::kBold;
419b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    }
420b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    if (fs.isItalic()) {
421b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        style |= SkTypeface::kItalic;
422b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    }
423b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    return (SkTypeface::Style)style;
424b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com}
425b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com
426e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgclass SkTypeface_Mac : public SkTypeface {
427e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgpublic:
42802799b558fe28f9869ebb4291834e93101ef44f4bungeman@google.com    SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isFixedPitch,
429e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                   CTFontRef fontRef, const char name[])
430b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        : SkTypeface(style, fontID, isFixedPitch)
431b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        , fName(name)
432b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        , fFontRef(fontRef) // caller has already called CFRetain for us
433b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        , fFontStyle(stylebits2fontstyle(style))
434e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    {
435e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkASSERT(fontRef);
436e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
437cb9a1cd72d397d254c18441743b79de0bbc3da09skia.committer@gmail.com
438b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    SkTypeface_Mac(const SkFontStyle& fs, SkFontID fontID, bool isFixedPitch,
439b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com                   CTFontRef fontRef, const char name[])
440b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        : SkTypeface(fontstyle2stylebits(fs), fontID, isFixedPitch)
441b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        , fName(name)
442b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        , fFontRef(fontRef) // caller has already called CFRetain for us
443b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        , fFontStyle(fs)
444b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    {
445b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        SkASSERT(fontRef);
446b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    }
447cb9a1cd72d397d254c18441743b79de0bbc3da09skia.committer@gmail.com
448e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkString fName;
449e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CTFontRef> fFontRef;
450b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    SkFontStyle fFontStyle;
451e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
452e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgprotected:
453e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    friend class SkFontHost;    // to access our protected members for deprecated methods
454e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
455e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    virtual int onGetUPEM() const SK_OVERRIDE;
456bbad7fe187bd8c112148dd7958bb645291f642ddreed@google.com    virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
4576e20a74d8cbcf19195559e8d98896fa22ebc535fbungeman@google.com    virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
458e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
459e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    virtual size_t onGetTableData(SkFontTableTag, size_t offset,
460e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                  size_t length, void* data) const SK_OVERRIDE;
461e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
462e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
4633d8295f60b8b733ec0210b08261e968ad79bf5c6reed@google.com    virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
4643dca9a6576d2baaf6132bbe736e8597723cbc5acreed@google.com    virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
4653dca9a6576d2baaf6132bbe736e8597723cbc5acreed@google.com                                SkAdvancedTypefaceMetrics::PerGlyphInfo,
4663dca9a6576d2baaf6132bbe736e8597723cbc5acreed@google.com                                const uint32_t*, uint32_t) const SK_OVERRIDE;
46748c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[],
46848c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com                                int glyphCount) const SK_OVERRIDE;
46948c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    virtual int onCountGlyphs() const SK_OVERRIDE;
470836008c1588a111f090a606726822d62d3026e00reed@google.com    virtual SkTypeface* onRefMatchingStyle(Style) const SK_OVERRIDE;
471f2b481703f64ccb4e7e25ccd5e80f2eed95a35ddskia.committer@gmail.com
472e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgprivate:
473b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com
474e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    typedef SkTypeface INHERITED;
475e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org};
476e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
477e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) {
478e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkASSERT(fontRef);
47902799b558fe28f9869ebb4291834e93101ef44f4bungeman@google.com    bool isFixedPitch;
48002799b558fe28f9869ebb4291834e93101ef44f4bungeman@google.com    SkTypeface::Style style = computeStyleBits(fontRef, &isFixedPitch);
481e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
482e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
48302799b558fe28f9869ebb4291834e93101ef44f4bungeman@google.com    return new SkTypeface_Mac(style, fontID, isFixedPitch, fontRef, name);
484e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
485e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
486e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic SkTypeface* NewFromName(const char familyName[], SkTypeface::Style theStyle) {
487e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CTFontRef ctFont = NULL;
488e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
489e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CTFontSymbolicTraits ctFontTraits = 0;
490e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (theStyle & SkTypeface::kBold) {
491e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        ctFontTraits |= kCTFontBoldTrait;
492e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
493e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (theStyle & SkTypeface::kItalic) {
494e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        ctFontTraits |= kCTFontItalicTrait;
495e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
496e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
497e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Create the font info
498ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    AutoCFRelease<CFStringRef> cfFontName(make_CFString(familyName));
499e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
500e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CFNumberRef> cfFontTraits(
501e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits));
502e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
503e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CFMutableDictionaryRef> cfAttributes(
504e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
505e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                      &kCFTypeDictionaryKeyCallBacks,
506e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                      &kCFTypeDictionaryValueCallBacks));
507e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
508e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CFMutableDictionaryRef> cfTraits(
509e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
510e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                      &kCFTypeDictionaryKeyCallBacks,
511e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                      &kCFTypeDictionaryValueCallBacks));
512e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
513e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Create the font
514e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) {
515e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits);
516e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
517e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName);
518e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits);
519e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
520e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        AutoCFRelease<CTFontDescriptorRef> ctFontDesc(
521e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                CTFontDescriptorCreateWithAttributes(cfAttributes));
522e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
523e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        if (ctFontDesc != NULL) {
524039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com            ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL);
525e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
526e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
527e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
528e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return ctFont ? NewFromFontRef(ctFont, familyName) : NULL;
529e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
530e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
531e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic SkTypeface* GetDefaultFace() {
532e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SK_DECLARE_STATIC_MUTEX(gMutex);
533e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkAutoMutexAcquire ma(gMutex);
534e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
535e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    static SkTypeface* gDefaultFace;
536e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
537e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (NULL == gDefaultFace) {
538e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        gDefaultFace = NewFromName(FONT_DEFAULT_NAME, SkTypeface::kNormal);
539e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkTypefaceCache::Add(gDefaultFace, SkTypeface::kNormal);
540e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
541e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return gDefaultFace;
542e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
543e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
544e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
545e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
546e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgextern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face);
547e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgCTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) {
548e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const SkTypeface_Mac* macface = (const SkTypeface_Mac*)face;
549e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return macface ? macface->fFontRef.get() : NULL;
550e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
551e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
552e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org/*  This function is visible on the outside. It first searches the cache, and if
553e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org *  not found, returns a new entry (after adding it to the cache).
554e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org */
555e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgSkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) {
556e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
557e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkTypeface* face = SkTypefaceCache::FindByID(fontID);
558e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (face) {
559e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        face->ref();
560e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    } else {
561e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        face = NewFromFontRef(fontRef, NULL);
562e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkTypefaceCache::Add(face, face->style());
563e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // NewFromFontRef doesn't retain the parameter, but the typeface it
564e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // creates does release it in its destructor, so we balance that with
565e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // a retain call here.
566e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CFRetain(fontRef);
567e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
568e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkASSERT(face->getRefCnt() > 1);
569e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return face;
570e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
571e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
572e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstruct NameStyleRec {
573e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const char*         fName;
574e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkTypeface::Style   fStyle;
575e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org};
576e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
577e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style,
578e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                            void* ctx) {
579e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
580e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx);
581e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
582e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return rec->fStyle == style && mface->fName.equals(rec->fName);
583e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
584e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
585e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic const char* map_css_names(const char* name) {
586e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    static const struct {
587e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        const char* fFrom;  // name the caller specified
588e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        const char* fTo;    // "canonical" name we map to
589e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    } gPairs[] = {
590e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        { "sans-serif", "Helvetica" },
591e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        { "serif",      "Times"     },
592e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        { "monospace",  "Courier"   }
593e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    };
594e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
595e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
596e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        if (strcmp(name, gPairs[i].fFrom) == 0) {
597e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            return gPairs[i].fTo;
598e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
599e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
600e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return name;    // no change
601e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
602e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
603836008c1588a111f090a606726822d62d3026e00reed@google.comstatic SkTypeface* create_typeface(const SkTypeface* familyFace,
604836008c1588a111f090a606726822d62d3026e00reed@google.com                                   const char familyName[],
605836008c1588a111f090a606726822d62d3026e00reed@google.com                                   SkTypeface::Style style) {
606e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (familyName) {
607e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        familyName = map_css_names(familyName);
608e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
609ff58f8b49a03197747998f4069e0980d9f6d34c0skia.committer@gmail.com
610e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Clone an existing typeface
611e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // TODO: only clone if style matches the familyFace's style...
612e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (familyName == NULL && familyFace != NULL) {
613e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        familyFace->ref();
614e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return const_cast<SkTypeface*>(familyFace);
615e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
616ff58f8b49a03197747998f4069e0980d9f6d34c0skia.committer@gmail.com
617e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!familyName || !*familyName) {
618e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        familyName = FONT_DEFAULT_NAME;
619e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
620ff58f8b49a03197747998f4069e0980d9f6d34c0skia.committer@gmail.com
621e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    NameStyleRec rec = { familyName, style };
622e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByNameStyle, &rec);
623ff58f8b49a03197747998f4069e0980d9f6d34c0skia.committer@gmail.com
624e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (NULL == face) {
625e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        face = NewFromName(familyName, style);
626e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        if (face) {
627e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            SkTypefaceCache::Add(face, style);
628e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        } else {
629e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            face = GetDefaultFace();
630e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            face->ref();
631e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
632e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
633e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return face;
634e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
635e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
636836008c1588a111f090a606726822d62d3026e00reed@google.comSkTypeface* SkTypeface_Mac::onRefMatchingStyle(Style styleBits) const {
637836008c1588a111f090a606726822d62d3026e00reed@google.com    return create_typeface(this, NULL, styleBits);
638836008c1588a111f090a606726822d62d3026e00reed@google.com}
639836008c1588a111f090a606726822d62d3026e00reed@google.com
640e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
641e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
642039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com/** GlyphRect is in FUnits (em space, y up). */
643e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstruct GlyphRect {
644e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    int16_t fMinX;
645e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    int16_t fMinY;
646e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    int16_t fMaxX;
647e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    int16_t fMaxY;
648e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org};
649e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
650e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgclass SkScalerContext_Mac : public SkScalerContext {
651e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgpublic:
6528e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com    SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*);
653e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
654e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgprotected:
655e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    unsigned generateGlyphCount(void) SK_OVERRIDE;
656e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
657e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
658e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
659e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
660e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
661e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE;
662e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
663e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgprivate:
664e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    static void CTPathElement(void *info, const CGPathElement *element);
665a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
666039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */
667039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const;
668039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com
669039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    /** Initializes and returns the value of fFBoundingBoxesGlyphOffset.
670039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *
671039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  For use with (and must be called before) generateBBoxes.
672039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     */
673039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    uint16_t getFBoundingBoxesGlyphOffset();
674a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
675039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    /** Initializes fFBoundingBoxes and returns true on success.
676039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *
677039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
678039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  return a bad value in bounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
679039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
680039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  font directly.
681039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *
682039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  This routine initializes fFBoundingBoxes to an array of
683039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  fGlyphCount - fFBoundingBoxesGlyphOffset GlyphRects which contain the bounds in FUnits
684039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  (em space, y up) of glyphs with ids in the range [fFBoundingBoxesGlyphOffset, fGlyphCount).
685039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *
686039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  Returns true if fFBoundingBoxes is properly initialized. The table can only be properly
687039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  initialized for a TrueType font with 'head', 'loca', and 'glyf' tables.
688039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *
689039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  TODO: A future optimization will compute fFBoundingBoxes once per fCTFont.
690039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     */
691e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    bool generateBBoxes();
692e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
693039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down).
694039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *
695039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs.
696039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  Used on Lion to correct CTFontGetBoundingRectsForGlyphs.
697039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     */
698039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    SkMatrix fFUnitMatrix;
699a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
700e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    Offscreen fOffscreen;
701e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CTFontRef> fCTFont;
702a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
703039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    /** Vertical variant of fCTFont.
704039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *
705039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise.
706039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  This makes kCTFontDefaultOrientation dangerous, because the metrics from
707039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  kCTFontHorizontalOrientation are in a different space from kCTFontVerticalOrientation.
708039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     *  Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in the same space.
709039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com     */
710039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    AutoCFRelease<CTFontRef> fCTVerticalFont;
711a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
712e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CGFontRef> fCGFont;
713039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    SkAutoTMalloc<GlyphRect> fFBoundingBoxes;
714e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint16_t fFBoundingBoxesGlyphOffset;
715e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint16_t fGlyphCount;
716e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    bool fGeneratedFBoundingBoxes;
717039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    const bool fDoSubPosition;
718039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    const bool fVertical;
719039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com
720e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    friend class Offscreen;
7218e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com
7228e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com    typedef SkScalerContext INHERITED;
723e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org};
724e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
7258e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.comSkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface,
7268e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com                                         const SkDescriptor* desc)
7278e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com        : INHERITED(typeface, desc)
728039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        , fFBoundingBoxes()
729e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        , fFBoundingBoxesGlyphOffset(0)
730e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        , fGeneratedFBoundingBoxes(false)
731039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
732039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        , fVertical(SkToBool(fRec.fFlags & kVertical_Flag))
733039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com
734e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org{
7353dca9a6576d2baaf6132bbe736e8597723cbc5acreed@google.com    CTFontRef ctFont = typeface->fFontRef.get();
736e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
737039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
738039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    fGlyphCount = SkToU16(numGlyphs);
739a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
740039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    fRec.getSingleMatrix(&fFUnitMatrix);
741039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix);
742039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com
743e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CTFontDescriptorRef> ctFontDesc;
744e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (fVertical) {
745e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMutable(
746e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                kCFAllocatorDefault, 0,
747e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                &kCFTypeDictionaryKeyCallBacks,
748e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                &kCFTypeDictionaryValueCallBacks));
749e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        if (cfAttributes) {
750e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
751e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate(
752e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                    kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation));
753e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVertical);
754e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
755e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
756e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
757039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // Since our matrix includes everything, we pass 1 for size.
758039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, ctFontDesc);
759e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL);
760e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (fVertical) {
761e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
762e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        transform = CGAffineTransformConcat(rotateLeft, transform);
763039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, NULL);
764e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
765ebcf3fdc3ebc30b2a3cd73347b996a7a6da19cd3commit-bot@chromium.org
766039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFont)));
767039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit);
768e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
769e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
770e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgCGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
771e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                             CGGlyph glyphID, size_t* rowBytesPtr,
772e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                             bool generateA8FromLCD) {
773e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!fRGBSpace) {
774e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        //It doesn't appear to matter what color space is specified.
775e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        //Regular blends and antialiased text are always (s*a + d*(1-a))
776e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        //and smoothed text is always g=2.0.
777e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        fRGBSpace = CGColorSpaceCreateDeviceRGB();
778e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
779e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
780e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // default to kBW_Format
781e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    bool doAA = false;
782e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    bool doLCD = false;
783e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
784e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (SkMask::kBW_Format != glyph.fMaskFormat) {
785e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        doLCD = true;
786e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        doAA = true;
787e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
788e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
789e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // FIXME: lcd smoothed un-hinted rasterization unsupported.
790e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) {
791e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        doLCD = false;
792e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        doAA = true;
793e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
794e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
795e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
796e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
797e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        if (fSize.fWidth < glyph.fWidth) {
798e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            fSize.fWidth = RoundSize(glyph.fWidth);
799e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
800e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        if (fSize.fHeight < glyph.fHeight) {
801e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            fSize.fHeight = RoundSize(glyph.fHeight);
802e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
803e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
804e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
805e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
806e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
807e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                    rowBytes, fRGBSpace, BITMAP_INFO_RGB);
808e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
809e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // skia handles quantization itself, so we disable this for cg to get
810e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // full fractional data from them.
811e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGContextSetAllowsFontSubpixelQuantization(fCG, false);
812e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
813e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
814e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGContextSetTextDrawingMode(fCG, kCGTextFill);
815e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGContextSetFont(fCG, context.fCGFont);
816039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        CGContextSetFontSize(fCG, 1 /*CTFontGetSize(context.fCTFont)*/);
817039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont));
818e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
819039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // Because CG always draws from the horizontal baseline,
820039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // if there is a non-integral translation from the horizontal origin to the vertical origin,
821039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // then CG cannot draw the glyph in the correct location without subpixel positioning.
822039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical);
823039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || context.fVertical);
824e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
825e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // Draw white on black to create mask.
826e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // TODO: Draw black on white and invert, CG has a special case codepath.
827e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGContextSetGrayFillColor(fCG, 1.0f, 1.0f);
828e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
829e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // force our checks below to happen
830e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        fDoAA = !doAA;
831e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        fDoLCD = !doLCD;
832e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
833e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
834e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (fDoAA != doAA) {
835e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGContextSetShouldAntialias(fCG, doAA);
836e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        fDoAA = doAA;
837e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
838e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (fDoLCD != doLCD) {
839e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGContextSetShouldSmoothFonts(fCG, doLCD);
840e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        fDoLCD = doLCD;
841e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
842e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
843e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
844e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // skip rows based on the glyph's height
845e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
846e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
847e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // erase to black
848e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes);
849e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
850e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    float subX = 0;
851e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    float subY = 0;
852e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (context.fDoSubPosition) {
853e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        subX = SkFixedToFloat(glyph.getSubXFixed());
854e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        subY = SkFixedToFloat(glyph.getSubYFixed());
855e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
856a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
857039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // CGContextShowGlyphsAtPoint always draws using the horizontal baseline origin.
858e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (context.fVertical) {
859039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        SkPoint offset;
860e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        context.getVerticalOffset(glyphID, &offset);
861e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        subX += offset.fX;
862e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        subY += offset.fY;
863e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
864a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
865e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX,
866e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                               glyph.fTop + glyph.fHeight - subY,
867e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                               &glyphID, 1);
868e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
869e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkASSERT(rowBytesPtr);
870e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    *rowBytesPtr = rowBytes;
871e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return image;
872e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
873e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
874039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.comvoid SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const {
875039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up).
876039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // Lion and Leopard return cgVertOffset in CG units (pixels, y up).
877039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    CGSize cgVertOffset;
878039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1);
879039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com
880039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) };
881039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    if (isSnowLeopard()) {
882039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
883039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        fFUnitMatrix.mapPoints(&skVertOffset, 1);
884039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    } else {
885039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // From CG units (pixels, y up) to SkGlyph units (pixels, y down).
886039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        skVertOffset.fY = -skVertOffset.fY;
887039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    }
888a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
889039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    *offset = skVertOffset;
890039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com}
891e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
892e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orguint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() {
893e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (fFBoundingBoxesGlyphOffset) {
894e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return fFBoundingBoxesGlyphOffset;
895e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
896e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts
897e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont);
898e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (hheaTable.fData) {
899e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetrics);
900e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
901e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return fFBoundingBoxesGlyphOffset;
902e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
903e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
904e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgbool SkScalerContext_Mac::generateBBoxes() {
905e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (fGeneratedFBoundingBoxes) {
906039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        return NULL != fFBoundingBoxes.get();
907e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
908e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    fGeneratedFBoundingBoxes = true;
909e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
910e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCGTable<SkOTTableHead> headTable(fCGFont);
911e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!headTable.fData) {
912e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return false;
913e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
914e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
915e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCGTable<SkOTTableIndexToLocation> locaTable(fCGFont);
916e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!locaTable.fData) {
917e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return false;
918e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
919e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
920e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont);
921e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!glyfTable.fData) {
922e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return false;
923e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
924e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
925e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset;
926039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    fFBoundingBoxes.reset(entries);
927e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
928e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat;
929e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, locaFormat);
930e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    glyphDataIter.advance(fFBoundingBoxesGlyphOffset);
931e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundingBoxesIndex) {
932e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        const SkOTTableGlyphData* glyphData = glyphDataIter.next();
933e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex];
934e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        rect.fMinX = SkEndian_SwapBE16(glyphData->xMin);
935e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        rect.fMinY = SkEndian_SwapBE16(glyphData->yMin);
936e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax);
937e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax);
938e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
939ebcf3fdc3ebc30b2a3cd73347b996a7a6da19cd3commit-bot@chromium.org
940e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return true;
941e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
942e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
943e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgunsigned SkScalerContext_Mac::generateGlyphCount(void) {
944e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return fGlyphCount;
945e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
946e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
947e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orguint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) {
948e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGGlyph     cgGlyph;
949e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    UniChar     theChar;
950e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
951e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Validate our parameters and state
952e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkASSERT(uni <= 0x0000FFFF);
953e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t));
954e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
955e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Get the glyph
956e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    theChar = (UniChar) uni;
957e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
958e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!CTFontGetGlyphsForCharacters(fCTFont, &theChar, &cgGlyph, 1)) {
959e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        cgGlyph = 0;
960e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
961e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
962e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return cgGlyph;
963e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
964e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
965e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgvoid SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
966e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    this->generateMetrics(glyph);
967e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
968e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
969039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.comvoid SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
970039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount);
971039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    glyph->zeroMetrics();
972a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
973039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // The following block produces cgAdvance in CG units (pixels, y up).
974039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    CGSize cgAdvance;
975039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    if (fVertical) {
976039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation,
977039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com                                   &cgGlyph, &cgAdvance, 1);
978039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    } else {
979039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation,
980039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com                                   &cgGlyph, &cgAdvance, 1);
981039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    }
982039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    glyph->fAdvanceX =  SkFloatToFixed_Check(cgAdvance.width);
983039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    glyph->fAdvanceY = -SkFloatToFixed_Check(cgAdvance.height);
984039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com
985039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // The following produces skBounds in SkGlyph units (pixels, y down),
986039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // or returns early if skBounds would be empty.
987039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    SkRect skBounds;
988a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
989039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // On Mountain Lion, CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation and
990039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // CTFontGetVerticalTranslationsForGlyphs do not agree when using OTF CFF fonts.
991039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // For TTF fonts these two do agree and we can use CTFontGetBoundingRectsForGlyphs to get
992039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // the bounding box and CTFontGetVerticalTranslationsForGlyphs to then draw the glyph
993039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // inside that bounding box. However, with OTF CFF fonts this does not work. It appears that
994039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation on OTF CFF fonts tries
995039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // to center the glyph along the vertical baseline and also perform some mysterious shift
996039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // along the baseline. CTFontGetVerticalTranslationsForGlyphs does not appear to perform
997039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // these steps.
998039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    //
999039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // It is not known which is correct (or if either is correct). However, we must always draw
1000039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // from the horizontal origin and must use CTFontGetVerticalTranslationsForGlyphs to draw.
1001039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // As a result, we do not call CTFontGetBoundingRectsForGlyphs for vertical glyphs.
1002a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
1003039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // On Snow Leopard, CTFontGetBoundingRectsForGlyphs ignores kCTFontVerticalOrientation and
1004039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // returns horizontal bounds.
1005a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
1006039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to
1007039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // return a bad value in cgBounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is
1008039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // less than its maxp::numGlyphs. When this is the case we try to read the bounds from the
1009039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // font directly.
1010039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    if ((isLion() || isMountainLion()) &&
1011039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && generateBBoxes()))
1012039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    {
1013039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphOffset];
1014039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        if (gRect.fMinX >= gRect.fMaxX || gRect.fMinY >= gRect.fMaxY) {
1015039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com            return;
1016039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        }
1017039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        skBounds = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY);
1018039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // From FUnits (em space, y up) to SkGlyph units (pixels, y down).
1019039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        fFUnitMatrix.mapRect(&skBounds);
1020039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com
1021039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    } else {
1022039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up).
1023039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        CGRect cgBounds;
1024039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation,
1025039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com                                        &cgGlyph, &cgBounds, 1);
1026a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
1027039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // BUG?
1028039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when
1029039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // it should be empty. So, if we see a zero-advance, we check if it has an
1030039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance
1031039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // is rare, so we won't incur a big performance cost for this extra check.
1032039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        if (0 == cgAdvance.width && 0 == cgAdvance.height) {
1033039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com            AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL));
1034039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com            if (NULL == path || CGPathIsEmpty(path)) {
1035039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com                return;
1036039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com            }
1037039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        }
1038039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com
1039039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        if (CGRectIsEmpty_inline(cgBounds)) {
1040039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com            return;
1041039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        }
1042039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com
1043039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // Convert cgBounds to SkGlyph units (pixels, y down).
1044039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height,
1045039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com                                    cgBounds.size.width, cgBounds.size.height);
1046039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    }
1047039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com
1048039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    if (fVertical) {
1049039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // Due to all of the vertical bounds bugs, skBounds is always the horizontal bounds.
1050039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        // Convert these horizontal bounds into vertical bounds.
1051039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        SkPoint offset;
1052039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        getVerticalOffset(cgGlyph, &offset);
1053039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        skBounds.offset(offset);
1054039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    }
1055a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
1056039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // Currently the bounds are based on being rendered at (0,0).
1057039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // The top left must not move, since that is the base from which subpixel positioning is offset.
1058039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    if (fDoSubPosition) {
1059039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed());
1060039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed());
1061039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    }
1062a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
1063039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    SkIRect skIBounds;
1064039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    skBounds.roundOut(&skIBounds);
1065039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
1066039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
1067039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // is not currently known, as CG dilates the outlines by some percentage.
1068039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    // Note that if this context is A8 and not back-forming from LCD, there is no need to outset.
1069039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    skIBounds.outset(1, 1);
1070039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    glyph->fLeft = SkToS16(skIBounds.fLeft);
1071039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    glyph->fTop = SkToS16(skIBounds.fTop);
1072039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    glyph->fWidth = SkToU16(skIBounds.width());
1073039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    glyph->fHeight = SkToU16(skIBounds.height());
1074a35ae01b7f409c673e990ea3b6a19a55080a1dcbskia.committer@gmail.com
1075039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com#ifdef HACK_COLORGLYPHS
1076039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    glyph->fMaskFormat = SkMask::kARGB32_Format;
1077039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com#endif
1078039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com}
1079e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1080e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#include "SkColorPriv.h"
1081e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1082e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic void build_power_table(uint8_t table[], float ee) {
1083e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    for (int i = 0; i < 256; i++) {
1084e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        float x = i / 255.f;
1085e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        x = sk_float_pow(x, ee);
1086e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        int xx = SkScalarRoundToInt(SkFloatToScalar(x * 255));
1087e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        table[i] = SkToU8(xx);
1088e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1089e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1090e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1091e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org/**
1092e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org *  This will invert the gamma applied by CoreGraphics, so we can get linear
1093e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org *  values.
1094e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org *
1095e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org *  CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value.
1096e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org *  The color space used does not appear to affect this choice.
1097e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org */
1098e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic const uint8_t* getInverseGammaTableCoreGraphicSmoothing() {
1099e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    static bool gInited;
1100e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    static uint8_t gTableCoreGraphicsSmoothing[256];
1101e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!gInited) {
1102e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        build_power_table(gTableCoreGraphicsSmoothing, 2.0f);
1103e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        gInited = true;
1104e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1105e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return gTableCoreGraphicsSmoothing;
1106e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1107e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1108e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
1109e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    while (count > 0) {
1110e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        uint8_t mask = 0;
1111e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        for (int i = 7; i >= 0; --i) {
1112e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            mask |= (CGRGBPixel_getAlpha(*src++) >> 7) << i;
1113e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            if (0 == --count) {
1114e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                break;
1115e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            }
1116e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1117e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        *dst++ = mask;
1118e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1119e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1120e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1121e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1122e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) {
1123e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    U8CPU r = (rgb >> 16) & 0xFF;
1124e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    U8CPU g = (rgb >>  8) & 0xFF;
1125e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    U8CPU b = (rgb >>  0) & 0xFF;
1126e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1127e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1128e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1129e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes,
1130e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                      const SkGlyph& glyph, const uint8_t* table8) {
1131e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const int width = glyph.fWidth;
1132e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    size_t dstRB = glyph.rowBytes();
1133e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
1134e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1135e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    for (int y = 0; y < glyph.fHeight; y++) {
1136e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        for (int i = 0; i < width; ++i) {
1137e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8);
1138e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1139e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1140e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        dst += dstRB;
1141e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1142e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1143e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1144e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1145e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic inline uint16_t rgb_to_lcd16(CGRGBPixel rgb, const uint8_t* tableR,
1146e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                                    const uint8_t* tableG,
1147e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                                    const uint8_t* tableB) {
1148e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1149e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
1150e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
1151e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return SkPack888ToRGB16(r, g, b);
1152e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1153e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1154e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
1155e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1156e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const int width = glyph.fWidth;
1157e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    size_t dstRB = glyph.rowBytes();
1158e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage;
1159e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1160e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    for (int y = 0; y < glyph.fHeight; y++) {
1161e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        for (int i = 0; i < width; i++) {
1162e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
1163e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1164e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1165e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        dst = (uint16_t*)((char*)dst + dstRB);
1166e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1167e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1168e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1169e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1170e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic inline uint32_t rgb_to_lcd32(CGRGBPixel rgb, const uint8_t* tableR,
1171e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                                    const uint8_t* tableG,
1172e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                                    const uint8_t* tableB) {
1173e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1174e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
1175e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
1176e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return SkPackARGB32(0xFF, r, g, b);
1177e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1178e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtemplate<bool APPLY_PREBLEND>
1179e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic void rgb_to_lcd32(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
1180e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1181e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const int width = glyph.fWidth;
1182e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    size_t dstRB = glyph.rowBytes();
1183e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint32_t* SK_RESTRICT dst = (uint32_t*)glyph.fImage;
1184e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    for (int y = 0; y < glyph.fHeight; y++) {
1185e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        for (int i = 0; i < width; i++) {
1186e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
1187e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1188e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1189e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        dst = (uint32_t*)((char*)dst + dstRB);
1190e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1191e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1192e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
11931ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com#ifdef HACK_COLORGLYPHS
11941ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com// hack to colorize the output for testing kARGB32_Format
11951ac3facef9444119e9d389e6b7b082c3120f0791reed@google.comstatic SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb, const SkGlyph& glyph,
11961ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com                                     int x, int y) {
11971ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com    U8CPU r = (rgb >> 16) & 0xFF;
11981ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com    U8CPU g = (rgb >>  8) & 0xFF;
11991ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com    U8CPU b = (rgb >>  0) & 0xFF;
12001ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com    unsigned a = SkComputeLuminance(r, g, b);
120174546d80ff050eecbf2d3a21194f10860504e68dskia.committer@gmail.com
12021ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com    // compute gradient from x,y
12031ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com    r = x * 255 / glyph.fWidth;
12041ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com    g = 0;
12051ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com    b = (glyph.fHeight - y) * 255 / glyph.fHeight;
12061ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com    return SkPreMultiplyARGB(a, r, g, b);    // red
12071ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com}
12081ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com#endif
12091ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com
1210e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgtemplate <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
1211e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return (T*)((char*)ptr + byteOffset);
1212e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1213e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1214e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgvoid SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
1215e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
1216e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1217e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // FIXME: lcd smoothed un-hinted rasterization unsupported.
1218e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting;
1219e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1220e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Draw the glyph
1221e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    size_t cgRowBytes;
1222e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, generateA8FromLCD);
1223e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (cgPixels == NULL) {
1224e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return;
1225e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1226e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1227e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    //TODO: see if drawing black on white and inverting is faster (at least in
1228e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    //lcd case) as core graphics appears to have special case code for drawing
1229e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    //black text.
1230e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1231e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Fix the glyph
1232e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const bool isLCD = isLCDFormat(glyph.fMaskFormat);
1233e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (isLCD || (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD)) {
1234e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        const uint8_t* table = getInverseGammaTableCoreGraphicSmoothing();
1235e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1236e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        //Note that the following cannot really be integrated into the
1237e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        //pre-blend, since we may not be applying the pre-blend; when we aren't
1238e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        //applying the pre-blend it means that a filter wants linear anyway.
1239e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        //Other code may also be applying the pre-blend, so we'd need another
1240e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        //one with this and one without.
1241e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGRGBPixel* addr = cgPixels;
1242e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        for (int y = 0; y < glyph.fHeight; ++y) {
1243e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            for (int x = 0; x < glyph.fWidth; ++x) {
1244e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                int r = (addr[x] >> 16) & 0xFF;
1245e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                int g = (addr[x] >>  8) & 0xFF;
1246e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                int b = (addr[x] >>  0) & 0xFF;
1247e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1248e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            }
1249e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            addr = SkTAddByteOffset(addr, cgRowBytes);
1250e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1251e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1252e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1253e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Convert glyph to mask
1254e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    switch (glyph.fMaskFormat) {
1255e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case SkMask::kLCD32_Format: {
1256e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            if (fPreBlend.isApplicable()) {
1257e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                rgb_to_lcd32<true>(cgPixels, cgRowBytes, glyph,
1258e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                   fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1259e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            } else {
1260e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                rgb_to_lcd32<false>(cgPixels, cgRowBytes, glyph,
1261e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                    fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1262e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            }
1263e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        } break;
1264e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case SkMask::kLCD16_Format: {
1265e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            if (fPreBlend.isApplicable()) {
1266e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph,
1267e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                   fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1268e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            } else {
1269e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph,
1270e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                    fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1271e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            }
1272e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        } break;
1273e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case SkMask::kA8_Format: {
1274e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            if (fPreBlend.isApplicable()) {
1275e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1276e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            } else {
1277e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1278e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            }
1279e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        } break;
1280e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case SkMask::kBW_Format: {
1281e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            const int width = glyph.fWidth;
1282e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            size_t dstRB = glyph.rowBytes();
1283e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            uint8_t* dst = (uint8_t*)glyph.fImage;
1284e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            for (int y = 0; y < glyph.fHeight; y++) {
1285e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                cgpixels_to_bits(dst, cgPixels, width);
1286e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
1287e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                dst += dstRB;
1288e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            }
1289e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        } break;
12901ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com#ifdef HACK_COLORGLYPHS
12911ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com        case SkMask::kARGB32_Format: {
12921ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com            const int width = glyph.fWidth;
12931ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com            size_t dstRB = glyph.rowBytes();
12941ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com            SkPMColor* dst = (SkPMColor*)glyph.fImage;
12951ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com            for (int y = 0; y < glyph.fHeight; y++) {
12961ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com                for (int x = 0; x < width; ++x) {
12971ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com                    dst[x] = cgpixels_to_pmcolor(cgPixels[x], glyph, x, y);
12981ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com                }
12991ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com                cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
13001ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com                dst = (SkPMColor*)((char*)dst + dstRB);
13011ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com            }
13021ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com        } break;
13031ac3facef9444119e9d389e6b7b082c3120f0791reed@google.com#endif
1304e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        default:
1305e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            SkDEBUGFAIL("unexpected mask format");
1306e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            break;
1307e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1308e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1309e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1310e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org/*
1311e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org *  Our subpixel resolution is only 2 bits in each direction, so a scale of 4
1312e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org *  seems sufficient, and possibly even correct, to allow the hinted outline
1313e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org *  to be subpixel positioned.
1314e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org */
1315e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#define kScaleForSubPixelPositionHinting (4.0f)
1316e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1317e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgvoid SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) {
1318e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CTFontRef font = fCTFont;
1319e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkScalar scaleX = SK_Scalar1;
1320e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkScalar scaleY = SK_Scalar1;
1321e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1322e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    /*
1323e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org     *  For subpixel positioning, we want to return an unhinted outline, so it
1324e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org     *  can be positioned nicely at fractional offsets. However, we special-case
1325e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org     *  if the baseline of the (horizontal) text is axis-aligned. In those cases
1326e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org     *  we want to retain hinting in the direction orthogonal to the baseline.
1327e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org     *  e.g. for horizontal baseline, we want to retain hinting in Y.
1328e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org     *  The way we remove hinting is to scale the font by some value (4) in that
1329e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org     *  direction, ask for the path, and then scale the path back down.
1330e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org     */
1331e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
1332e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkMatrix m;
1333e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        fRec.getSingleMatrix(&m);
1334e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1335e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // start out by assuming that we want no hining in X and Y
1336e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        scaleX = scaleY = SkFloatToScalar(kScaleForSubPixelPositionHinting);
1337e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // now see if we need to restore hinting for axis-aligned baselines
1338e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        switch (SkComputeAxisAlignmentForHText(m)) {
1339e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            case kX_SkAxisAlignment:
1340e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                scaleY = SK_Scalar1; // want hinting in the Y direction
1341e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                break;
1342e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            case kY_SkAxisAlignment:
1343e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                scaleX = SK_Scalar1; // want hinting in the X direction
1344e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                break;
1345e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            default:
1346e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                break;
1347e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1348e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1349e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGAffineTransform xform = MatrixToCGAffineTransform(m, scaleX, scaleY);
1350e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // need to release font when we're done
1351e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        font = CTFontCreateCopyWithAttributes(fCTFont, 1, &xform, NULL);
1352e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1353e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1354e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount);
1355e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL));
1356e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1357e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    path->reset();
1358e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (cgPath != NULL) {
1359e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement);
1360e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1361e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1362039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    if (fDoSubPosition) {
1363e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkMatrix m;
1364e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY));
1365e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        path->transform(m);
1366e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // balance the call to CTFontCreateCopyWithAttributes
1367e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CFSafeRelease(font);
1368e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1369039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com    if (fVertical) {
1370039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        SkPoint offset;
1371039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        getVerticalOffset(cgGlyph, &offset);
1372039261bd15e9a1dfa7871703d7baac2b84a25298bungeman@google.com        path->offset(offset.fX, offset.fY);
1373e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1374e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1375e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1376e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgvoid SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
1377e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                              SkPaint::FontMetrics* my) {
1378e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGRect theBounds = CTFontGetBoundingBox(fCTFont);
1379e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1380e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkPaint::FontMetrics theMetrics;
1381e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    theMetrics.fTop          = CGToScalar(-CGRectGetMaxY_inline(theBounds));
1382e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    theMetrics.fAscent       = CGToScalar(-CTFontGetAscent(fCTFont));
1383e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    theMetrics.fDescent      = CGToScalar( CTFontGetDescent(fCTFont));
1384e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    theMetrics.fBottom       = CGToScalar(-CGRectGetMinY_inline(theBounds));
1385e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    theMetrics.fLeading      = CGToScalar( CTFontGetLeading(fCTFont));
1386e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    theMetrics.fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds));
1387e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    theMetrics.fXMin         = CGToScalar( CGRectGetMinX_inline(theBounds));
1388e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    theMetrics.fXMax         = CGToScalar( CGRectGetMaxX_inline(theBounds));
1389e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    theMetrics.fXHeight      = CGToScalar( CTFontGetXHeight(fCTFont));
1390e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1391e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (mx != NULL) {
1392e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        *mx = theMetrics;
1393e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1394e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (my != NULL) {
1395e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        *my = theMetrics;
1396e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1397e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1398e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1399e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgvoid SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) {
1400e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkPath* skPath = (SkPath*)info;
1401e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1402e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Process the path element
1403e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    switch (element->type) {
1404e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case kCGPathElementMoveToPoint:
1405e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            skPath->moveTo(element->points[0].x, -element->points[0].y);
1406e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            break;
1407e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1408e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case kCGPathElementAddLineToPoint:
1409e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            skPath->lineTo(element->points[0].x, -element->points[0].y);
1410e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            break;
1411e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1412e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case kCGPathElementAddQuadCurveToPoint:
1413e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            skPath->quadTo(element->points[0].x, -element->points[0].y,
1414e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                           element->points[1].x, -element->points[1].y);
1415e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            break;
1416e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1417e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case kCGPathElementAddCurveToPoint:
1418e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            skPath->cubicTo(element->points[0].x, -element->points[0].y,
1419e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                            element->points[1].x, -element->points[1].y,
1420e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                            element->points[2].x, -element->points[2].y);
1421e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            break;
1422e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1423e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case kCGPathElementCloseSubpath:
1424e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            skPath->close();
1425e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            break;
1426e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1427e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        default:
1428e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            SkDEBUGFAIL("Unknown path element!");
1429e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            break;
1430e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1431e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1432e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1433e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1434e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
1435e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1436e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// Returns NULL on failure
1437e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// Call must still manage its ownership of provider
1438e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic SkTypeface* create_from_dataProvider(CGDataProviderRef provider) {
1439e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider));
1440e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (NULL == cg) {
1441e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return NULL;
1442e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1443e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CTFontRef ct = CTFontCreateWithGraphicsFont(cg, 0, NULL, NULL);
1444e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return cg ? SkCreateTypefaceFromCTFont(ct) : NULL;
1445e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1446e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1447e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// Web fonts added to the the CTFont registry do not return their character set.
1448e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// Iterate through the font in this case. The existing caller caches the result,
1449e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// so the performance impact isn't too bad.
1450e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
1451e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                           SkTDArray<SkUnichar>* glyphToUnicode) {
1452e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    glyphToUnicode->setCount(glyphCount);
1453e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkUnichar* out = glyphToUnicode->begin();
1454e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    sk_bzero(out, glyphCount * sizeof(SkUnichar));
1455e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    UniChar unichar = 0;
1456e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    while (glyphCount > 0) {
1457e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CGGlyph glyph;
1458e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1459e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            out[glyph] = unichar;
1460e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            --glyphCount;
1461e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1462e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        if (++unichar == 0) {
1463e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            break;
1464e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1465e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1466e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1467e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1468e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// Construct Glyph to Unicode table.
1469e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// Unicode code points that require conjugate pairs in utf16 are not
1470e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// supported.
1471e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
1472e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                      SkTDArray<SkUnichar>* glyphToUnicode) {
1473e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
1474e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!charSet) {
1475e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
1476e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return;
1477e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1478e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1479e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CFDataRef> bitmap(CFCharacterSetCreateBitmapRepresentation(kCFAllocatorDefault,
1480e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                                                             charSet));
1481e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!bitmap) {
1482e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return;
1483e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1484e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CFIndex length = CFDataGetLength(bitmap);
1485e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!length) {
1486e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return;
1487e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1488e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (length > 8192) {
1489e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // TODO: Add support for Unicode above 0xFFFF
1490e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // Consider only the BMP portion of the Unicode character points.
1491e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // The bitmap may contain other planes, up to plane 16.
1492e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html
1493e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        length = 8192;
1494e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1495e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const UInt8* bits = CFDataGetBytePtr(bitmap);
1496e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    glyphToUnicode->setCount(glyphCount);
1497e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkUnichar* out = glyphToUnicode->begin();
1498e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    sk_bzero(out, glyphCount * sizeof(SkUnichar));
1499e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    for (int i = 0; i < length; i++) {
1500e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        int mask = bits[i];
1501e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        if (!mask) {
1502e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            continue;
1503e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1504e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        for (int j = 0; j < 8; j++) {
1505e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            CGGlyph glyph;
1506e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            UniChar unichar = static_cast<UniChar>((i << 3) + j);
1507e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1508e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                out[glyph] = unichar;
1509e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            }
1510e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1511e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1512e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1513e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1514e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic bool getWidthAdvance(CTFontRef ctFont, int gId, int16_t* data) {
1515e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGSize advance;
1516e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    advance.width = 0;
1517e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGGlyph glyph = gId;
1518e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &glyph, &advance, 1);
1519e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    *data = sk_float_round2int(advance.width);
1520e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return true;
1521e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1522e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1523e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// we might move this into our CGUtils...
1524e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic void CFStringToSkString(CFStringRef src, SkString* dst) {
1525e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Reserve enough room for the worst-case string,
1526e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // plus 1 byte for the trailing null.
1527e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src),
1528e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                                       kCFStringEncodingUTF8) + 1;
1529e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    dst->resize(length);
1530e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8);
1531e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Resize to the actual UTF-8 length used, stripping the null character.
1532e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    dst->resize(strlen(dst->c_str()));
1533e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1534e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
15353dca9a6576d2baaf6132bbe736e8597723cbc5acreed@google.comSkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics(
1536e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1537e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        const uint32_t* glyphIDs,
15383dca9a6576d2baaf6132bbe736e8597723cbc5acreed@google.com        uint32_t glyphIDsCount) const {
15393dca9a6576d2baaf6132bbe736e8597723cbc5acreed@google.com
15403dca9a6576d2baaf6132bbe736e8597723cbc5acreed@google.com    CTFontRef originalCTFont = fFontRef.get();
1541e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CTFontRef> ctFont(CTFontCreateCopyWithAttributes(
1542e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            originalCTFont, CTFontGetUnitsPerEm(originalCTFont), NULL, NULL));
1543e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
1544e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1545e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    {
1546e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        AutoCFRelease<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont));
1547e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CFStringToSkString(fontName, &info->fFontName);
1548e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1549e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1550e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    info->fMultiMaster = false;
1551e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CFIndex glyphCount = CTFontGetGlyphCount(ctFont);
1552e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    info->fLastGlyphID = SkToU16(glyphCount - 1);
1553e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    info->fEmSize = CTFontGetUnitsPerEm(ctFont);
1554e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1555e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1556e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode);
1557e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1558e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1559e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    info->fStyle = 0;
1560e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1561e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // If it's not a truetype font, mark it as 'other'. Assume that TrueType
1562e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // fonts always have both glyf and loca tables. At the least, this is what
1563e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // sfntly needs to subset the font. CTFontCopyAttribute() does not always
1564e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // succeed in determining this directly.
15653dca9a6576d2baaf6132bbe736e8597723cbc5acreed@google.com    if (!this->getTableSize('glyf') || !this->getTableSize('loca')) {
1566e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1567e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fItalicAngle = 0;
1568e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fAscent = 0;
1569e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fDescent = 0;
1570e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fStemV = 0;
1571e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fCapHeight = 0;
1572e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fBBox = SkIRect::MakeEmpty();
1573e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return info;
1574e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1575e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1576e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1577e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont);
1578e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (symbolicTraits & kCTFontMonoSpaceTrait) {
1579e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1580e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1581e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (symbolicTraits & kCTFontItalicTrait) {
1582e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1583e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1584e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
1585e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
1586e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1587e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    } else if (stylisticClass & kCTFontScriptsClass) {
1588e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1589e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1590e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont);
1591e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    info->fAscent = (int16_t) CTFontGetAscent(ctFont);
1592e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    info->fDescent = (int16_t) CTFontGetDescent(ctFont);
1593e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont);
1594e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGRect bbox = CTFontGetBoundingBox(ctFont);
1595e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1596e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkRect r;
1597e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    r.set( CGToScalar(CGRectGetMinX_inline(bbox)),   // Left
1598e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org           CGToScalar(CGRectGetMaxY_inline(bbox)),   // Top
1599e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org           CGToScalar(CGRectGetMaxX_inline(bbox)),   // Right
1600e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org           CGToScalar(CGRectGetMinY_inline(bbox)));  // Bottom
1601e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1602e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    r.roundOut(&(info->fBBox));
1603e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1604e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Figure out a good guess for StemV - Min width of i, I, !, 1.
1605e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // This probably isn't very good with an italic font.
1606e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    int16_t min_width = SHRT_MAX;
1607e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    info->fStemV = 0;
1608e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
1609e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
1610e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGGlyph glyphs[count];
1611e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CGRect boundingRects[count];
1612e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) {
1613e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation,
1614e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                        glyphs, boundingRects, count);
1615e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        for (size_t i = 0; i < count; i++) {
1616e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            int16_t width = (int16_t) boundingRects[i].size.width;
1617e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            if (width > 0 && width < min_width) {
1618e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                min_width = width;
1619e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                info->fStemV = min_width;
1620e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            }
1621e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1622e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1623e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1624e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (false) { // TODO: haven't figured out how to know if font is embeddable
1625e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        // (information is in the OS/2 table)
1626e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
1627e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1628e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1629e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            skia_advanced_typeface_metrics_utils::appendRange(&info->fGlyphWidths, 0);
1630e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            info->fGlyphWidths->fAdvance.append(1, &min_width);
1631e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            skia_advanced_typeface_metrics_utils::finishRange(info->fGlyphWidths.get(), 0,
1632e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                        SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1633e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        } else {
1634e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            info->fGlyphWidths.reset(
1635e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                skia_advanced_typeface_metrics_utils::getAdvanceData(ctFont.get(),
1636e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                               glyphCount,
1637e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                               glyphIDs,
1638e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                               glyphIDsCount,
1639e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                               &getWidthAdvance));
1640e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1641e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1642e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return info;
1643e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1644e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1645e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
1646e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1647bbad7fe187bd8c112148dd7958bb645291f642ddreed@google.comstatic SK_SFNT_ULONG get_font_type_tag(const SkTypeface_Mac* typeface) {
1648bbad7fe187bd8c112148dd7958bb645291f642ddreed@google.com    CTFontRef ctFont = typeface->fFontRef.get();
1649e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CFNumberRef> fontFormatRef(
1650e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
1651e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!fontFormatRef) {
1652e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return 0;
1653e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1654e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1655e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SInt32 fontFormatValue;
1656e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (!CFNumberGetValue(fontFormatRef, kCFNumberSInt32Type, &fontFormatValue)) {
1657e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return 0;
1658e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1659e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1660e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    switch (fontFormatValue) {
1661e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case kCTFontFormatOpenTypePostScript:
1662e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            return SkSFNTHeader::fontType_OpenTypeCFF::TAG;
1663e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case kCTFontFormatOpenTypeTrueType:
1664e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1665e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case kCTFontFormatTrueType:
1666e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            return SkSFNTHeader::fontType_MacTrueType::TAG;
1667e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case kCTFontFormatPostScript:
1668e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            return SkSFNTHeader::fontType_PostScript::TAG;
1669e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case kCTFontFormatBitmap:
1670e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            return SkSFNTHeader::fontType_MacTrueType::TAG;
1671e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        case kCTFontFormatUnrecognized:
1672e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        default:
1673e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            //CT seems to be unreliable in being able to obtain the type,
1674e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            //even if all we want is the first four bytes of the font resource.
1675e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            //Just the presence of the FontForge 'FFTM' table seems to throw it off.
1676e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1677e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1678e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1679e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1680bbad7fe187bd8c112148dd7958bb645291f642ddreed@google.comSkStream* SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
1681bbad7fe187bd8c112148dd7958bb645291f642ddreed@google.com    SK_SFNT_ULONG fontType = get_font_type_tag(this);
1682e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (0 == fontType) {
1683e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return NULL;
1684e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1685e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1686e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // get table tags
1687bbad7fe187bd8c112148dd7958bb645291f642ddreed@google.com    int numTables = this->countTables();
1688e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkTDArray<SkFontTableTag> tableTags;
1689e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    tableTags.setCount(numTables);
1690bbad7fe187bd8c112148dd7958bb645291f642ddreed@google.com    this->getTableTags(tableTags.begin());
1691e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1692e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // calc total size for font, save sizes
1693e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkTDArray<size_t> tableSizes;
1694e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1695e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1696bbad7fe187bd8c112148dd7958bb645291f642ddreed@google.com        size_t tableSize = this->getTableSize(tableTags[tableIndex]);
1697e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        totalSize += (tableSize + 3) & ~3;
1698e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        *tableSizes.append() = tableSize;
1699e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1700e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1701e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // reserve memory for stream, and zero it (tables must be zero padded)
1702e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkMemoryStream* stream = new SkMemoryStream(totalSize);
1703e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    char* dataStart = (char*)stream->getMemoryBase();
1704e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    sk_bzero(dataStart, totalSize);
1705e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    char* dataPtr = dataStart;
1706e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1707e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // compute font header entries
1708e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint16_t entrySelector = 0;
1709e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint16_t searchRange = 1;
1710e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    while (searchRange < numTables >> 1) {
1711e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        entrySelector++;
1712e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        searchRange <<= 1;
1713e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1714e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    searchRange <<= 4;
1715e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    uint16_t rangeShift = (numTables << 4) - searchRange;
1716e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1717e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // write font header
1718e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkSFNTHeader* header = (SkSFNTHeader*)dataPtr;
1719e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    header->fontType = fontType;
1720e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    header->numTables = SkEndian_SwapBE16(numTables);
1721e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    header->searchRange = SkEndian_SwapBE16(searchRange);
1722e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    header->entrySelector = SkEndian_SwapBE16(entrySelector);
1723e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    header->rangeShift = SkEndian_SwapBE16(rangeShift);
1724e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    dataPtr += sizeof(SkSFNTHeader);
1725e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1726e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // write tables
1727e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr;
1728e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1729e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1730e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        size_t tableSize = tableSizes[tableIndex];
1731bbad7fe187bd8c112148dd7958bb645291f642ddreed@google.com        this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
1732e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]);
1733e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr,
1734e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                                                         tableSize));
1735e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        entry->offset = SkEndian_SwapBE32(dataPtr - dataStart);
1736e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        entry->logicalLength = SkEndian_SwapBE32(tableSize);
1737e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1738e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        dataPtr += (tableSize + 3) & ~3;
1739e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        ++entry;
1740e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1741e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1742e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return stream;
1743e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1744e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1745e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
1746e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
1747e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1748e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgint SkTypeface_Mac::onGetUPEM() const {
1749e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef, NULL));
1750e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return CGFontGetUnitsPerEm(cgFont);
1751e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1752e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
17536e20a74d8cbcf19195559e8d98896fa22ebc535fbungeman@google.comSkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const {
1754ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com    SkTypeface::LocalizedStrings* nameIter =
1755ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com        SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
1756ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com    if (NULL == nameIter) {
1757ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com        AutoCFRelease<CFStringRef> cfLanguage;
1758ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com        AutoCFRelease<CFStringRef> cfFamilyName(
1759ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com            CTFontCopyLocalizedName(fFontRef, kCTFontFamilyNameKey, &cfLanguage));
1760ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com
1761ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com        SkString skLanguage;
1762ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com        SkString skFamilyName;
1763ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com        if (cfLanguage.get()) {
1764ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com            CFStringToSkString(cfLanguage.get(), &skLanguage);
1765ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com        } else {
1766ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com            skLanguage = "und"; //undetermined
1767ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com        }
1768ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com        if (cfFamilyName.get()) {
1769ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com            CFStringToSkString(cfFamilyName.get(), &skFamilyName);
1770ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com        }
1771ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com
1772ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com        nameIter = new SkOTUtils::LocalizedStrings_SingleName(skFamilyName, skLanguage);
1773ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com    }
1774ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com    return nameIter;
1775ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com}
1776ee8341d57355c54ea8db5fb21be75e7354069fb3bungeman@google.com
1777e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// If, as is the case with web fonts, the CTFont data isn't available,
1778e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// the CGFont data may work. While the CGFont may always provide the
1779e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// right result, leave the CTFont code path to minimize disruption.
1780e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic CFDataRef copyTableFromFont(CTFontRef ctFont, SkFontTableTag tag) {
1781e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CFDataRef data = CTFontCopyTable(ctFont, (CTFontTableTag) tag,
1782e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                     kCTFontTableOptionNoOptions);
1783e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (NULL == data) {
1784e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, NULL));
1785e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        data = CGFontCopyTableForTag(cgFont, tag);
1786e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1787e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return data;
1788e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1789e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1790e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgint SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
1791e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CFArrayRef> cfArray(CTFontCopyAvailableTables(fFontRef,
1792e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                                kCTFontTableOptionNoOptions));
1793e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (NULL == cfArray) {
1794e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return 0;
1795e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1796e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    int count = CFArrayGetCount(cfArray);
1797e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (tags) {
1798e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        for (int i = 0; i < count; ++i) {
1799e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            uintptr_t fontTag = reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(cfArray, i));
1800e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            tags[i] = static_cast<SkFontTableTag>(fontTag);
1801e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1802e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1803e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return count;
1804e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1805e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1806e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgsize_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset,
1807e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org                                      size_t length, void* dstData) const {
1808e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    AutoCFRelease<CFDataRef> srcData(copyTableFromFont(fFontRef, tag));
1809e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (NULL == srcData) {
1810e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return 0;
1811e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1812e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1813e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    size_t srcSize = CFDataGetLength(srcData);
1814e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (offset >= srcSize) {
1815e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        return 0;
1816e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1817e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (length > srcSize - offset) {
1818e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        length = srcSize - offset;
1819e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1820e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (dstData) {
1821e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        memcpy(dstData, CFDataGetBytePtr(srcData) + offset, length);
1822e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1823e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return length;
1824e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1825e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1826e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgSkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkDescriptor* desc) const {
18278e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com    return new SkScalerContext_Mac(const_cast<SkTypeface_Mac*>(this), desc);
1828e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1829e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1830e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgvoid SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
1831722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org    if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
1832722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org        rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
1833722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org    {
1834722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org        rec->fMaskFormat = SkMask::kA8_Format;
1835722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org        // Render the glyphs as close as possible to what was requested.
1836722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org        // The above turns off subpixel rendering, but the user requested it.
1837722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org        // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks.
1838722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org        // See comments below for more details.
1839722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org        rec->setHinting(SkPaint::kNormal_Hinting);
1840722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org    }
18414f43eb3b716935a2905f8071f3ca21d59aeee676skia.committer@gmail.com
1842722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org    unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag  |
1843722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org                                  SkScalerContext::kAutohinting_Flag  |
1844722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org                                  SkScalerContext::kLCD_BGROrder_Flag |
1845722656683cb3806f36b45f481fda19f73f4dca5ccommit-bot@chromium.org                                  SkScalerContext::kLCD_Vertical_Flag;
1846f35b0ddb7e95937c441c95d5d36f64a38fa83f7fskia.committer@gmail.com
1847e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    rec->fFlags &= ~flagsWeDontSupport;
1848f35b0ddb7e95937c441c95d5d36f64a38fa83f7fskia.committer@gmail.com
1849e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    bool lcdSupport = supports_LCD();
1850f35b0ddb7e95937c441c95d5d36f64a38fa83f7fskia.committer@gmail.com
1851e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Only two levels of hinting are supported.
1852e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // kNo_Hinting means avoid CoreGraphics outline dilation.
1853e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // kNormal_Hinting means CoreGraphics outline dilation is allowed.
1854e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // If there is no lcd support, hinting (dilation) cannot be supported.
1855e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkPaint::Hinting hinting = rec->getHinting();
1856e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (SkPaint::kSlight_Hinting == hinting || !lcdSupport) {
1857e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        hinting = SkPaint::kNo_Hinting;
1858e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    } else if (SkPaint::kFull_Hinting == hinting) {
1859e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        hinting = SkPaint::kNormal_Hinting;
1860e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1861e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    rec->setHinting(hinting);
1862f35b0ddb7e95937c441c95d5d36f64a38fa83f7fskia.committer@gmail.com
1863e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // FIXME: lcd smoothed un-hinted rasterization unsupported.
1864e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Tracked by http://code.google.com/p/skia/issues/detail?id=915 .
1865e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // There is no current means to honor a request for unhinted lcd,
1866e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // so arbitrarilly ignore the hinting request and honor lcd.
1867f35b0ddb7e95937c441c95d5d36f64a38fa83f7fskia.committer@gmail.com
1868e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Hinting and smoothing should be orthogonal, but currently they are not.
1869e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // CoreGraphics has no API to influence hinting. However, its lcd smoothed
1870e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // output is drawn from auto-dilated outlines (the amount of which is
1871e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // determined by AppleFontSmoothing). Its regular anti-aliased output is
1872e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // drawn from un-dilated outlines.
1873f35b0ddb7e95937c441c95d5d36f64a38fa83f7fskia.committer@gmail.com
1874e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // The behavior of Skia is as follows:
1875e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // [AA][no-hint]: generate AA using CoreGraphic's AA output.
1876e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single
1877e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // channel. This matches [LCD][yes-hint] in weight.
1878e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // [LCD][no-hint]: curently unable to honor, and must pick which to respect.
1879e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Currenly side with LCD, effectively ignoring the hinting setting.
1880e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output.
1881f35b0ddb7e95937c441c95d5d36f64a38fa83f7fskia.committer@gmail.com
1882e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (isLCDFormat(rec->fMaskFormat)) {
1883e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        if (lcdSupport) {
1884e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            //CoreGraphics creates 555 masks for smoothed text anyway.
1885e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            rec->fMaskFormat = SkMask::kLCD16_Format;
1886e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            rec->setHinting(SkPaint::kNormal_Hinting);
1887e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        } else {
1888e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org            rec->fMaskFormat = SkMask::kA8_Format;
1889e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        }
1890e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1891f35b0ddb7e95937c441c95d5d36f64a38fa83f7fskia.committer@gmail.com
1892e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
1893e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    // All other masks can use regular gamma.
1894e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hinting) {
1895e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org#ifndef SK_GAMMA_APPLY_TO_A8
1896e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        rec->ignorePreBlend();
1897a4bcd158e63c2c000fb01ad2bc013859546dd788reed@android.com#endif
1898e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    } else {
1899e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        //CoreGraphics dialates smoothed text as needed.
1900e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org        rec->setContrast(0);
1901e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    }
1902e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1903e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
1904e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org// we take ownership of the ref
1905e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.orgstatic const char* get_str(CFStringRef ref, SkString* str) {
1906e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CFStringToSkString(ref, str);
1907e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    CFSafeRelease(ref);
1908e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    return str->c_str();
1909e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
1910e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org
19113d8295f60b8b733ec0210b08261e968ad79bf5c6reed@google.comvoid SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc,
19123d8295f60b8b733ec0210b08261e968ad79bf5c6reed@google.com                                         bool* isLocalStream) const {
1913e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    SkString tmpStr;
1914f35b0ddb7e95937c441c95d5d36f64a38fa83f7fskia.committer@gmail.com
1915e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef), &tmpStr));
1916e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    desc->setFullName(get_str(CTFontCopyFullName(fFontRef), &tmpStr));
1917e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org    desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef), &tmpStr));
19183d8295f60b8b733ec0210b08261e968ad79bf5c6reed@google.com    // TODO: need to add support for local-streams (here and openStream)
19193d8295f60b8b733ec0210b08261e968ad79bf5c6reed@google.com    *isLocalStream = false;
1920e7705126b25c9078339b2de7e0a78ded6b39cd75mike@reedtribe.org}
19213d8295f60b8b733ec0210b08261e968ad79bf5c6reed@google.com
192248c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.comint SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding,
192348c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com                                    uint16_t glyphs[], int glyphCount) const {
192448c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    // UniChar is utf16
192548c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    SkAutoSTMalloc<1024, UniChar> charStorage;
192648c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    const UniChar* src;
192748c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    switch (encoding) {
192848c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com        case kUTF8_Encoding: {
192948c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            const char* u8 = (const char*)chars;
193048c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            const UniChar* u16 = src = charStorage.reset(2 * glyphCount);
193148c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            for (int i = 0; i < glyphCount; ++i) {
193248c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com                SkUnichar uni = SkUTF8_NextUnichar(&u8);
193348c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com                int n = SkUTF16_FromUnichar(uni, (uint16_t*)u16);
193448c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com                u16 += n;
193548c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            }
193648c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            break;
193748c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com        }
193848c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com        case kUTF16_Encoding:
193948c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            src = (const UniChar*)chars;
194048c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            break;
194148c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com        case kUTF32_Encoding: {
194248c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            const SkUnichar* u32 = (const SkUnichar*)chars;
194348c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            const UniChar* u16 = src = charStorage.reset(2 * glyphCount);
194448c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            for (int i = 0; i < glyphCount; ++i) {
194548c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com                int n = SkUTF16_FromUnichar(u32[i], (uint16_t*)u16);
194648c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com                u16 += n;
194748c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            }
194848c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            break;
194948c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com        }
195048c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    }
195148c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com
195248c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    // Our caller may not want glyphs for output, but we need to give that
195348c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    // storage to CT, so we can walk it looking for the first non-zero.
195448c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    SkAutoSTMalloc<1024, uint16_t> glyphStorage;
195548c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    uint16_t* macGlyphs = glyphs;
195648c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    if (NULL == macGlyphs) {
195748c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com        macGlyphs = glyphStorage.reset(glyphCount);
195848c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    }
195948c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com
196048c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    if (CTFontGetGlyphsForCharacters(fFontRef, src, macGlyphs, glyphCount)) {
196148c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com        return glyphCount;
196248c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    }
196348c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    // If we got false, then we need to manually look for first failure
196448c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    for (int i = 0; i < glyphCount; ++i) {
196548c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com        if (0 == macGlyphs[i]) {
196648c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com            return i;
196748c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com        }
196848c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    }
196948c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    // odd to get here, as we expected CT to have returned true up front.
197048c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    return glyphCount;
197148c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com}
197248c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com
197348c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.comint SkTypeface_Mac::onCountGlyphs() const {
197448c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com    return CTFontGetGlyphCount(fFontRef);
197548c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com}
197648c173d413ecc4c3661064be0f6f65022c1dc40dreed@google.com
1977e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com///////////////////////////////////////////////////////////////////////////////
1978e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com///////////////////////////////////////////////////////////////////////////////
1979e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com#if 1
198001ffa71f87664453998e2870808c82610584929areed@google.com
198101ffa71f87664453998e2870808c82610584929areed@google.comstatic bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
198201ffa71f87664453998e2870808c82610584929areed@google.com    AutoCFRelease<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
198301ffa71f87664453998e2870808c82610584929areed@google.com    if (NULL == ref.get()) {
198401ffa71f87664453998e2870808c82610584929areed@google.com        return false;
198501ffa71f87664453998e2870808c82610584929areed@google.com    }
198601ffa71f87664453998e2870808c82610584929areed@google.com    CFStringToSkString(ref, value);
198701ffa71f87664453998e2870808c82610584929areed@google.com    return true;
198801ffa71f87664453998e2870808c82610584929areed@google.com}
198901ffa71f87664453998e2870808c82610584929areed@google.com
199001ffa71f87664453998e2870808c82610584929areed@google.comstatic bool find_dict_float(CFDictionaryRef dict, CFStringRef name, float* value) {
199101ffa71f87664453998e2870808c82610584929areed@google.com    CFNumberRef num;
199201ffa71f87664453998e2870808c82610584929areed@google.com    return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num)
199301ffa71f87664453998e2870808c82610584929areed@google.com    && CFNumberIsFloatType(num)
199401ffa71f87664453998e2870808c82610584929areed@google.com    && CFNumberGetValue(num, kCFNumberFloatType, value);
199501ffa71f87664453998e2870808c82610584929areed@google.com}
199601ffa71f87664453998e2870808c82610584929areed@google.com
1997e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com#include "SkFontMgr.h"
1998e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com
199901ffa71f87664453998e2870808c82610584929areed@google.comstatic int unit_weight_to_fontstyle(float unit) {
200001ffa71f87664453998e2870808c82610584929areed@google.com    float value;
200101ffa71f87664453998e2870808c82610584929areed@google.com    if (unit < 0) {
200201ffa71f87664453998e2870808c82610584929areed@google.com        value = 100 + (1 + unit) * 300;
200301ffa71f87664453998e2870808c82610584929areed@google.com    } else {
200401ffa71f87664453998e2870808c82610584929areed@google.com        value = 400 + unit * 500;
200501ffa71f87664453998e2870808c82610584929areed@google.com    }
200601ffa71f87664453998e2870808c82610584929areed@google.com    return sk_float_round2int(value);
200701ffa71f87664453998e2870808c82610584929areed@google.com}
200801ffa71f87664453998e2870808c82610584929areed@google.com
200901ffa71f87664453998e2870808c82610584929areed@google.comstatic int unit_width_to_fontstyle(float unit) {
201001ffa71f87664453998e2870808c82610584929areed@google.com    float value;
201101ffa71f87664453998e2870808c82610584929areed@google.com    if (unit < 0) {
201201ffa71f87664453998e2870808c82610584929areed@google.com        value = 1 + (1 + unit) * 4;
201301ffa71f87664453998e2870808c82610584929areed@google.com    } else {
201401ffa71f87664453998e2870808c82610584929areed@google.com        value = 5 + unit * 4;
201501ffa71f87664453998e2870808c82610584929areed@google.com    }
201601ffa71f87664453998e2870808c82610584929areed@google.com    return sk_float_round2int(value);
201701ffa71f87664453998e2870808c82610584929areed@google.com}
201801ffa71f87664453998e2870808c82610584929areed@google.com
2019ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.comstatic inline int sqr(int value) {
2020ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    SkASSERT(SkAbs32(value) < 0x7FFF);  // check for overflow
2021ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    return value * value;
2022ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com}
2023ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com
2024ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com// We normalize each axis (weight, width, italic) to be base-900
2025ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.comstatic int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
2026ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    return sqr(a.weight() - b.weight()) +
2027ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com           sqr((a.width() - b.width()) * 100) +
2028ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com           sqr((a.isItalic() != b.isItalic()) * 900);
2029ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com}
2030ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com
203101ffa71f87664453998e2870808c82610584929areed@google.comstatic SkFontStyle desc2fontstyle(CTFontDescriptorRef desc) {
203201ffa71f87664453998e2870808c82610584929areed@google.com    AutoCFRelease<CFDictionaryRef> dict(
203301ffa71f87664453998e2870808c82610584929areed@google.com        (CFDictionaryRef)CTFontDescriptorCopyAttribute(desc,
203401ffa71f87664453998e2870808c82610584929areed@google.com                                                       kCTFontTraitsAttribute));
203501ffa71f87664453998e2870808c82610584929areed@google.com    if (NULL == dict.get()) {
203601ffa71f87664453998e2870808c82610584929areed@google.com        return SkFontStyle();
203701ffa71f87664453998e2870808c82610584929areed@google.com    }
203801ffa71f87664453998e2870808c82610584929areed@google.com
203901ffa71f87664453998e2870808c82610584929areed@google.com    float weight, width, slant;
204001ffa71f87664453998e2870808c82610584929areed@google.com    if (!find_dict_float(dict, kCTFontWeightTrait, &weight)) {
204101ffa71f87664453998e2870808c82610584929areed@google.com        weight = 0;
204201ffa71f87664453998e2870808c82610584929areed@google.com    }
204301ffa71f87664453998e2870808c82610584929areed@google.com    if (!find_dict_float(dict, kCTFontWidthTrait, &width)) {
204401ffa71f87664453998e2870808c82610584929areed@google.com        width = 0;
204501ffa71f87664453998e2870808c82610584929areed@google.com    }
204601ffa71f87664453998e2870808c82610584929areed@google.com    if (!find_dict_float(dict, kCTFontSlantTrait, &slant)) {
204701ffa71f87664453998e2870808c82610584929areed@google.com        slant = 0;
204801ffa71f87664453998e2870808c82610584929areed@google.com    }
2049cb9a1cd72d397d254c18441743b79de0bbc3da09skia.committer@gmail.com
205001ffa71f87664453998e2870808c82610584929areed@google.com    return SkFontStyle(unit_weight_to_fontstyle(weight),
205101ffa71f87664453998e2870808c82610584929areed@google.com                       unit_width_to_fontstyle(width),
205201ffa71f87664453998e2870808c82610584929areed@google.com                       slant ? SkFontStyle::kItalic_Slant
205301ffa71f87664453998e2870808c82610584929areed@google.com                       : SkFontStyle::kUpright_Slant);
205401ffa71f87664453998e2870808c82610584929areed@google.com}
205501ffa71f87664453998e2870808c82610584929areed@google.com
2056159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.comstruct NameFontStyleRec {
2057159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    SkString    fFamilyName;
2058159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    SkFontStyle fFontStyle;
2059159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com};
2060159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com
2061159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.comstatic bool nameFontStyleProc(SkTypeface* face, SkTypeface::Style,
2062159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com                              void* ctx) {
2063159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    SkTypeface_Mac* macFace = (SkTypeface_Mac*)face;
2064159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    const NameFontStyleRec* rec = (const NameFontStyleRec*)ctx;
2065159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com
2066159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    return macFace->fFontStyle == rec->fFontStyle &&
2067159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com           macFace->fName == rec->fFamilyName;
2068159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com}
2069159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com
2070b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.comstatic SkTypeface* createFromDesc(CFStringRef cfFamilyName,
2071b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com                                  CTFontDescriptorRef desc) {
2072159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    NameFontStyleRec rec;
2073159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    CFStringToSkString(cfFamilyName, &rec.fFamilyName);
2074159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    rec.fFontStyle = desc2fontstyle(desc);
2075159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com
2076159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    SkTypeface* face = SkTypefaceCache::FindByProcAndRef(nameFontStyleProc,
2077159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com                                                         &rec);
2078159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    if (face) {
2079159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com        return face;
2080159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    }
2081159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com
2082b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithName(cfFamilyName, 1, NULL));
2083b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    CTFontRef ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL, desc);
2084b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    if (NULL == ctFont) {
2085b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com        return NULL;
2086b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    }
2087cb9a1cd72d397d254c18441743b79de0bbc3da09skia.committer@gmail.com
2088b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    SkString str;
2089b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    CFStringToSkString(cfFamilyName, &str);
2090cb9a1cd72d397d254c18441743b79de0bbc3da09skia.committer@gmail.com
2091b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    bool isFixedPitch;
2092b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    (void)computeStyleBits(ctFont, &isFixedPitch);
2093b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com    SkFontID fontID = CTFontRef_to_SkFontID(ctFont);
2094cb9a1cd72d397d254c18441743b79de0bbc3da09skia.committer@gmail.com
2095159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    face = SkNEW_ARGS(SkTypeface_Mac, (rec.fFontStyle, fontID, isFixedPitch,
2096159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com                                       ctFont, str.c_str()));
2097159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    SkTypefaceCache::Add(face, face->style());
2098159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    return face;
2099b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com}
2100b6950743ce31468a5ca478f7916da10cf7b8c16areed@google.com
210101ffa71f87664453998e2870808c82610584929areed@google.comclass SkFontStyleSet_Mac : public SkFontStyleSet {
210201ffa71f87664453998e2870808c82610584929areed@google.compublic:
210301ffa71f87664453998e2870808c82610584929areed@google.com    SkFontStyleSet_Mac(CFStringRef familyName, CTFontDescriptorRef desc)
210401ffa71f87664453998e2870808c82610584929areed@google.com        : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, NULL))
2105159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com        , fFamilyName(familyName)
2106159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com        , fCount(0) {
210701ffa71f87664453998e2870808c82610584929areed@google.com        CFRetain(familyName);
2108159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com        if (NULL == fArray) {
2109159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com            fArray = CFArrayCreate(NULL, NULL, 0, NULL);
2110159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com        }
2111159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com        fCount = CFArrayGetCount(fArray);
211201ffa71f87664453998e2870808c82610584929areed@google.com    }
2113cb9a1cd72d397d254c18441743b79de0bbc3da09skia.committer@gmail.com
211401ffa71f87664453998e2870808c82610584929areed@google.com    virtual ~SkFontStyleSet_Mac() {
2115159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com        CFRelease(fArray);
211601ffa71f87664453998e2870808c82610584929areed@google.com        CFRelease(fFamilyName);
211701ffa71f87664453998e2870808c82610584929areed@google.com    }
211801ffa71f87664453998e2870808c82610584929areed@google.com
211901ffa71f87664453998e2870808c82610584929areed@google.com    virtual int count() SK_OVERRIDE {
2120159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com        return fCount;
212101ffa71f87664453998e2870808c82610584929areed@google.com    }
212201ffa71f87664453998e2870808c82610584929areed@google.com
212301ffa71f87664453998e2870808c82610584929areed@google.com    virtual void getStyle(int index, SkFontStyle* style,
212401ffa71f87664453998e2870808c82610584929areed@google.com                          SkString* name) SK_OVERRIDE {
2125159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com        SkASSERT((unsigned)index < (unsigned)fCount);
212601ffa71f87664453998e2870808c82610584929areed@google.com        CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
212701ffa71f87664453998e2870808c82610584929areed@google.com        if (style) {
212801ffa71f87664453998e2870808c82610584929areed@google.com            *style = desc2fontstyle(desc);
212901ffa71f87664453998e2870808c82610584929areed@google.com        }
213001ffa71f87664453998e2870808c82610584929areed@google.com        if (name) {
213101ffa71f87664453998e2870808c82610584929areed@google.com            if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
213201ffa71f87664453998e2870808c82610584929areed@google.com                name->reset();
213301ffa71f87664453998e2870808c82610584929areed@google.com            }
213401ffa71f87664453998e2870808c82610584929areed@google.com        }
213501ffa71f87664453998e2870808c82610584929areed@google.com    }
213601ffa71f87664453998e2870808c82610584929areed@google.com
213701ffa71f87664453998e2870808c82610584929areed@google.com    virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
213801ffa71f87664453998e2870808c82610584929areed@google.com        SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray));
213901ffa71f87664453998e2870808c82610584929areed@google.com        CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index);
2140cb9a1cd72d397d254c18441743b79de0bbc3da09skia.committer@gmail.com
214101ffa71f87664453998e2870808c82610584929areed@google.com        return createFromDesc(fFamilyName, desc);
214201ffa71f87664453998e2870808c82610584929areed@google.com    }
2143cb9a1cd72d397d254c18441743b79de0bbc3da09skia.committer@gmail.com
2144ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
2145ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        if (0 == fCount) {
2146ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com            return NULL;
2147ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        }
2148ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        return createFromDesc(fFamilyName, findMatchingDesc(pattern));
2149ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    }
2150ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com
215101ffa71f87664453998e2870808c82610584929areed@google.comprivate:
215201ffa71f87664453998e2870808c82610584929areed@google.com    CFArrayRef  fArray;
215301ffa71f87664453998e2870808c82610584929areed@google.com    CFStringRef fFamilyName;
2154159dfb6076b6a25e4bb87c5723567f1caf12e03freed@google.com    int         fCount;
2155ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com
2156ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
2157ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        int bestMetric = SK_MaxS32;
2158ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        CTFontDescriptorRef bestDesc = NULL;
2159e0a1ec938fbf36150f4d0869cf95fb5b7e0edcceskia.committer@gmail.com
2160ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        for (int i = 0; i < fCount; ++i) {
2161ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com            CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, i);
2162ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com            int metric = compute_metric(pattern, desc2fontstyle(desc));
2163ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com            if (0 == metric) {
2164ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com                return desc;
2165ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com            }
2166ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com            if (metric < bestMetric) {
2167ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com                bestMetric = metric;
2168ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com                bestDesc = desc;
2169ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com            }
2170ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        }
2171ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        SkASSERT(bestDesc);
2172ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        return bestDesc;
2173ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    }
217401ffa71f87664453998e2870808c82610584929areed@google.com};
217501ffa71f87664453998e2870808c82610584929areed@google.com
2176e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.comclass SkFontMgr_Mac : public SkFontMgr {
217701ffa71f87664453998e2870808c82610584929areed@google.com    int         fCount;
217801ffa71f87664453998e2870808c82610584929areed@google.com    CFArrayRef  fNames;
217901ffa71f87664453998e2870808c82610584929areed@google.com
218001ffa71f87664453998e2870808c82610584929areed@google.com    CFStringRef stringAt(int index) const {
218101ffa71f87664453998e2870808c82610584929areed@google.com        SkASSERT((unsigned)index < (unsigned)fCount);
218201ffa71f87664453998e2870808c82610584929areed@google.com        return (CFStringRef)CFArrayGetValueAtIndex(fNames, index);
218301ffa71f87664453998e2870808c82610584929areed@google.com    }
218401ffa71f87664453998e2870808c82610584929areed@google.com
218501ffa71f87664453998e2870808c82610584929areed@google.com    void lazyInit() {
218601ffa71f87664453998e2870808c82610584929areed@google.com        if (NULL == fNames) {
21879c28f1149c205580cbb0f018b083d065a7ae9222reed@google.com            fNames = SkCTFontManagerCopyAvailableFontFamilyNames();
218801ffa71f87664453998e2870808c82610584929areed@google.com            fCount = fNames ? CFArrayGetCount(fNames) : 0;
218901ffa71f87664453998e2870808c82610584929areed@google.com        }
219001ffa71f87664453998e2870808c82610584929areed@google.com    }
219101ffa71f87664453998e2870808c82610584929areed@google.com
2192ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) {
2193ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        AutoCFRelease<CFMutableDictionaryRef> cfAttr(
2194ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com                 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2195ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com                                           &kCFTypeDictionaryKeyCallBacks,
2196ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com                                           &kCFTypeDictionaryValueCallBacks));
2197e0a1ec938fbf36150f4d0869cf95fb5b7e0edcceskia.committer@gmail.com
2198ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        CFDictionaryAddValue(cfAttr, kCTFontFamilyNameAttribute, cfFamilyName);
2199e0a1ec938fbf36150f4d0869cf95fb5b7e0edcceskia.committer@gmail.com
2200ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        AutoCFRelease<CTFontDescriptorRef> desc(
2201ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com                                CTFontDescriptorCreateWithAttributes(cfAttr));
2202ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        return SkNEW_ARGS(SkFontStyleSet_Mac, (cfFamilyName, desc));
2203ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    }
2204e0a1ec938fbf36150f4d0869cf95fb5b7e0edcceskia.committer@gmail.com
2205e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.compublic:
220601ffa71f87664453998e2870808c82610584929areed@google.com    SkFontMgr_Mac() : fCount(0), fNames(NULL) {}
220701ffa71f87664453998e2870808c82610584929areed@google.com
220801ffa71f87664453998e2870808c82610584929areed@google.com    virtual ~SkFontMgr_Mac() {
220901ffa71f87664453998e2870808c82610584929areed@google.com        CFSafeRelease(fNames);
221001ffa71f87664453998e2870808c82610584929areed@google.com    }
2211e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com
2212e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.comprotected:
2213e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    virtual int onCountFamilies() SK_OVERRIDE {
221401ffa71f87664453998e2870808c82610584929areed@google.com        this->lazyInit();
221501ffa71f87664453998e2870808c82610584929areed@google.com        return fCount;
2216e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    }
2217e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com
2218e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    virtual void onGetFamilyName(int index, SkString* familyName) SK_OVERRIDE {
221901ffa71f87664453998e2870808c82610584929areed@google.com        this->lazyInit();
222001ffa71f87664453998e2870808c82610584929areed@google.com        if ((unsigned)index < (unsigned)fCount) {
222101ffa71f87664453998e2870808c82610584929areed@google.com            CFStringToSkString(this->stringAt(index), familyName);
222201ffa71f87664453998e2870808c82610584929areed@google.com        } else {
222301ffa71f87664453998e2870808c82610584929areed@google.com            familyName->reset();
222401ffa71f87664453998e2870808c82610584929areed@google.com        }
2225e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    }
2226e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com
2227e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    virtual SkFontStyleSet* onCreateStyleSet(int index) SK_OVERRIDE {
222801ffa71f87664453998e2870808c82610584929areed@google.com        this->lazyInit();
222901ffa71f87664453998e2870808c82610584929areed@google.com        if ((unsigned)index >= (unsigned)fCount) {
223001ffa71f87664453998e2870808c82610584929areed@google.com            return NULL;
223101ffa71f87664453998e2870808c82610584929areed@google.com        }
2232ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        return CreateSet(this->stringAt(index));
2233e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    }
2234e0a1ec938fbf36150f4d0869cf95fb5b7e0edcceskia.committer@gmail.com
2235ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    virtual SkFontStyleSet* onMatchFamily(const char familyName[]) SK_OVERRIDE {
2236ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        AutoCFRelease<CFStringRef> cfName(make_CFString(familyName));
2237ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com        return CreateSet(cfName);
2238ab8665f8e88927b1a9b82aca38483d8a963fd2e0reed@google.com    }
2239e0a1ec938fbf36150f4d0869cf95fb5b7e0edcceskia.committer@gmail.com
2240e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
2241e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com                                           const SkFontStyle&) SK_OVERRIDE {
2242e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        return NULL;
2243e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    }
2244b691cc7b343bbe193c11aa423f95783c073bef6dskia.committer@gmail.com
2245e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2246e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com                                         const SkFontStyle&) SK_OVERRIDE {
2247e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        return NULL;
2248e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    }
2249b691cc7b343bbe193c11aa423f95783c073bef6dskia.committer@gmail.com
2250e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    virtual SkTypeface* onCreateFromData(SkData* data,
2251e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com                                         int ttcIndex) SK_OVERRIDE {
2252e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromData(data));
2253e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        if (NULL == pr) {
2254e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com            return NULL;
2255e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        }
2256e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        return create_from_dataProvider(pr);
2257e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    }
2258e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com
2259e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    virtual SkTypeface* onCreateFromStream(SkStream* stream,
2260e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com                                           int ttcIndex) SK_OVERRIDE {
2261e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromStream(stream));
2262e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        if (NULL == pr) {
2263e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com            return NULL;
2264e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        }
2265e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        return create_from_dataProvider(pr);
2266e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    }
2267e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com
2268e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    virtual SkTypeface* onCreateFromFile(const char path[],
2269e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com                                         int ttcIndex) SK_OVERRIDE {
2270e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        AutoCFRelease<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path));
2271e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        if (NULL == pr) {
2272e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com            return NULL;
2273e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        }
2274e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com        return create_from_dataProvider(pr);
2275e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    }
2276ff58f8b49a03197747998f4069e0980d9f6d34c0skia.committer@gmail.com
2277836008c1588a111f090a606726822d62d3026e00reed@google.com    virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
2278836008c1588a111f090a606726822d62d3026e00reed@google.com                                               unsigned styleBits) SK_OVERRIDE {
2279836008c1588a111f090a606726822d62d3026e00reed@google.com        return create_typeface(NULL, familyName, (SkTypeface::Style)styleBits);
2280836008c1588a111f090a606726822d62d3026e00reed@google.com    }
2281e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com};
2282e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com
2283836008c1588a111f090a606726822d62d3026e00reed@google.com///////////////////////////////////////////////////////////////////////////////
2284836008c1588a111f090a606726822d62d3026e00reed@google.com
2285836008c1588a111f090a606726822d62d3026e00reed@google.com#ifndef SK_FONTHOST_USES_FONTMGR
2286836008c1588a111f090a606726822d62d3026e00reed@google.com
2287836008c1588a111f090a606726822d62d3026e00reed@google.comSkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
2288836008c1588a111f090a606726822d62d3026e00reed@google.com                                       const char familyName[],
2289836008c1588a111f090a606726822d62d3026e00reed@google.com                                       SkTypeface::Style style) {
2290836008c1588a111f090a606726822d62d3026e00reed@google.com    return create_typeface(familyFace, familyName, style);
2291836008c1588a111f090a606726822d62d3026e00reed@google.com}
2292836008c1588a111f090a606726822d62d3026e00reed@google.com
2293836008c1588a111f090a606726822d62d3026e00reed@google.comSkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
2294836008c1588a111f090a606726822d62d3026e00reed@google.com    AutoCFRelease<CGDataProviderRef> provider(SkCreateDataProviderFromStream(stream));
2295836008c1588a111f090a606726822d62d3026e00reed@google.com    if (NULL == provider) {
2296836008c1588a111f090a606726822d62d3026e00reed@google.com        return NULL;
2297836008c1588a111f090a606726822d62d3026e00reed@google.com    }
2298836008c1588a111f090a606726822d62d3026e00reed@google.com    return create_from_dataProvider(provider);
2299836008c1588a111f090a606726822d62d3026e00reed@google.com}
2300836008c1588a111f090a606726822d62d3026e00reed@google.com
2301836008c1588a111f090a606726822d62d3026e00reed@google.comSkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
2302836008c1588a111f090a606726822d62d3026e00reed@google.com    AutoCFRelease<CGDataProviderRef> provider(CGDataProviderCreateWithFilename(path));
2303836008c1588a111f090a606726822d62d3026e00reed@google.com    if (NULL == provider) {
2304836008c1588a111f090a606726822d62d3026e00reed@google.com        return NULL;
2305836008c1588a111f090a606726822d62d3026e00reed@google.com    }
2306836008c1588a111f090a606726822d62d3026e00reed@google.com    return create_from_dataProvider(provider);
2307836008c1588a111f090a606726822d62d3026e00reed@google.com}
2308836008c1588a111f090a606726822d62d3026e00reed@google.com
2309836008c1588a111f090a606726822d62d3026e00reed@google.com#endif
2310836008c1588a111f090a606726822d62d3026e00reed@google.com
2311e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.comSkFontMgr* SkFontMgr::Factory() {
2312e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com    return SkNEW(SkFontMgr_Mac);
2313e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com}
2314e621e833c89b7621721bbc8a162c5685aa33ade0reed@google.com#endif
2315