| /* |
| * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
| * its contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #import "config.h" |
| #import "FontCache.h" |
| |
| #import "Font.h" |
| #import "FontData.h" |
| #import "FontPlatformData.h" |
| #import "WebCoreSystemInterface.h" |
| #import "WebFontCache.h" |
| |
| namespace WebCore { |
| |
| static bool getAppDefaultValue(CFStringRef key, int *v) |
| { |
| CFPropertyListRef value; |
| |
| value = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication, |
| kCFPreferencesAnyUser, |
| kCFPreferencesAnyHost); |
| if (value == 0) { |
| value = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication, |
| kCFPreferencesCurrentUser, |
| kCFPreferencesAnyHost); |
| if (value == 0) |
| return false; |
| } |
| |
| if (CFGetTypeID(value) == CFNumberGetTypeID()) { |
| if (v != 0) |
| CFNumberGetValue((const CFNumberRef)value, kCFNumberIntType, v); |
| } else if (CFGetTypeID(value) == CFStringGetTypeID()) { |
| if (v != 0) |
| *v = CFStringGetIntValue((const CFStringRef)value); |
| } else { |
| CFRelease(value); |
| return false; |
| } |
| |
| CFRelease(value); |
| return true; |
| } |
| |
| static bool getUserDefaultValue(CFStringRef key, int *v) |
| { |
| CFPropertyListRef value; |
| |
| value = CFPreferencesCopyValue(key, kCFPreferencesAnyApplication, |
| kCFPreferencesCurrentUser, |
| kCFPreferencesCurrentHost); |
| if (value == 0) |
| return false; |
| |
| if (CFGetTypeID(value) == CFNumberGetTypeID()) { |
| if (v != 0) |
| CFNumberGetValue((const CFNumberRef)value, kCFNumberIntType, v); |
| } else if (CFGetTypeID(value) == CFStringGetTypeID()) { |
| if (v != 0) |
| *v = CFStringGetIntValue((const CFStringRef)value); |
| } else { |
| CFRelease(value); |
| return false; |
| } |
| |
| CFRelease(value); |
| return true; |
| } |
| |
| static int getLCDScaleParameters(void) |
| { |
| int mode; |
| CFStringRef key; |
| |
| key = CFSTR("AppleFontSmoothing"); |
| if (!getAppDefaultValue(key, &mode)) { |
| if (!getUserDefaultValue(key, &mode)) |
| return 1; |
| } |
| |
| if (wkFontSmoothingModeIsLCD(mode)) |
| return 4; |
| return 1; |
| } |
| |
| #define MINIMUM_GLYPH_CACHE_SIZE 1536 * 1024 |
| |
| void FontCache::platformInit() |
| { |
| size_t s = MINIMUM_GLYPH_CACHE_SIZE*getLCDScaleParameters(); |
| |
| wkSetUpFontCache(s); |
| } |
| |
| const FontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) |
| { |
| const FontPlatformData& platformData = font.primaryFont()->platformData(); |
| NSFont *nsFont = platformData.font(); |
| |
| NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(characters) |
| length:length freeWhenDone:NO]; |
| NSFont *substituteFont = wkGetFontInLanguageForRange(nsFont, string, NSMakeRange(0, length)); |
| [string release]; |
| |
| if (!substituteFont && length == 1) |
| substituteFont = wkGetFontInLanguageForCharacter(nsFont, characters[0]); |
| if (!substituteFont) |
| return 0; |
| |
| // Use the family name from the AppKit-supplied substitute font, requesting the |
| // traits, weight, and size we want. One way this does better than the original |
| // AppKit request is that it takes synthetic bold and oblique into account. |
| // But it does create the possibility that we could end up with a font that |
| // doesn't actually cover the characters we need. |
| |
| NSFontManager *manager = [NSFontManager sharedFontManager]; |
| |
| NSFontTraitMask traits = [manager traitsOfFont:nsFont]; |
| if (platformData.syntheticBold) |
| traits |= NSBoldFontMask; |
| if (platformData.syntheticOblique) |
| traits |= NSItalicFontMask; |
| |
| NSFont *bestVariation = [manager fontWithFamily:[substituteFont familyName] |
| traits:traits |
| weight:[manager weightOfFont:nsFont] |
| size:[nsFont pointSize]]; |
| if (bestVariation) |
| substituteFont = bestVariation; |
| |
| substituteFont = font.fontDescription().usePrinterFont() |
| ? [substituteFont printerFont] : [substituteFont screenFont]; |
| |
| NSFontTraitMask substituteFontTraits = [manager traitsOfFont:substituteFont]; |
| |
| FontPlatformData alternateFont(substituteFont, |
| !font.isPlatformFont() && (traits & NSBoldFontMask) && !(substituteFontTraits & NSBoldFontMask), |
| !font.isPlatformFont() && (traits & NSItalicFontMask) && !(substituteFontTraits & NSItalicFontMask)); |
| return getCachedFontData(&alternateFont); |
| } |
| |
| FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) |
| { |
| // Attempt to find an appropriate font using a match based on |
| // the presence of keywords in the the requested names. For example, we'll |
| // match any name that contains "Arabic" to Geeza Pro. |
| FontPlatformData* platformData = 0; |
| const FontFamily* currFamily = &font.fontDescription().family(); |
| while (currFamily && !platformData) { |
| if (currFamily->family().length()) { |
| static String matchWords[3] = { String("Arabic"), String("Pashto"), String("Urdu") }; |
| static AtomicString geezaStr("Geeza Pro"); |
| for (int j = 0; j < 3 && !platformData; ++j) |
| if (currFamily->family().contains(matchWords[j], false)) |
| platformData = getCachedFontPlatformData(font.fontDescription(), geezaStr); |
| } |
| currFamily = currFamily->next(); |
| } |
| |
| return platformData; |
| } |
| |
| FontPlatformData* FontCache::getLastResortFallbackFont(const Font& font) |
| { |
| static AtomicString timesStr("Times"); |
| static AtomicString lucidaGrandeStr("Lucida Grande"); |
| |
| // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick |
| // the default that the user would get without changing any prefs. |
| FontPlatformData* platformFont = getCachedFontPlatformData(font.fontDescription(), timesStr); |
| if (!platformFont) |
| // The Times fallback will almost always work, but in the highly unusual case where |
| // the user doesn't have it, we fall back on Lucida Grande because that's |
| // guaranteed to be there, according to Nathan Taylor. This is good enough |
| // to avoid a crash at least. |
| platformFont = getCachedFontPlatformData(font.fontDescription(), lucidaGrandeStr); |
| |
| return platformFont; |
| } |
| |
| FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) |
| { |
| NSFontTraitMask traits = 0; |
| if (fontDescription.italic()) |
| traits |= NSItalicFontMask; |
| if (fontDescription.bold()) |
| traits |= NSBoldFontMask; |
| float size = fontDescription.computedPixelSize(); |
| |
| NSFont* nsFont = [WebFontCache fontWithFamily:family traits:traits size:size]; |
| if (!nsFont) |
| return 0; |
| |
| NSFontTraitMask actualTraits = 0; |
| if (fontDescription.bold() || fontDescription.italic()) |
| actualTraits = [[NSFontManager sharedFontManager] traitsOfFont:nsFont]; |
| |
| FontPlatformData* result = new FontPlatformData; |
| |
| // Use the correct font for print vs. screen. |
| result->setFont(fontDescription.usePrinterFont() ? [nsFont printerFont] : [nsFont screenFont]); |
| result->syntheticBold = (traits & NSBoldFontMask) && !(actualTraits & NSBoldFontMask); |
| result->syntheticOblique = (traits & NSItalicFontMask) && !(actualTraits & NSItalicFontMask); |
| return result; |
| } |
| |
| } // namespace WebCore |