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