OLD | NEW |
| (Empty) |
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 "core/platform/graphics/FontCache.h" | |
32 | |
33 #import <AppKit/AppKit.h> | |
34 #import "core/platform/graphics/FontPlatformData.h" | |
35 #import "core/platform/graphics/SimpleFontData.h" | |
36 #import "platform/fonts/FontDescription.h" | |
37 #import "platform/mac/WebFontCache.h" | |
38 #import <wtf/MainThread.h> | |
39 #import <wtf/StdLibExtras.h> | |
40 | |
41 // Forward declare Mac SPIs. | |
42 // Request for public API: rdar://13803570 | |
43 @interface NSFont (WebKitSPI) | |
44 + (NSFont*)findFontLike:(NSFont*)font forString:(NSString*)string withRange:(NSR
ange)range inLanguage:(id)useNil; | |
45 + (NSFont*)findFontLike:(NSFont*)font forCharacter:(UniChar)uc inLanguage:(id)us
eNil; | |
46 @end | |
47 | |
48 namespace WebCore { | |
49 | |
50 // The "void*" parameter makes the function match the prototype for callbacks fr
om callOnMainThread. | |
51 static void invalidateFontCache(void*) | |
52 { | |
53 if (!isMainThread()) { | |
54 callOnMainThread(&invalidateFontCache, 0); | |
55 return; | |
56 } | |
57 fontCache()->invalidate(); | |
58 } | |
59 | |
60 static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCe
nterRef, void* observer, CFStringRef name, const void *, CFDictionaryRef) | |
61 { | |
62 ASSERT_UNUSED(observer, observer == fontCache()); | |
63 ASSERT_UNUSED(name, CFEqual(name, kCTFontManagerRegisteredFontsChangedNotifi
cation)); | |
64 invalidateFontCache(0); | |
65 } | |
66 | |
67 void FontCache::platformInit() | |
68 { | |
69 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this,
fontCacheRegisteredFontsChangedNotificationCallback, kCTFontManagerRegisteredFon
tsChangedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately); | |
70 } | |
71 | |
72 static int toAppKitFontWeight(FontWeight fontWeight) | |
73 { | |
74 static int appKitFontWeights[] = { | |
75 2, // FontWeight100 | |
76 3, // FontWeight200 | |
77 4, // FontWeight300 | |
78 5, // FontWeight400 | |
79 6, // FontWeight500 | |
80 8, // FontWeight600 | |
81 9, // FontWeight700 | |
82 10, // FontWeight800 | |
83 12, // FontWeight900 | |
84 }; | |
85 return appKitFontWeights[fontWeight]; | |
86 } | |
87 | |
88 static inline bool isAppKitFontWeightBold(NSInteger appKitFontWeight) | |
89 { | |
90 return appKitFontWeight >= 7; | |
91 } | |
92 | |
93 PassRefPtr<SimpleFontData> FontCache::platformFallbackForCharacter(const FontDes
cription& fontDescription, UChar32 character, const SimpleFontData* fontDataToSu
bstitute, bool disallowSynthetics) | |
94 { | |
95 // FIXME: We should fix getFallbackFamily to take a UChar32 | |
96 // and remove this split-to-UChar16 code. | |
97 UChar codeUnits[2]; | |
98 int codeUnitsLength; | |
99 if (character <= 0xFFFF) { | |
100 codeUnits[0] = character; | |
101 codeUnitsLength = 1; | |
102 } else { | |
103 codeUnits[0] = U16_LEAD(character); | |
104 codeUnits[1] = U16_TRAIL(character); | |
105 codeUnitsLength = 2; | |
106 } | |
107 | |
108 const FontPlatformData& platformData = fontDataToSubstitute->platformData(); | |
109 NSFont *nsFont = platformData.font(); | |
110 | |
111 NSString *string = [[NSString alloc] initWithCharactersNoCopy:codeUnits leng
th:codeUnitsLength freeWhenDone:NO]; | |
112 NSFont *substituteFont = [NSFont findFontLike:nsFont forString:string withRa
nge:NSMakeRange(0, codeUnitsLength) inLanguage:nil]; | |
113 [string release]; | |
114 | |
115 // FIXME: Remove this SPI usage: http://crbug.com/255122 | |
116 if (!substituteFont && codeUnitsLength == 1) | |
117 substituteFont = [NSFont findFontLike:nsFont forCharacter:codeUnits[0] i
nLanguage:nil]; | |
118 if (!substituteFont) | |
119 return 0; | |
120 | |
121 // Chromium can't render AppleColorEmoji. | |
122 if ([[substituteFont familyName] isEqual:@"Apple Color Emoji"]) | |
123 return 0; | |
124 | |
125 // Use the family name from the AppKit-supplied substitute font, requesting
the | |
126 // traits, weight, and size we want. One way this does better than the origi
nal | |
127 // AppKit request is that it takes synthetic bold and oblique into account. | |
128 // But it does create the possibility that we could end up with a font that | |
129 // doesn't actually cover the characters we need. | |
130 | |
131 NSFontManager *fontManager = [NSFontManager sharedFontManager]; | |
132 | |
133 NSFontTraitMask traits; | |
134 NSInteger weight; | |
135 CGFloat size; | |
136 | |
137 if (nsFont) { | |
138 traits = [fontManager traitsOfFont:nsFont]; | |
139 if (platformData.m_syntheticBold) | |
140 traits |= NSBoldFontMask; | |
141 if (platformData.m_syntheticOblique) | |
142 traits |= NSFontItalicTrait; | |
143 weight = [fontManager weightOfFont:nsFont]; | |
144 size = [nsFont pointSize]; | |
145 } else { | |
146 // For custom fonts nsFont is nil. | |
147 traits = fontDescription.italic() ? NSFontItalicTrait : 0; | |
148 weight = toAppKitFontWeight(fontDescription.weight()); | |
149 size = fontDescription.computedPixelSize(); | |
150 } | |
151 | |
152 NSFontTraitMask substituteFontTraits = [fontManager traitsOfFont:substituteF
ont]; | |
153 NSInteger substituteFontWeight = [fontManager weightOfFont:substituteFont]; | |
154 | |
155 if (traits != substituteFontTraits || weight != substituteFontWeight || !nsF
ont) { | |
156 if (NSFont *bestVariation = [fontManager fontWithFamily:[substituteFont
familyName] traits:traits weight:weight size:size]) { | |
157 if (!nsFont || (([fontManager traitsOfFont:bestVariation] != substit
uteFontTraits || [fontManager weightOfFont:bestVariation] != substituteFontWeigh
t) | |
158 && [[bestVariation coveredCharacterSet] longCharacterIsMember:ch
aracter])) | |
159 substituteFont = bestVariation; | |
160 } | |
161 } | |
162 | |
163 substituteFont = fontDescription.usePrinterFont() ? [substituteFont printerF
ont] : [substituteFont screenFont]; | |
164 | |
165 substituteFontTraits = [fontManager traitsOfFont:substituteFont]; | |
166 substituteFontWeight = [fontManager weightOfFont:substituteFont]; | |
167 | |
168 FontPlatformData alternateFont(substituteFont, platformData.size(), platform
Data.isPrinterFont(), | |
169 !disallowSynthetics && isAppKitFontWeightBold(weight) && !isAppKitFontWe
ightBold(substituteFontWeight), | |
170 !disallowSynthetics && (traits & NSFontItalicTrait) && !(substituteFontT
raits & NSFontItalicTrait), | |
171 platformData.m_orientation); | |
172 | |
173 return fontDataFromFontPlatformData(&alternateFont, DoNotRetain); | |
174 } | |
175 | |
176 PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescri
ption& fontDescription, ShouldRetain shouldRetain) | |
177 { | |
178 DEFINE_STATIC_LOCAL(AtomicString, timesStr, ("Times", AtomicString::Construc
tFromLiteral)); | |
179 | |
180 // FIXME: Would be even better to somehow get the user's default font here.
For now we'll pick | |
181 // the default that the user would get without changing any prefs. | |
182 RefPtr<SimpleFontData> simpleFontData = getFontData(fontDescription, timesSt
r, false, shouldRetain); | |
183 if (simpleFontData) | |
184 return simpleFontData.release(); | |
185 | |
186 // The Times fallback will almost always work, but in the highly unusual cas
e where | |
187 // the user doesn't have it, we fall back on Lucida Grande because that's | |
188 // guaranteed to be there, according to Nathan Taylor. This is good enough | |
189 // to avoid a crash at least. | |
190 DEFINE_STATIC_LOCAL(AtomicString, lucidaGrandeStr, ("Lucida Grande", AtomicS
tring::ConstructFromLiteral)); | |
191 return getFontData(fontDescription, lucidaGrandeStr, false, shouldRetain); | |
192 } | |
193 | |
194 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
escription, const AtomicString& family, float fontSize) | |
195 { | |
196 NSFontTraitMask traits = fontDescription.italic() ? NSFontItalicTrait : 0; | |
197 NSInteger weight = toAppKitFontWeight(fontDescription.weight()); | |
198 float size = fontSize; | |
199 | |
200 NSFont *nsFont = [WebFontCache fontWithFamily:family traits:traits weight:we
ight size:size]; | |
201 if (!nsFont) | |
202 return 0; | |
203 | |
204 NSFontManager *fontManager = [NSFontManager sharedFontManager]; | |
205 NSFontTraitMask actualTraits = 0; | |
206 if (fontDescription.italic()) | |
207 actualTraits = [fontManager traitsOfFont:nsFont]; | |
208 NSInteger actualWeight = [fontManager weightOfFont:nsFont]; | |
209 | |
210 NSFont *platformFont = fontDescription.usePrinterFont() ? [nsFont printerFon
t] : [nsFont screenFont]; | |
211 bool syntheticBold = (isAppKitFontWeightBold(weight) && !isAppKitFontWeightB
old(actualWeight)) || fontDescription.isSyntheticBold(); | |
212 bool syntheticOblique = ((traits & NSFontItalicTrait) && !(actualTraits & NS
FontItalicTrait)) || fontDescription.isSyntheticItalic(); | |
213 | |
214 // FontPlatformData::font() can be null for the case of Chromium out-of-proc
ess font loading. | |
215 // In that case, we don't want to use the platformData. | |
216 OwnPtr<FontPlatformData> platformData = adoptPtr(new FontPlatformData(platfo
rmFont, size, fontDescription.usePrinterFont(), syntheticBold, syntheticOblique,
fontDescription.orientation(), fontDescription.widthVariant())); | |
217 if (!platformData->font()) | |
218 return 0; | |
219 return platformData.leakPtr(); | |
220 } | |
221 | |
222 } // namespace WebCore | |
OLD | NEW |