blob: ce3f8db1c12a0909dbf55dc85d6490e9c889b62e [file] [log] [blame]
/*
* 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"
#if PLATFORM(IOS_FAMILY)
#import "FontCascade.h"
#import "RenderThemeIOS.h"
#import "SystemFontDatabaseCoreText.h"
#import <pal/spi/cg/CoreGraphicsSPI.h>
#import <pal/spi/cocoa/CoreTextSPI.h>
#import <wtf/HashSet.h>
#import <wtf/NeverDestroyed.h>
#import <wtf/RetainPtr.h>
#import <wtf/SoftLinking.h>
#import <wtf/text/CString.h>
namespace WebCore {
bool requiresCustomFallbackFont(UChar32 character)
{
return character == AppleLogo || character == narrowNonBreakingSpace;
}
FontPlatformData* FontCache::getCustomFallbackFont(const UInt32 c, const FontDescription& description)
{
ASSERT(requiresCustomFallbackFont(c));
static NeverDestroyed<AtomString> helveticaFamily("Helvetica Neue", AtomString::ConstructFromLiteral);
static NeverDestroyed<AtomString> timesNewRomanPSMTFamily("TimesNewRomanPSMT", AtomString::ConstructFromLiteral);
AtomString* family = nullptr;
switch (c) {
case AppleLogo:
family = &helveticaFamily.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<CTFontDescriptorRef> baseSystemFontDescriptor(FontSelectionValue weight, bool bold, float size)
{
CTFontUIFontType fontType = kCTFontUIFontSystem;
if (weight >= FontSelectionValue(350)) {
if (bold)
fontType = kCTFontUIFontEmphasizedSystem;
} else if (weight >= FontSelectionValue(250))
fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemLight);
else if (weight >= FontSelectionValue(150))
fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemThin);
else
fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemUltraLight);
return adoptCF(CTFontDescriptorCreateForUIType(fontType, size, nullptr));
}
static RetainPtr<NSDictionary> systemFontModificationAttributes(FontSelectionValue weight, bool italic)
{
RetainPtr<NSMutableDictionary> traitsDictionary = adoptNS([[NSMutableDictionary alloc] init]);
float ctWeight = kCTFontWeightRegular;
if (weight < FontSelectionValue(150))
ctWeight = kCTFontWeightUltraLight;
else if (weight < FontSelectionValue(250))
ctWeight = kCTFontWeightThin;
else if (weight < FontSelectionValue(350))
ctWeight = kCTFontWeightLight;
else if (weight < FontSelectionValue(450))
ctWeight = kCTFontWeightRegular;
else if (weight < FontSelectionValue(550))
ctWeight = kCTFontWeightMedium;
else if (weight < FontSelectionValue(650))
ctWeight = kCTFontWeightSemibold;
else if (weight < FontSelectionValue(750))
ctWeight = kCTFontWeightBold;
else if (weight < FontSelectionValue(850))
ctWeight = kCTFontWeightHeavy;
else
ctWeight = kCTFontWeightBlack;
[traitsDictionary setObject:[NSNumber numberWithFloat:ctWeight] 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() };
}
static RetainPtr<CTFontDescriptorRef> systemFontDescriptor(FontSelectionValue weight, bool bold, bool italic, float size)
{
RetainPtr<CTFontDescriptorRef> fontDescriptor = baseSystemFontDescriptor(weight, bold, size);
RetainPtr<NSDictionary> attributes = systemFontModificationAttributes(weight, italic);
return adoptCF(CTFontDescriptorCreateCopyWithAttributes(fontDescriptor.get(), static_cast<CFDictionaryRef>(attributes.get())));
}
RetainPtr<CTFontRef> platformFontWithFamilySpecialCase(const AtomString& family, const FontDescription& fontDescription, float size, AllowUserInstalledFonts allowUserInstalledFonts)
{
// FIXME: See comment in FontCascadeDescription::effectiveFamilyAt() in FontDescriptionCocoa.cpp
const auto& request = fontDescription.fontSelectionRequest();
if (family.startsWith("UICTFontTextStyle")) {
CTFontSymbolicTraits traits = (isFontWeightBold(request.weight) || FontCache::singleton().shouldMockBoldSystemFontForAccessibility() ? kCTFontTraitBold : 0) | (isItalic(request.slope) ? kCTFontTraitItalic : 0);
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 createFontForInstalledFonts(fontDescriptor.get(), size, allowUserInstalledFonts);
}
// FIXME: Migrate this to use SystemFontDatabaseCoreText like the design system-ui block below.
if (equalLettersIgnoringASCIICase(family, "-webkit-system-font") || equalLettersIgnoringASCIICase(family, "-apple-system") || equalLettersIgnoringASCIICase(family, "-apple-system-font") || equalLettersIgnoringASCIICase(family, "system-ui")) {
auto fontDescriptor = systemFontDescriptor(request.weight, isFontWeightBold(request.weight), isItalic(request.slope), size);
return createFontForInstalledFonts(fontDescriptor.get(), size, allowUserInstalledFonts);
}
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 createFontForInstalledFonts(monospaceFontDescriptor.get(), size, allowUserInstalledFonts);
}
if (equalLettersIgnoringASCIICase(family, "lastresort")) {
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
static const CTFontDescriptorRef lastResort = CTFontDescriptorCreateLastResort();
return adoptCF(CTFontCreateWithFontDescriptor(lastResort, size, nullptr));
#else
// LastResort is special, so it's important to look this exact string up, and not some case-folded version.
// We handle this here so any caching and case folding we do in our general text codepath is bypassed.
return adoptCF(CTFontCreateWithName(CFSTR("LastResort"), size, nullptr));
#endif
}
return nullptr;
}
} // namespace WebCore
#endif // PLATFORM(IOS_FAMILY)