| 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 |