Upstream version 10.39.225.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 #import "platform/fonts/harfbuzz/HarfBuzzFace.h"
32 #include "third_party/skia/include/ports/SkTypeface_mac.h"
33
34 namespace blink {
35
36 unsigned FontPlatformData::hash() const
37 {
38     ASSERT(m_font || !m_cgFont);
39     uintptr_t hashCodes[3] = { (uintptr_t)m_font, m_widthVariant, static_cast<uintptr_t>(m_isHashTableDeletedValue << 3 | m_orientation << 2 | m_syntheticBold << 1 | m_syntheticItalic) };
40     return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes);
41 }
42
43 // These CoreText Text Spacing feature selectors are not defined in CoreText.
44 enum TextSpacingCTFeatureSelector { TextSpacingProportional, TextSpacingFullWidth, TextSpacingHalfWidth, TextSpacingThirdWidth, TextSpacingQuarterWidth };
45
46 FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBold, bool syntheticItalic, FontOrientation orientation, FontWidthVariant widthVariant)
47     : m_textSize(size)
48     , m_syntheticBold(syntheticBold)
49     , m_syntheticItalic(syntheticItalic)
50     , m_orientation(orientation)
51     , m_isColorBitmapFont(false)
52     , m_isCompositeFontReference(false)
53     , m_widthVariant(widthVariant)
54     , m_font(nsFont)
55     , m_isHashTableDeletedValue(false)
56 {
57     ASSERT_ARG(nsFont, nsFont);
58
59     CGFontRef cgFont = 0;
60     loadFont(nsFont, size, m_font, cgFont);
61
62 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
63     // FIXME: Chromium: The following code isn't correct for the Chromium port since the sandbox might
64     // have blocked font loading, in which case we'll only have the real loaded font file after the call to loadFont().
65     {
66         CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(m_font));
67         m_isColorBitmapFont = traits & kCTFontColorGlyphsTrait;
68 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
69         m_isCompositeFontReference = traits & kCTFontCompositeTrait;
70 #endif
71     }
72 #endif
73
74     if (m_font)
75         CFRetain(m_font);
76
77     m_cgFont.adoptCF(cgFont);
78 }
79
80 void FontPlatformData::platformDataInit(const FontPlatformData& f)
81 {
82     m_font = f.m_font ? [f.m_font retain] : f.m_font;
83
84     m_cgFont = f.m_cgFont;
85     m_CTFont = f.m_CTFont;
86
87     m_inMemoryFont = f.m_inMemoryFont;
88     m_harfBuzzFace = f.m_harfBuzzFace;
89     m_typeface = f.m_typeface;
90 }
91
92 const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformData& f)
93 {
94     m_cgFont = f.m_cgFont;
95     if (m_font == f.m_font)
96         return *this;
97     if (f.m_font)
98         CFRetain(f.m_font);
99     if (m_font)
100         CFRelease(m_font);
101     m_font = f.m_font;
102     m_CTFont = f.m_CTFont;
103
104     m_inMemoryFont = f.m_inMemoryFont;
105     m_harfBuzzFace = f.m_harfBuzzFace;
106     m_typeface = f.m_typeface;
107
108     return *this;
109 }
110
111
112 void FontPlatformData::setFont(NSFont *font)
113 {
114     ASSERT_ARG(font, font);
115
116     if (m_font == font)
117         return;
118
119     CFRetain(font);
120     if (m_font)
121         CFRelease(m_font);
122     m_font = font;
123     m_textSize = [font pointSize];
124
125     CGFontRef cgFont = 0;
126     NSFont* loadedFont = 0;
127     loadFont(m_font, m_textSize, loadedFont, cgFont);
128
129     // If loadFont replaced m_font with a fallback font, then release the
130     // previous font to counter the retain above. Then retain the new font.
131     if (loadedFont != m_font) {
132         CFRelease(m_font);
133         CFRetain(loadedFont);
134         m_font = loadedFont;
135     }
136
137     m_cgFont.adoptCF(cgFont);
138 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
139     {
140         CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(m_font));
141         m_isColorBitmapFont = traits & kCTFontColorGlyphsTrait;
142 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
143         m_isCompositeFontReference = traits & kCTFontCompositeTrait;
144 #endif
145     }
146 #endif
147     m_CTFont = 0;
148 }
149
150 bool FontPlatformData::roundsGlyphAdvances() const
151 {
152     return [m_font renderingMode] == NSFontAntialiasedIntegerAdvancementsRenderingMode;
153 }
154
155 bool FontPlatformData::allowsLigatures() const
156 {
157     return ![[m_font coveredCharacterSet] characterIsMember:'a'];
158 }
159
160 inline int mapFontWidthVariantToCTFeatureSelector(FontWidthVariant variant)
161 {
162     switch(variant) {
163     case RegularWidth:
164         return TextSpacingProportional;
165
166     case HalfWidth:
167         return TextSpacingHalfWidth;
168
169     case ThirdWidth:
170         return TextSpacingThirdWidth;
171
172     case QuarterWidth:
173         return TextSpacingQuarterWidth;
174     }
175
176     ASSERT_NOT_REACHED();
177     return TextSpacingProportional;
178 }
179
180 static CFDictionaryRef createFeatureSettingDictionary(int featureTypeIdentifier, int featureSelectorIdentifier)
181 {
182     RetainPtr<CFNumberRef> featureTypeIdentifierNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeIdentifier));
183     RetainPtr<CFNumberRef> featureSelectorIdentifierNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorIdentifier));
184
185     const void* settingKeys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey };
186     const void* settingValues[] = { featureTypeIdentifierNumber.get(), featureSelectorIdentifierNumber.get() };
187
188     return CFDictionaryCreate(kCFAllocatorDefault, settingKeys, settingValues, WTF_ARRAY_LENGTH(settingKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
189 }
190
191 static CTFontDescriptorRef cascadeToLastResortFontDescriptor()
192 {
193     static CTFontDescriptorRef descriptor;
194     if (descriptor)
195         return descriptor;
196
197     const void* keys[] = { kCTFontCascadeListAttribute };
198     const void* descriptors[] = { CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0) };
199     const void* values[] = { CFArrayCreate(kCFAllocatorDefault, descriptors, WTF_ARRAY_LENGTH(descriptors), &kCFTypeArrayCallBacks) };
200     RetainPtr<CFDictionaryRef> attributes(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
201
202     descriptor = CTFontDescriptorCreateWithAttributes(attributes.get());
203
204     return descriptor;
205 }
206
207 static CTFontDescriptorRef cascadeToLastResortAndDisableSwashesFontDescriptor()
208 {
209     static CTFontDescriptorRef descriptor;
210     if (descriptor)
211         return descriptor;
212
213     RetainPtr<CFDictionaryRef> lineInitialSwashesOffSetting(AdoptCF, createFeatureSettingDictionary(kSmartSwashType, kLineInitialSwashesOffSelector));
214     RetainPtr<CFDictionaryRef> lineFinalSwashesOffSetting(AdoptCF, createFeatureSettingDictionary(kSmartSwashType, kLineFinalSwashesOffSelector));
215
216     const void* settingDictionaries[] = { lineInitialSwashesOffSetting.get(), lineFinalSwashesOffSetting.get() };
217     RetainPtr<CFArrayRef> featureSettings(AdoptCF, CFArrayCreate(kCFAllocatorDefault, settingDictionaries, WTF_ARRAY_LENGTH(settingDictionaries), &kCFTypeArrayCallBacks));
218
219     const void* keys[] = { kCTFontFeatureSettingsAttribute };
220     const void* values[] = { featureSettings.get() };
221     RetainPtr<CFDictionaryRef> attributes(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
222
223     descriptor = CTFontDescriptorCreateCopyWithAttributes(cascadeToLastResortFontDescriptor(), attributes.get());
224
225     return descriptor;
226 }
227
228 CTFontRef FontPlatformData::ctFont() const
229 {
230     if (m_CTFont)
231         return m_CTFont.get();
232
233     if (m_inMemoryFont) {
234         m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_inMemoryFont->cgFont(), m_textSize, 0, cascadeToLastResortFontDescriptor()));
235         return m_CTFont.get();
236     }
237
238     m_CTFont = toCTFontRef(m_font);
239     if (m_CTFont) {
240         CTFontDescriptorRef fontDescriptor;
241         RetainPtr<CFStringRef> postScriptName(AdoptCF, CTFontCopyPostScriptName(m_CTFont.get()));
242         // Hoefler Text Italic has line-initial and -final swashes enabled by default, so disable them.
243         if (CFEqual(postScriptName.get(), CFSTR("HoeflerText-Italic")) || CFEqual(postScriptName.get(), CFSTR("HoeflerText-BlackItalic")))
244             fontDescriptor = cascadeToLastResortAndDisableSwashesFontDescriptor();
245         else
246             fontDescriptor = cascadeToLastResortFontDescriptor();
247         m_CTFont.adoptCF(CTFontCreateCopyWithAttributes(m_CTFont.get(), m_textSize, 0, fontDescriptor));
248     } else
249         m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), m_textSize, 0, cascadeToLastResortFontDescriptor()));
250
251     if (m_widthVariant != RegularWidth) {
252         int featureTypeValue = kTextSpacingType;
253         int featureSelectorValue = mapFontWidthVariantToCTFeatureSelector(m_widthVariant);
254         RetainPtr<CTFontDescriptorRef> sourceDescriptor(AdoptCF, CTFontCopyFontDescriptor(m_CTFont.get()));
255         RetainPtr<CFNumberRef> featureType(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeValue));
256         RetainPtr<CFNumberRef> featureSelector(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorValue));
257         RetainPtr<CTFontDescriptorRef> newDescriptor(AdoptCF, CTFontDescriptorCreateCopyWithFeature(sourceDescriptor.get(), featureType.get(), featureSelector.get()));
258         RetainPtr<CTFontRef> newFont(AdoptCF, CTFontCreateWithFontDescriptor(newDescriptor.get(), m_textSize, 0));
259
260         if (newFont)
261             m_CTFont = newFont;
262     }
263
264     return m_CTFont.get();
265 }
266
267 bool FontPlatformData::isAATFont(CTFontRef ctFont) const
268 {
269     CFDataRef table = CTFontCopyTable(ctFont, kCTFontTableMort, 0);
270     if (table) {
271         CFRelease(table);
272         return true;
273     }
274     table = CTFontCopyTable(ctFont, kCTFontTableMorx, 0);
275     if (table) {
276         CFRelease(table);
277         return true;
278     }
279     return false;
280 }
281
282 } // namespace blink