Improve use of NeverDestroyed
[WebKit-https.git] / Source / WebCore / platform / graphics / ios / FontCacheIOS.mm
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "config.h"
30 #import "FontCache.h"
31
32 #import "CoreGraphicsSPI.h"
33 #import "CoreTextSPI.h"
34 #import "FontCascade.h"
35 #import "RenderThemeIOS.h"
36 #import <wtf/HashSet.h>
37 #import <wtf/NeverDestroyed.h>
38 #import <wtf/RetainPtr.h>
39 #import <wtf/SoftLinking.h>
40 #import <wtf/text/CString.h>
41
42 namespace WebCore {
43
44 bool requiresCustomFallbackFont(UChar32 character)
45 {
46     return character == AppleLogo || character == blackCircle || character == narrowNonBreakingSpace;
47 }
48
49 FontPlatformData* FontCache::getCustomFallbackFont(const UInt32 c, const FontDescription& description)
50 {
51     ASSERT(requiresCustomFallbackFont(c));
52
53     static NeverDestroyed<AtomicString> helveticaFamily("Helvetica Neue", AtomicString::ConstructFromLiteral);
54     static NeverDestroyed<AtomicString> lockClockFamily("LockClock-Light", AtomicString::ConstructFromLiteral);
55     static NeverDestroyed<AtomicString> timesNewRomanPSMTFamily("TimesNewRomanPSMT", AtomicString::ConstructFromLiteral);
56
57     AtomicString* family = nullptr;
58     switch (c) {
59     case AppleLogo:
60         family = &helveticaFamily.get();
61         break;
62     case blackCircle:
63         family = &lockClockFamily.get();
64         break;
65     case narrowNonBreakingSpace:
66         family = &timesNewRomanPSMTFamily.get();
67         break;
68     default:
69         ASSERT_NOT_REACHED();
70         return nullptr;
71     }
72     ASSERT(family);
73     if (!family)
74         return nullptr;
75     return getCachedFontPlatformData(description, *family);
76 }
77
78 Ref<Font> FontCache::lastResortFallbackFont(const FontDescription& fontDescription)
79 {
80     return *fontForFamily(fontDescription, AtomicString(".PhoneFallback", AtomicString::ConstructFromLiteral));
81 }
82
83 static RetainPtr<CTFontDescriptorRef> baseSystemFontDescriptor(FontSelectionValue weight, bool bold, float size)
84 {
85     CTFontUIFontType fontType = kCTFontUIFontSystem;
86     if (weight >= FontSelectionValue(350)) {
87         if (bold)
88             fontType = kCTFontUIFontEmphasizedSystem;
89     } else if (weight >= FontSelectionValue(250))
90         fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemLight);
91     else if (weight >= FontSelectionValue(150))
92         fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemThin);
93     else
94         fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemUltraLight);
95     return adoptCF(CTFontDescriptorCreateForUIType(fontType, size, nullptr));
96 }
97
98 static RetainPtr<NSDictionary> systemFontModificationAttributes(FontSelectionValue weight, bool italic)
99 {
100     RetainPtr<NSMutableDictionary> traitsDictionary = adoptNS([[NSMutableDictionary alloc] init]);
101
102     float ctWeight = kCTFontWeightRegular;
103     if (weight < FontSelectionValue(150))
104         ctWeight = kCTFontWeightUltraLight;
105     else if (weight < FontSelectionValue(250))
106         ctWeight = kCTFontWeightThin;
107     else if (weight < FontSelectionValue(350))
108         ctWeight = kCTFontWeightLight;
109     else if (weight < FontSelectionValue(450))
110         ctWeight = kCTFontWeightRegular;
111     else if (weight < FontSelectionValue(550))
112         ctWeight = kCTFontWeightMedium;
113     else if (weight < FontSelectionValue(650))
114         ctWeight = kCTFontWeightSemibold;
115     else if (weight < FontSelectionValue(750))
116         ctWeight = kCTFontWeightBold;
117     else if (weight < FontSelectionValue(850))
118         ctWeight = kCTFontWeightHeavy;
119     else
120         ctWeight = kCTFontWeightBlack;
121     [traitsDictionary setObject:[NSNumber numberWithFloat:ctWeight] forKey:static_cast<NSString *>(kCTFontWeightTrait)];
122
123     [traitsDictionary setObject:@YES forKey:static_cast<NSString *>(kCTFontUIFontDesignTrait)];
124
125     if (italic)
126         [traitsDictionary setObject:[NSNumber numberWithInt:kCTFontItalicTrait] forKey:static_cast<NSString *>(kCTFontSymbolicTrait)];
127
128     return @{ static_cast<NSString *>(kCTFontTraitsAttribute) : traitsDictionary.get() };
129 }
130
131 static RetainPtr<CTFontDescriptorRef> systemFontDescriptor(FontSelectionValue weight, bool bold, bool italic, float size)
132 {
133     RetainPtr<CTFontDescriptorRef> fontDescriptor = baseSystemFontDescriptor(weight, bold, size);
134     RetainPtr<NSDictionary> attributes = systemFontModificationAttributes(weight, italic);
135     return adoptCF(CTFontDescriptorCreateCopyWithAttributes(fontDescriptor.get(), static_cast<CFDictionaryRef>(attributes.get())));
136 }
137
138 RetainPtr<CTFontRef> platformFontWithFamilySpecialCase(const AtomicString& family, FontSelectionRequest request, float size)
139 {
140     // FIXME: See comment in FontCascadeDescription::effectiveFamilyAt() in FontDescriptionCocoa.cpp
141     if (family.startsWith("UICTFontTextStyle")) {
142         CTFontSymbolicTraits traits = (isFontWeightBold(request.weight) || FontCache::singleton().shouldMockBoldSystemFontForAccessibility() ? kCTFontTraitBold : 0) | (isItalic(request.slope) ? kCTFontTraitItalic : 0);
143         RetainPtr<CFStringRef> familyNameStr = family.string().createCFString();
144         RetainPtr<CTFontDescriptorRef> fontDescriptor = adoptCF(CTFontDescriptorCreateWithTextStyle(familyNameStr.get(), RenderThemeIOS::contentSizeCategory(), nullptr));
145         if (traits)
146             fontDescriptor = adoptCF(CTFontDescriptorCreateCopyWithSymbolicTraits(fontDescriptor.get(), traits, traits));
147
148         return adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor.get(), size, nullptr));
149     }
150
151     if (equalLettersIgnoringASCIICase(family, "-webkit-system-font") || equalLettersIgnoringASCIICase(family, "-apple-system") || equalLettersIgnoringASCIICase(family, "-apple-system-font") || equalLettersIgnoringASCIICase(family, "system-ui")) {
152         return adoptCF(CTFontCreateWithFontDescriptor(systemFontDescriptor(request.weight, isFontWeightBold(request.weight), isItalic(request.slope), size).get(), size, nullptr));
153     }
154
155     if (equalLettersIgnoringASCIICase(family, "-apple-system-monospaced-numbers")) {
156         RetainPtr<CTFontDescriptorRef> systemFontDescriptor = adoptCF(CTFontDescriptorCreateForUIType(kCTFontUIFontSystem, size, nullptr));
157         RetainPtr<CTFontDescriptorRef> monospaceFontDescriptor = adoptCF(CTFontDescriptorCreateCopyWithFeature(systemFontDescriptor.get(), (CFNumberRef)@(kNumberSpacingType), (CFNumberRef)@(kMonospacedNumbersSelector)));
158         return adoptCF(CTFontCreateWithFontDescriptor(monospaceFontDescriptor.get(), size, nullptr));
159     }
160
161     if (equalLettersIgnoringASCIICase(family, "lastresort")) {
162 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
163         static const CTFontDescriptorRef lastResort = CTFontDescriptorCreateLastResort();
164         return adoptCF(CTFontCreateWithFontDescriptor(lastResort, size, nullptr));
165 #else
166         // LastResort is special, so it's important to look this exact string up, and not some case-folded version.
167         // We handle this here so any caching and case folding we do in our general text codepath is bypassed.
168         return adoptCF(CTFontCreateWithName(CFSTR("LastResort"), size, nullptr));
169 #endif
170     }
171
172     return nullptr;
173 }
174
175 } // namespace WebCore