/* * 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 = ×NewRomanPSMTFamily.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)