Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / fonts / mac / FontCacheMac.mm
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #import "config.h"
31 #import "platform/fonts/FontCache.h"
32
33 #import <AppKit/AppKit.h>
34 #import "platform/LayoutTestSupport.h"
35 #import "platform/RuntimeEnabledFeatures.h"
36 #import "platform/fonts/FontDescription.h"
37 #import "platform/fonts/FontFaceCreationParams.h"
38 #import "platform/fonts/FontPlatformData.h"
39 #import "platform/fonts/SimpleFontData.h"
40 #import "platform/mac/WebFontCache.h"
41 #import <wtf/MainThread.h>
42 #import <wtf/StdLibExtras.h>
43
44 // Forward declare Mac SPIs.
45 // Request for public API: rdar://13803570
46 @interface NSFont (WebKitSPI)
47 + (NSFont*)findFontLike:(NSFont*)font forString:(NSString*)string withRange:(NSRange)range inLanguage:(id)useNil;
48 + (NSFont*)findFontLike:(NSFont*)font forCharacter:(UniChar)uc inLanguage:(id)useNil;
49 @end
50
51 namespace blink {
52
53 // The "void*" parameter makes the function match the prototype for callbacks from callOnMainThread.
54 static void invalidateFontCache(void*)
55 {
56     if (!isMainThread()) {
57         callOnMainThread(&invalidateFontCache, 0);
58         return;
59     }
60     FontCache::fontCache()->invalidate();
61 }
62
63 static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef name, const void *, CFDictionaryRef)
64 {
65     ASSERT_UNUSED(observer, observer == FontCache::fontCache());
66     ASSERT_UNUSED(name, CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification));
67     invalidateFontCache(0);
68 }
69
70 static bool useHinting()
71 {
72     // Enable hinting when subpixel font scaling is disabled or
73     // when running the set of standard non-subpixel layout tests,
74     // otherwise use subpixel glyph positioning.
75     return (LayoutTestSupport::isRunningLayoutTest() && !LayoutTestSupport::isFontAntialiasingEnabledForTest()) || !RuntimeEnabledFeatures::subpixelFontScalingEnabled();
76 }
77
78 void FontCache::platformInit()
79 {
80     CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this, fontCacheRegisteredFontsChangedNotificationCallback, kCTFontManagerRegisteredFontsChangedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately);
81 }
82
83 static int toAppKitFontWeight(FontWeight fontWeight)
84 {
85     static int appKitFontWeights[] = {
86         2,  // FontWeight100
87         3,  // FontWeight200
88         4,  // FontWeight300
89         5,  // FontWeight400
90         6,  // FontWeight500
91         8,  // FontWeight600
92         9,  // FontWeight700
93         10, // FontWeight800
94         12, // FontWeight900
95     };
96     return appKitFontWeights[fontWeight];
97 }
98
99 static inline bool isAppKitFontWeightBold(NSInteger appKitFontWeight)
100 {
101     return appKitFontWeight >= 7;
102 }
103
104 PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 character, const SimpleFontData* fontDataToSubstitute)
105 {
106     // FIXME: We should fix getFallbackFamily to take a UChar32
107     // and remove this split-to-UChar16 code.
108     UChar codeUnits[2];
109     int codeUnitsLength;
110     if (character <= 0xFFFF) {
111         codeUnits[0] = character;
112         codeUnitsLength = 1;
113     } else {
114         codeUnits[0] = U16_LEAD(character);
115         codeUnits[1] = U16_TRAIL(character);
116         codeUnitsLength = 2;
117     }
118
119     const FontPlatformData& platformData = fontDataToSubstitute->platformData();
120     NSFont *nsFont = platformData.font();
121
122     NSString *string = [[NSString alloc] initWithCharactersNoCopy:codeUnits length:codeUnitsLength freeWhenDone:NO];
123     NSFont *substituteFont = [NSFont findFontLike:nsFont forString:string withRange:NSMakeRange(0, codeUnitsLength) inLanguage:nil];
124     [string release];
125
126     // FIXME: Remove this SPI usage: http://crbug.com/255122
127     if (!substituteFont && codeUnitsLength == 1)
128         substituteFont = [NSFont findFontLike:nsFont forCharacter:codeUnits[0] inLanguage:nil];
129     if (!substituteFont)
130         return nullptr;
131
132     // Chromium can't render AppleColorEmoji.
133     if ([[substituteFont familyName] isEqual:@"Apple Color Emoji"])
134         return nullptr;
135
136     // Use the family name from the AppKit-supplied substitute font, requesting the
137     // traits, weight, and size we want. One way this does better than the original
138     // AppKit request is that it takes synthetic bold and oblique into account.
139     // But it does create the possibility that we could end up with a font that
140     // doesn't actually cover the characters we need.
141
142     NSFontManager *fontManager = [NSFontManager sharedFontManager];
143
144     NSFontTraitMask traits;
145     NSInteger weight;
146     CGFloat size;
147
148     if (nsFont) {
149         traits = [fontManager traitsOfFont:nsFont];
150         if (platformData.m_syntheticBold)
151             traits |= NSBoldFontMask;
152         if (platformData.m_syntheticItalic)
153             traits |= NSFontItalicTrait;
154         weight = [fontManager weightOfFont:nsFont];
155         size = [nsFont pointSize];
156     } else {
157         // For custom fonts nsFont is nil.
158         traits = fontDescription.style() ? NSFontItalicTrait : 0;
159         weight = toAppKitFontWeight(fontDescription.weight());
160         size = fontDescription.computedPixelSize();
161     }
162
163     NSFontTraitMask substituteFontTraits = [fontManager traitsOfFont:substituteFont];
164     NSInteger substituteFontWeight = [fontManager weightOfFont:substituteFont];
165
166     if (traits != substituteFontTraits || weight != substituteFontWeight || !nsFont) {
167         if (NSFont *bestVariation = [fontManager fontWithFamily:[substituteFont familyName] traits:traits weight:weight size:size]) {
168             if ((!nsFont || [fontManager traitsOfFont:bestVariation] != substituteFontTraits || [fontManager weightOfFont:bestVariation] != substituteFontWeight)
169                 && [[bestVariation coveredCharacterSet] longCharacterIsMember:character])
170                 substituteFont = bestVariation;
171         }
172     }
173
174     substituteFont = useHinting() ? [substituteFont screenFont] : [substituteFont printerFont];
175
176     substituteFontTraits = [fontManager traitsOfFont:substituteFont];
177     substituteFontWeight = [fontManager weightOfFont:substituteFont];
178
179     FontPlatformData alternateFont(substituteFont, platformData.size(),
180         isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(substituteFontWeight),
181         (traits & NSFontItalicTrait) && !(substituteFontTraits & NSFontItalicTrait),
182         platformData.orientation());
183
184     return fontDataFromFontPlatformData(&alternateFont, DoNotRetain);
185 }
186
187 PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescription& fontDescription, ShouldRetain shouldRetain)
188 {
189     DEFINE_STATIC_LOCAL(AtomicString, timesStr, ("Times", AtomicString::ConstructFromLiteral));
190
191     // FIXME: Would be even better to somehow get the user's default font here.  For now we'll pick
192     // the default that the user would get without changing any prefs.
193     RefPtr<SimpleFontData> simpleFontData = getFontData(fontDescription, timesStr, false, shouldRetain);
194     if (simpleFontData)
195         return simpleFontData.release();
196
197     // The Times fallback will almost always work, but in the highly unusual case where
198     // the user doesn't have it, we fall back on Lucida Grande because that's
199     // guaranteed to be there, according to Nathan Taylor. This is good enough
200     // to avoid a crash at least.
201     DEFINE_STATIC_LOCAL(AtomicString, lucidaGrandeStr, ("Lucida Grande", AtomicString::ConstructFromLiteral));
202     return getFontData(fontDescription, lucidaGrandeStr, false, shouldRetain);
203 }
204
205 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, float fontSize)
206 {
207     NSFontTraitMask traits = fontDescription.style() ? NSFontItalicTrait : 0;
208     NSInteger weight = toAppKitFontWeight(fontDescription.weight());
209     float size = fontSize;
210
211     NSFont *nsFont = [WebFontCache fontWithFamily:creationParams.family() traits:traits weight:weight size:size];
212     if (!nsFont)
213         return 0;
214
215     NSFontManager *fontManager = [NSFontManager sharedFontManager];
216     NSFontTraitMask actualTraits = 0;
217     if (fontDescription.style())
218         actualTraits = [fontManager traitsOfFont:nsFont];
219     NSInteger actualWeight = [fontManager weightOfFont:nsFont];
220
221     NSFont *platformFont = useHinting() ? [nsFont screenFont] : [nsFont printerFont];
222     bool syntheticBold = (isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight)) || fontDescription.isSyntheticBold();
223     bool syntheticItalic = ((traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait)) || fontDescription.isSyntheticItalic();
224
225     // FontPlatformData::font() can be null for the case of Chromium out-of-process font loading.
226     // In that case, we don't want to use the platformData.
227     OwnPtr<FontPlatformData> platformData = adoptPtr(new FontPlatformData(platformFont, size, syntheticBold, syntheticItalic, fontDescription.orientation(), fontDescription.widthVariant()));
228     if (!platformData->font())
229         return 0;
230     return platformData.leakPtr();
231 }
232
233 } // namespace blink