Permalink
Find file
bc42e3a Aug 3, 2016
219 lines (189 sloc) 10.1 KB
/*
* Copyright (C) 2006, 2007, 2008, 2009 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 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 "CoreGraphicsSPI.h"
#import "CoreTextSPI.h"
#import "FontCascade.h"
#import "RenderThemeIOS.h"
#import <wtf/HashSet.h>
#import <wtf/NeverDestroyed.h>
#import <wtf/RetainPtr.h>
#import <wtf/text/CString.h>
namespace WebCore {
void platformInvalidateFontCache()
{
}
bool requiresCustomFallbackFont(UChar32 character)
{
return character == AppleLogo || character == blackCircle || character == narrowNonBreakingSpace;
}
FontPlatformData* FontCache::getCustomFallbackFont(const UInt32 c, const FontDescription& description)
{
ASSERT(requiresCustomFallbackFont(c));
static NeverDestroyed<AtomicString> helveticaFamily("Helvetica Neue", AtomicString::ConstructFromLiteral);
static NeverDestroyed<AtomicString> lockClockFamily("LockClock-Light", AtomicString::ConstructFromLiteral);
static NeverDestroyed<AtomicString> timesNewRomanPSMTFamily("TimesNewRomanPSMT", AtomicString::ConstructFromLiteral);
AtomicString* family = nullptr;
switch (c) {
case AppleLogo:
family = &helveticaFamily.get();
break;
case blackCircle:
family = &lockClockFamily.get();
break;
case narrowNonBreakingSpace:
family = &timesNewRomanPSMTFamily.get();
break;
default:
ASSERT_NOT_REACHED();
return nullptr;
}
ASSERT(family);
if (!family)
return nullptr;
return getCachedFontPlatformData(description, *family);
}
static RetainPtr<CTFontRef> getSystemFontFallbackForCharacters(CTFontRef font, const AtomicString& locale, const UChar* characters, unsigned length)
{
// FIXME: Unify this with platformLookupFallbackFont()
RetainPtr<CFStringRef> localeString;
if (!locale.isNull())
localeString = locale.string().createCFString();
CFIndex coveredLength = 0;
return adoptCF(CTFontCreatePhysicalFontForCharactersWithLanguage(font, (const UTF16Char*)characters, (CFIndex)length, localeString.get(), &coveredLength));
}
RetainPtr<CTFontRef> platformLookupFallbackFont(CTFontRef font, FontWeight fontWeight, const AtomicString& locale, const UChar* characters, unsigned length)
{
// For system fonts we use CoreText fallback mechanism.
if (length && CTFontDescriptorIsSystemUIFont(adoptCF(CTFontCopyFontDescriptor(font)).get()))
return getSystemFontFallbackForCharacters(font, locale, characters, length);
RetainPtr<CFStringRef> localeString;
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000
if (!locale.isNull())
localeString = locale.string().createCFString();
#endif
RetainPtr<CTFontDescriptorRef> fallbackFontDescriptor = adoptCF(CTFontCreatePhysicalFontDescriptorForCharactersWithLanguage(font, characters, length, localeString.get(), nullptr));
UChar32 c = *characters;
if (length > 1 && U16_IS_LEAD(c) && U16_IS_TRAIL(characters[1]))
c = U16_GET_SUPPLEMENTARY(c, characters[1]);
// Arabic
if (c >= 0x0600 && c <= 0x06ff) {
auto familyName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(fallbackFontDescriptor.get(), kCTFontFamilyNameAttribute)));
if (fontFamilyShouldNotBeUsedForArabic(familyName.get())) {
CFStringRef newFamilyName = isFontWeightBold(fontWeight) ? CFSTR("GeezaPro-Bold") : CFSTR("GeezaPro");
CFTypeRef keys[] = { kCTFontNameAttribute };
CFTypeRef values[] = { newFamilyName };
RetainPtr<CFDictionaryRef> attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
fallbackFontDescriptor = adoptCF(CTFontDescriptorCreateCopyWithAttributes(fallbackFontDescriptor.get(), attributes.get()));
}
}
return adoptCF(CTFontCreateWithFontDescriptor(fallbackFontDescriptor.get(), CTFontGetSize(font), nullptr));
}
Ref<Font> FontCache::lastResortFallbackFont(const FontDescription& fontDescription)
{
return *fontForFamily(fontDescription, AtomicString(".PhoneFallback", AtomicString::ConstructFromLiteral));
}
float FontCache::weightOfCTFont(CTFontRef font)
{
RetainPtr<CFDictionaryRef> traits = adoptCF(CTFontCopyTraits(font));
CFNumberRef resultRef = (CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontWeightTrait);
float result = 0;
CFNumberGetValue(resultRef, kCFNumberFloatType, &result);
return result;
}
static RetainPtr<CTFontDescriptorRef> baseSystemFontDescriptor(FontWeight weight, bool bold, float size)
{
CTFontUIFontType fontType = kCTFontUIFontSystem;
if (weight > FontWeight300) {
if (bold)
fontType = kCTFontUIFontEmphasizedSystem;
} else if (weight > FontWeight200)
fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemLight);
else if (weight > FontWeight100)
fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemThin);
else
fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemUltraLight);
return adoptCF(CTFontDescriptorCreateForUIType(fontType, size, nullptr));
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000
static RetainPtr<NSDictionary> systemFontModificationAttributes(FontWeight weight, bool italic)
{
RetainPtr<NSMutableDictionary> traitsDictionary = adoptNS([[NSMutableDictionary alloc] init]);
ASSERT(weight >= FontWeight100 && weight <= FontWeight900);
float ctWeights[] = {
static_cast<float>(kCTFontWeightUltraLight),
static_cast<float>(kCTFontWeightThin),
static_cast<float>(kCTFontWeightLight),
static_cast<float>(kCTFontWeightRegular),
static_cast<float>(kCTFontWeightMedium),
static_cast<float>(kCTFontWeightSemibold),
static_cast<float>(kCTFontWeightBold),
static_cast<float>(kCTFontWeightHeavy),
static_cast<float>(kCTFontWeightBlack)
};
[traitsDictionary setObject:[NSNumber numberWithFloat:ctWeights[weight]] forKey:static_cast<NSString *>(kCTFontWeightTrait)];
[traitsDictionary setObject:@YES forKey:static_cast<NSString *>(kCTFontUIFontDesignTrait)];
if (italic)
[traitsDictionary setObject:[NSNumber numberWithInt:kCTFontItalicTrait] forKey:static_cast<NSString *>(kCTFontSymbolicTrait)];
return @{ static_cast<NSString *>(kCTFontTraitsAttribute) : traitsDictionary.get() };
}
#endif
static RetainPtr<CTFontDescriptorRef> systemFontDescriptor(FontWeight weight, bool bold, bool italic, float size)
{
RetainPtr<CTFontDescriptorRef> fontDescriptor = baseSystemFontDescriptor(weight, bold, size);
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000
RetainPtr<NSDictionary> attributes = systemFontModificationAttributes(weight, italic);
return adoptCF(CTFontDescriptorCreateCopyWithAttributes(fontDescriptor.get(), static_cast<CFDictionaryRef>(attributes.get())));
#else
if (italic)
return adoptCF(CTFontDescriptorCreateCopyWithSymbolicTraits(fontDescriptor.get(), kCTFontItalicTrait, kCTFontItalicTrait));
return fontDescriptor;
#endif
}
RetainPtr<CTFontRef> platformFontWithFamilySpecialCase(const AtomicString& family, FontWeight weight, CTFontSymbolicTraits traits, float size)
{
if (family.startsWith("UICTFontTextStyle")) {
traits &= (kCTFontBoldTrait | kCTFontItalicTrait);
RetainPtr<CFStringRef> familyNameStr = family.string().createCFString();
RetainPtr<CTFontDescriptorRef> fontDescriptor = adoptCF(CTFontDescriptorCreateWithTextStyle(familyNameStr.get(), RenderThemeIOS::contentSizeCategory(), nullptr));
if (traits)
fontDescriptor = adoptCF(CTFontDescriptorCreateCopyWithSymbolicTraits(fontDescriptor.get(), traits, traits));
return adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor.get(), size, nullptr));
}
if (equalLettersIgnoringASCIICase(family, "-webkit-system-font") || equalLettersIgnoringASCIICase(family, "-apple-system") || equalLettersIgnoringASCIICase(family, "-apple-system-font")) {
return adoptCF(CTFontCreateWithFontDescriptor(systemFontDescriptor(weight, traits & kCTFontTraitBold, traits & kCTFontTraitItalic, size).get(), size, nullptr));
}
if (equalLettersIgnoringASCIICase(family, "-apple-system-monospaced-numbers")) {
RetainPtr<CTFontDescriptorRef> systemFontDescriptor = adoptCF(CTFontDescriptorCreateForUIType(kCTFontUIFontSystem, size, nullptr));
RetainPtr<CTFontDescriptorRef> monospaceFontDescriptor = adoptCF(CTFontDescriptorCreateCopyWithFeature(systemFontDescriptor.get(), (CFNumberRef)@(kNumberSpacingType), (CFNumberRef)@(kMonospacedNumbersSelector)));
return adoptCF(CTFontCreateWithFontDescriptor(monospaceFontDescriptor.get(), size, nullptr));
}
return nullptr;
}
} // namespace WebCore