Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / fonts / cocoa / FontPlatformDataCocoa.mm
1 /*
2  * This file is part of the internal font implementation.
3  *
4  * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
5  * Copyright (c) 2010 Google Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #import "config.h"
25 #import "platform/fonts/FontPlatformData.h"
26
27 #import <AppKit/NSFont.h>
28 #import <AvailabilityMacros.h>
29 #import <wtf/text/WTFString.h>
30
31 #if OS(MACOSX)
32 #import "platform/fonts/harfbuzz/HarfBuzzFace.h"
33 #include "third_party/skia/include/ports/SkTypeface_mac.h"
34 #endif
35
36 namespace blink {
37
38 // These CoreText Text Spacing feature selectors are not defined in CoreText.
39 enum TextSpacingCTFeatureSelector { TextSpacingProportional, TextSpacingFullWidth, TextSpacingHalfWidth, TextSpacingThirdWidth, TextSpacingQuarterWidth };
40
41 FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, FontWidthVariant widthVariant)
42     : m_syntheticBold(syntheticBold)
43     , m_syntheticOblique(syntheticOblique)
44     , m_orientation(orientation)
45     , m_size(size)
46     , m_widthVariant(widthVariant)
47     , m_font(nsFont)
48     , m_isColorBitmapFont(false)
49     , m_isCompositeFontReference(false)
50 {
51     ASSERT_ARG(nsFont, nsFont);
52
53     CGFontRef cgFont = 0;
54     loadFont(nsFont, size, m_font, cgFont);
55
56 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
57     // FIXME: Chromium: The following code isn't correct for the Chromium port since the sandbox might
58     // have blocked font loading, in which case we'll only have the real loaded font file after the call to loadFont().
59     {
60         CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(m_font));
61         m_isColorBitmapFont = traits & kCTFontColorGlyphsTrait;
62 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
63         m_isCompositeFontReference = traits & kCTFontCompositeTrait;
64 #endif
65     }
66 #endif
67
68     if (m_font)
69         CFRetain(m_font);
70
71     m_cgFont.adoptCF(cgFont);
72 }
73
74 FontPlatformData:: ~FontPlatformData()
75 {
76     if (m_font && m_font != reinterpret_cast<NSFont *>(-1))
77         CFRelease(m_font);
78 }
79
80 void FontPlatformData::platformDataInit(const FontPlatformData& f)
81 {
82     m_font = f.m_font && f.m_font != reinterpret_cast<NSFont *>(-1) ? [f.m_font retain] : f.m_font;
83
84     m_cgFont = f.m_cgFont;
85     m_CTFont = f.m_CTFont;
86
87 #if OS(MACOSX)
88     m_inMemoryFont = f.m_inMemoryFont;
89     m_harfBuzzFace = f.m_harfBuzzFace;
90     m_typeface = f.m_typeface;
91 #endif
92 }
93
94 const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformData& f)
95 {
96     m_cgFont = f.m_cgFont;
97     if (m_font == f.m_font)
98         return *this;
99     if (f.m_font && f.m_font != reinterpret_cast<NSFont *>(-1))
100         CFRetain(f.m_font);
101     if (m_font && m_font != reinterpret_cast<NSFont *>(-1))
102         CFRelease(m_font);
103     m_font = f.m_font;
104     m_CTFont = f.m_CTFont;
105 #if OS(MACOSX)
106     m_inMemoryFont = f.m_inMemoryFont;
107     m_harfBuzzFace = f.m_harfBuzzFace;
108     m_typeface = f.m_typeface;
109 #endif
110     return *this;
111 }
112
113 bool FontPlatformData::platformIsEqual(const FontPlatformData& other) const
114 {
115     if (m_font || other.m_font)
116         return m_font == other.m_font;
117     return m_cgFont == other.m_cgFont;
118 }
119
120 void FontPlatformData::setFont(NSFont *font)
121 {
122     ASSERT_ARG(font, font);
123     ASSERT(m_font != reinterpret_cast<NSFont *>(-1));
124
125     if (m_font == font)
126         return;
127
128     CFRetain(font);
129     if (m_font)
130         CFRelease(m_font);
131     m_font = font;
132     m_size = [font pointSize];
133
134     CGFontRef cgFont = 0;
135     NSFont* loadedFont = 0;
136     loadFont(m_font, m_size, loadedFont, cgFont);
137
138 #if OS(MACOSX)
139     // If loadFont replaced m_font with a fallback font, then release the
140     // previous font to counter the retain above. Then retain the new font.
141     if (loadedFont != m_font) {
142         CFRelease(m_font);
143         CFRetain(loadedFont);
144         m_font = loadedFont;
145     }
146 #endif
147
148     m_cgFont.adoptCF(cgFont);
149 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
150     {
151         CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(m_font));
152         m_isColorBitmapFont = traits & kCTFontColorGlyphsTrait;
153 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
154         m_isCompositeFontReference = traits & kCTFontCompositeTrait;
155 #endif
156     }
157 #endif
158     m_CTFont = 0;
159 }
160
161 bool FontPlatformData::roundsGlyphAdvances() const
162 {
163     return [m_font renderingMode] == NSFontAntialiasedIntegerAdvancementsRenderingMode;
164 }
165
166 bool FontPlatformData::allowsLigatures() const
167 {
168     return ![[m_font coveredCharacterSet] characterIsMember:'a'];
169 }
170
171 inline int mapFontWidthVariantToCTFeatureSelector(FontWidthVariant variant)
172 {
173     switch(variant) {
174     case RegularWidth:
175         return TextSpacingProportional;
176
177     case HalfWidth:
178         return TextSpacingHalfWidth;
179
180     case ThirdWidth:
181         return TextSpacingThirdWidth;
182
183     case QuarterWidth:
184         return TextSpacingQuarterWidth;
185     }
186
187     ASSERT_NOT_REACHED();
188     return TextSpacingProportional;
189 }
190
191 static CFDictionaryRef createFeatureSettingDictionary(int featureTypeIdentifier, int featureSelectorIdentifier)
192 {
193     RetainPtr<CFNumberRef> featureTypeIdentifierNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeIdentifier));
194     RetainPtr<CFNumberRef> featureSelectorIdentifierNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorIdentifier));
195
196     const void* settingKeys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey };
197     const void* settingValues[] = { featureTypeIdentifierNumber.get(), featureSelectorIdentifierNumber.get() };
198
199     return CFDictionaryCreate(kCFAllocatorDefault, settingKeys, settingValues, WTF_ARRAY_LENGTH(settingKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
200 }
201
202 static CTFontDescriptorRef cascadeToLastResortFontDescriptor()
203 {
204     static CTFontDescriptorRef descriptor;
205     if (descriptor)
206         return descriptor;
207
208     const void* keys[] = { kCTFontCascadeListAttribute };
209     const void* descriptors[] = { CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0) };
210     const void* values[] = { CFArrayCreate(kCFAllocatorDefault, descriptors, WTF_ARRAY_LENGTH(descriptors), &kCFTypeArrayCallBacks) };
211     RetainPtr<CFDictionaryRef> attributes(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
212
213     descriptor = CTFontDescriptorCreateWithAttributes(attributes.get());
214
215     return descriptor;
216 }
217
218 static CTFontDescriptorRef cascadeToLastResortAndDisableSwashesFontDescriptor()
219 {
220     static CTFontDescriptorRef descriptor;
221     if (descriptor)
222         return descriptor;
223
224     RetainPtr<CFDictionaryRef> lineInitialSwashesOffSetting(AdoptCF, createFeatureSettingDictionary(kSmartSwashType, kLineInitialSwashesOffSelector));
225     RetainPtr<CFDictionaryRef> lineFinalSwashesOffSetting(AdoptCF, createFeatureSettingDictionary(kSmartSwashType, kLineFinalSwashesOffSelector));
226
227     const void* settingDictionaries[] = { lineInitialSwashesOffSetting.get(), lineFinalSwashesOffSetting.get() };
228     RetainPtr<CFArrayRef> featureSettings(AdoptCF, CFArrayCreate(kCFAllocatorDefault, settingDictionaries, WTF_ARRAY_LENGTH(settingDictionaries), &kCFTypeArrayCallBacks));
229
230     const void* keys[] = { kCTFontFeatureSettingsAttribute };
231     const void* values[] = { featureSettings.get() };
232     RetainPtr<CFDictionaryRef> attributes(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
233
234     descriptor = CTFontDescriptorCreateCopyWithAttributes(cascadeToLastResortFontDescriptor(), attributes.get());
235
236     return descriptor;
237 }
238
239 String FontPlatformData::fontFamilyName() const
240 {
241     return String(CTFontCopyDisplayName(ctFont()));
242 }
243
244 CTFontRef FontPlatformData::ctFont() const
245 {
246     if (m_CTFont)
247         return m_CTFont.get();
248
249     if (m_inMemoryFont) {
250         m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_inMemoryFont->cgFont(), m_size, 0, cascadeToLastResortFontDescriptor()));
251         return m_CTFont.get();
252     }
253
254     m_CTFont = toCTFontRef(m_font);
255     if (m_CTFont) {
256         CTFontDescriptorRef fontDescriptor;
257         RetainPtr<CFStringRef> postScriptName(AdoptCF, CTFontCopyPostScriptName(m_CTFont.get()));
258         // Hoefler Text Italic has line-initial and -final swashes enabled by default, so disable them.
259         if (CFEqual(postScriptName.get(), CFSTR("HoeflerText-Italic")) || CFEqual(postScriptName.get(), CFSTR("HoeflerText-BlackItalic")))
260             fontDescriptor = cascadeToLastResortAndDisableSwashesFontDescriptor();
261         else
262             fontDescriptor = cascadeToLastResortFontDescriptor();
263         m_CTFont.adoptCF(CTFontCreateCopyWithAttributes(m_CTFont.get(), m_size, 0, fontDescriptor));
264     } else
265         m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), m_size, 0, cascadeToLastResortFontDescriptor()));
266
267     if (m_widthVariant != RegularWidth) {
268         int featureTypeValue = kTextSpacingType;
269         int featureSelectorValue = mapFontWidthVariantToCTFeatureSelector(m_widthVariant);
270         RetainPtr<CTFontDescriptorRef> sourceDescriptor(AdoptCF, CTFontCopyFontDescriptor(m_CTFont.get()));
271         RetainPtr<CFNumberRef> featureType(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeValue));
272         RetainPtr<CFNumberRef> featureSelector(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorValue));
273         RetainPtr<CTFontDescriptorRef> newDescriptor(AdoptCF, CTFontDescriptorCreateCopyWithFeature(sourceDescriptor.get(), featureType.get(), featureSelector.get()));
274         RetainPtr<CTFontRef> newFont(AdoptCF, CTFontCreateWithFontDescriptor(newDescriptor.get(), m_size, 0));
275
276         if (newFont)
277             m_CTFont = newFont;
278     }
279
280     return m_CTFont.get();
281 }
282
283 SkTypeface* FontPlatformData::typeface() const{
284     if (m_typeface)
285         return m_typeface.get();
286
287     m_typeface = adoptRef(SkCreateTypefaceFromCTFont(ctFont()));
288     return m_typeface.get();
289 }
290
291 #if OS(MACOSX)
292 static bool isAATFont(CTFontRef ctFont)
293 {
294     CFDataRef table = CTFontCopyTable(ctFont, kCTFontTableMort, 0);
295     if (table) {
296         CFRelease(table);
297         return true;
298     }
299     table = CTFontCopyTable(ctFont, kCTFontTableMorx, 0);
300     if (table) {
301         CFRelease(table);
302         return true;
303     }
304     return false;
305 }
306
307 HarfBuzzFace* FontPlatformData::harfBuzzFace()
308 {
309     CTFontRef font = ctFont();
310     // HarfBuzz can't handle AAT font
311     if (isAATFont(font))
312         return 0;
313
314     if (!m_harfBuzzFace) {
315         uint64_t uniqueID = reinterpret_cast<uintptr_t>(font);
316         m_harfBuzzFace = HarfBuzzFace::create(const_cast<FontPlatformData*>(this), uniqueID);
317     }
318     return m_harfBuzzFace.get();
319 }
320 #endif
321
322 #ifndef NDEBUG
323 String FontPlatformData::description() const
324 {
325     RetainPtr<CFStringRef> cgFontDescription(AdoptCF, CFCopyDescription(cgFont()));
326     return String(cgFontDescription.get()) + " " + String::number(m_size)
327             + (m_syntheticBold ? " synthetic bold" : "") + (m_syntheticOblique ? " synthetic oblique" : "") + (m_orientation ? " vertical orientation" : "");
328 }
329 #endif
330
331 } // namespace blink