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