Web Inspector: Add VisualStyleSelectorSection
[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/NeverDestroyed.h>
37 #import <wtf/RetainPtr.h>
38 #import <wtf/text/CString.h>
39
40 namespace WebCore {
41
42 void FontCache::platformInit()
43 {
44 }
45
46 static inline bool isFontWeightBold(NSInteger fontWeight)
47 {
48     return fontWeight >= FontWeight600;
49 }
50
51 static inline bool requiresCustomFallbackFont(const UInt32 character)
52 {
53     return character == AppleLogo || character == blackCircle || character == narrowNonBreakingSpace;
54 }
55
56 #if __IPHONE_OS_VERSION_MIN_REQUIRED < 90000
57 static CFCharacterSetRef copyFontCharacterSet(CFStringRef fontName)
58 {
59     // The size, 10, is arbitrary.
60     RetainPtr<CTFontDescriptorRef> fontDescriptor = adoptCF(CTFontDescriptorCreateWithNameAndSize(fontName, 10));
61     RetainPtr<CTFontRef> font = adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor.get(), 10, nullptr));
62     return (CFCharacterSetRef)CTFontDescriptorCopyAttribute(fontDescriptor.get(), kCTFontCharacterSetAttribute);
63 }
64
65 static CFCharacterSetRef appleColorEmojiCharacterSet()
66 {
67     static CFCharacterSetRef characterSet = copyFontCharacterSet(CFSTR("AppleColorEmoji"));
68     return characterSet;
69 }
70
71 static CFCharacterSetRef phoneFallbackCharacterSet()
72 {
73     static CFCharacterSetRef characterSet = copyFontCharacterSet(CFSTR(".PhoneFallback"));
74     return characterSet;
75 }
76 #endif
77
78 PassRefPtr<Font> FontCache::getSystemFontFallbackForCharacters(const FontDescription& description, const Font* originalFontData, const UChar* characters, unsigned length)
79 {
80     const FontPlatformData& platformData = originalFontData->platformData();
81     CTFontRef ctFont = platformData.font();
82
83     RetainPtr<CFStringRef> localeString;
84 #if __IPHONE_OS_VERSION_MIN_REQUIRED > 90000
85     if (!description.locale().isNull())
86         localeString = description.locale().string().createCFString();
87 #endif
88
89     CFIndex coveredLength = 0;
90     RetainPtr<CTFontRef> substituteFont = adoptCF(CTFontCreatePhysicalFontForCharactersWithLanguage(ctFont, (const UTF16Char*)characters, (CFIndex)length, localeString.get(), &coveredLength));
91     if (!substituteFont)
92         return nullptr;
93
94     substituteFont = applyFontFeatureSettings(substituteFont.get(), description.featureSettings());
95
96     CTFontSymbolicTraits originalTraits = CTFontGetSymbolicTraits(ctFont);
97     CTFontSymbolicTraits actualTraits = 0;
98     if (isFontWeightBold(description.weight()) || description.italic())
99         actualTraits = CTFontGetSymbolicTraits(substituteFont.get());
100
101     bool syntheticBold = (originalTraits & kCTFontTraitBold) && !(actualTraits & kCTFontTraitBold);
102     bool syntheticOblique = (originalTraits & kCTFontTraitItalic) && !(actualTraits & kCTFontTraitItalic);
103
104     FontPlatformData alternateFont(substituteFont.get(), platformData.size(), syntheticBold, syntheticOblique, platformData.m_orientation);
105     alternateFont.setIsEmoji(CTFontIsAppleColorEmoji(substituteFont.get()));
106
107     return fontForPlatformData(alternateFont);
108 }
109
110 #if __IPHONE_OS_VERSION_MIN_REQUIRED < 90000
111 enum class LanguageSpecificFont {
112     None,
113     ChineseJapanese,
114     Korean,
115     Cyrillic,
116     Arabic,
117     Hebrew,
118     Indic,
119     Thai,
120     Lao,
121     Tibetan,
122     CanadianAboriginalSyllabic,
123     Khmer,
124     Emoji,
125 };
126
127 static LanguageSpecificFont languageSpecificFallbackFont(UChar32 c)
128 {
129     static bool isGB18030ComplianceRequired = wkIsGB18030ComplianceRequired();
130
131     // The following ranges are Korean Hangul and should be rendered by AppleSDGothicNeo
132     // U+1100 - U+11FF
133     // U+3130 - U+318F
134     // U+AC00 - U+D7A3
135
136     // These are Cyrillic and should be rendered by Helvetica Neue
137     // U+0400 - U+052F
138
139     if (c < 0x400)
140         return LanguageSpecificFont::None;
141     if (c < 0x530)
142         return LanguageSpecificFont::Cyrillic;
143     if (c < 0x590)
144         return LanguageSpecificFont::None;
145     if (c < 0x600)
146         return LanguageSpecificFont::Hebrew;
147     if (c < 0x700)
148         return LanguageSpecificFont::Arabic;
149     if (c < 0x900)
150         return LanguageSpecificFont::None;
151     if (c < 0xE00)
152         return LanguageSpecificFont::Indic;
153     if (c < 0xE80)
154         return LanguageSpecificFont::Thai;
155     if (c < 0x0F00)
156         return LanguageSpecificFont::Lao;
157     if (c < 0x1000)
158         return LanguageSpecificFont::Tibetan;
159     if (c < 0x1100)
160         return LanguageSpecificFont::None;
161     if (c < 0x1200)
162         return LanguageSpecificFont::Korean;
163     if (c < 0x1400)
164         return LanguageSpecificFont::None;
165     if (c < 0x1780)
166         return LanguageSpecificFont::CanadianAboriginalSyllabic;
167     if (c < 0x1800)
168         return LanguageSpecificFont::Khmer;
169     if (c < 0x2E80)
170         return LanguageSpecificFont::None;
171     if (c < 0x3130)
172         return LanguageSpecificFont::ChineseJapanese;
173     if (c < 0x3190)
174         return LanguageSpecificFont::Korean;
175     if (c < 0xAC00)
176         return LanguageSpecificFont::ChineseJapanese;
177     if (c < 0xD7A4)
178         return LanguageSpecificFont::Korean;
179     if (c < 0xE000)
180         return LanguageSpecificFont::ChineseJapanese;
181     if (c < 0xE600)
182         return isGB18030ComplianceRequired ? LanguageSpecificFont::ChineseJapanese : LanguageSpecificFont::Emoji;
183     if (c < 0xE865 && isGB18030ComplianceRequired)
184         return LanguageSpecificFont::ChineseJapanese;
185     if (c < 0xF900)
186         return LanguageSpecificFont::None;
187     if (c < 0xFB00)
188         return LanguageSpecificFont::ChineseJapanese;
189     if (c < 0xFB50)
190         return LanguageSpecificFont::None;
191     if (c < 0xFE00)
192         return LanguageSpecificFont::Arabic;
193     if (c < 0xFE20)
194         return LanguageSpecificFont::None;
195     if (c < 0xFE70)
196         return LanguageSpecificFont::ChineseJapanese;
197     if (c < 0xFF00)
198         return LanguageSpecificFont::Arabic;
199     if (c < 0xFFF0)
200         return LanguageSpecificFont::ChineseJapanese;
201     if (c < 0x20000)
202         return LanguageSpecificFont::None;
203     if (c < 0x30000)
204         return LanguageSpecificFont::ChineseJapanese;
205     return LanguageSpecificFont::None;
206 }
207 #endif
208
209 RefPtr<Font> FontCache::systemFallbackForCharacters(const FontDescription& description, const Font* originalFontData, bool, const UChar* characters, unsigned length)
210 {
211     // Unlike OS X, our fallback font on iPhone is Arial Unicode, which doesn't have some apple-specific glyphs like F8FF.
212     // Fall back to the Apple Fallback font in this case.
213     if (length && requiresCustomFallbackFont(*characters)) {
214         auto* fallback = getCustomFallbackFont(*characters, description);
215         if (!fallback)
216             return nullptr;
217         return fontForPlatformData(*fallback);
218     }
219
220     UChar32 c = *characters;
221     if (length > 1 && U16_IS_LEAD(c) && U16_IS_TRAIL(characters[1]))
222         c = U16_GET_SUPPLEMENTARY(c, characters[1]);
223
224     // For system fonts we use CoreText fallback mechanism.
225     if (length) {
226         RetainPtr<CTFontDescriptorRef> fontDescriptor = adoptCF(CTFontCopyFontDescriptor(originalFontData->getCTFont()));
227         if (CTFontDescriptorIsSystemUIFont(fontDescriptor.get()))
228             return getSystemFontFallbackForCharacters(description, originalFontData, characters, length);
229     }
230
231     RefPtr<Font> font;
232
233 #if __IPHONE_OS_VERSION_MIN_REQUIRED < 90000
234     LanguageSpecificFont languageSpecificFont = LanguageSpecificFont::None;
235     if (length)
236         languageSpecificFont = languageSpecificFallbackFont(c);
237
238     switch (languageSpecificFont) {
239     case LanguageSpecificFont::ChineseJapanese: {
240         // By default, Chinese font is preferred, fall back on Japanese.
241
242         enum CJKFontVariant {
243             kCJKFontUseHiragino = 0,
244             kCJKFontUseSTHeitiSC,
245             kCJKFontUseSTHeitiTC,
246             kCJKFontUseSTHeitiJ,
247             kCJKFontUseSTHeitiK,
248             kCJKFontsUseHKGPW3UI
249         };
250
251         static NeverDestroyed<AtomicString> plainHiragino("HiraKakuProN-W3", AtomicString::ConstructFromLiteral);
252         static NeverDestroyed<AtomicString> plainSTHeitiSC("STHeitiSC-Light", AtomicString::ConstructFromLiteral);
253         static NeverDestroyed<AtomicString> plainSTHeitiTC("STHeitiTC-Light", AtomicString::ConstructFromLiteral);
254         static NeverDestroyed<AtomicString> plainSTHeitiJ("STHeitiJ-Light", AtomicString::ConstructFromLiteral);
255         static NeverDestroyed<AtomicString> plainSTHeitiK("STHeitiK-Light", AtomicString::ConstructFromLiteral);
256         static NeverDestroyed<AtomicString> plainHKGPW3UI("HKGPW3UI", AtomicString::ConstructFromLiteral);
257         static AtomicString* cjkPlain[] = {     
258             &plainHiragino.get(),
259             &plainSTHeitiSC.get(),
260             &plainSTHeitiTC.get(),
261             &plainSTHeitiJ.get(),
262             &plainSTHeitiK.get(),
263             &plainHKGPW3UI.get(),
264         };
265
266         static NeverDestroyed<AtomicString> boldHiragino("HiraKakuProN-W6", AtomicString::ConstructFromLiteral);
267         static NeverDestroyed<AtomicString> boldSTHeitiSC("STHeitiSC-Medium", AtomicString::ConstructFromLiteral);
268         static NeverDestroyed<AtomicString> boldSTHeitiTC("STHeitiTC-Medium", AtomicString::ConstructFromLiteral);
269         static NeverDestroyed<AtomicString> boldSTHeitiJ("STHeitiJ-Medium", AtomicString::ConstructFromLiteral);
270         static NeverDestroyed<AtomicString> boldSTHeitiK("STHeitiK-Medium", AtomicString::ConstructFromLiteral);
271         static NeverDestroyed<AtomicString> boldHKGPW3UI("HKGPW3UI", AtomicString::ConstructFromLiteral);
272         static AtomicString* cjkBold[] = {  
273             &boldHiragino.get(),
274             &boldSTHeitiSC.get(),
275             &boldSTHeitiTC.get(),
276             &boldSTHeitiJ.get(),
277             &boldSTHeitiK.get(),
278             &boldHKGPW3UI.get(),
279         };
280
281         // Default below is for Simplified Chinese user: zh-Hans - note that Hiragino is the
282         // the secondary font as we want its for Hiragana and Katakana. The other CJK fonts
283         // do not, and should not, contain Hiragana or Katakana glyphs.
284         static CJKFontVariant preferredCJKFont = kCJKFontUseSTHeitiSC;
285         static CJKFontVariant secondaryCJKFont = kCJKFontsUseHKGPW3UI;
286
287         static bool CJKFontInitialized;
288         if (!CJKFontInitialized) {
289             CJKFontInitialized = true;
290             // Testing: languageName = (CFStringRef)@"ja";
291             NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
292             NSArray *languages = [defaults stringArrayForKey:@"AppleLanguages"];
293
294             if (languages) {
295                 for (NSString *language in languages) {
296                     RetainPtr<CFStringRef> languageName = adoptCF(CFLocaleCreateCanonicalLanguageIdentifierFromString(nullptr, (CFStringRef)language));
297                     if (CFEqual(languageName.get(), CFSTR("zh-Hans")))
298                         break; // Simplified Chinese - default settings
299                     else if (CFEqual(languageName.get(), CFSTR("ja"))) {
300                         preferredCJKFont = kCJKFontUseHiragino; // Japanese - prefer Hiragino and STHeiti Japanse Variant
301                         secondaryCJKFont = kCJKFontUseSTHeitiJ;
302                         break;
303                     } else if (CFEqual(languageName.get(), CFSTR("ko"))) {
304                         preferredCJKFont = kCJKFontUseSTHeitiK; // Korean - prefer STHeiti Korean Variant 
305                         break;
306                     } else if (CFEqual(languageName.get(), CFSTR("zh-Hant"))) {
307                         preferredCJKFont = kCJKFontUseSTHeitiTC; // Traditional Chinese - prefer STHeiti Traditional Variant
308                         break;
309                     }
310                 }
311             }
312         }
313
314         font = fontForFamily(description, isFontWeightBold(description.weight()) ? *cjkBold[preferredCJKFont] : *cjkPlain[preferredCJKFont], false);
315         bool useSecondaryFont = true;
316         if (font) {
317             CGGlyph glyphs[2];
318             // CGFontGetGlyphsForUnichars takes UTF-16 buffer. Should only be 1 codepoint but since we may pass in two UTF-16 characters,
319             // make room for 2 glyphs just to be safe.
320             CGFontGetGlyphsForUnichars(font->platformData().cgFont(), characters, glyphs, length);
321
322             useSecondaryFont = (glyphs[0] == 0);
323         }
324
325         if (useSecondaryFont)
326             font = fontForFamily(description, isFontWeightBold(description.weight()) ? *cjkBold[secondaryCJKFont] : *cjkPlain[secondaryCJKFont], false);
327         break;
328     }
329     case LanguageSpecificFont::Korean: {
330         static NeverDestroyed<AtomicString> koreanPlain("AppleSDGothicNeo-Medium", AtomicString::ConstructFromLiteral);
331         static NeverDestroyed<AtomicString> koreanBold("AppleSDGothicNeo-Bold", AtomicString::ConstructFromLiteral);
332         font = fontForFamily(description, isFontWeightBold(description.weight()) ? koreanBold : koreanPlain, false);
333         break;
334     }
335     case LanguageSpecificFont::Cyrillic: {
336         static NeverDestroyed<AtomicString> cyrillicPlain("HelveticaNeue", AtomicString::ConstructFromLiteral);
337         static NeverDestroyed<AtomicString> cyrillicBold("HelveticaNeue-Bold", AtomicString::ConstructFromLiteral);
338         font = fontForFamily(description, isFontWeightBold(description.weight()) ? cyrillicBold : cyrillicPlain, false);
339         break;
340     }
341     case LanguageSpecificFont::Arabic: {
342         static NeverDestroyed<AtomicString> arabicPlain("GeezaPro", AtomicString::ConstructFromLiteral);
343         static NeverDestroyed<AtomicString> arabicBold("GeezaPro-Bold", AtomicString::ConstructFromLiteral);
344         font = fontForFamily(description, isFontWeightBold(description.weight()) ? arabicBold : arabicPlain, false);
345         break;
346     }
347     case LanguageSpecificFont::Hebrew: {
348         static NeverDestroyed<AtomicString> hebrewPlain("ArialHebrew", AtomicString::ConstructFromLiteral);
349         static NeverDestroyed<AtomicString> hebrewBold("ArialHebrew-Bold", AtomicString::ConstructFromLiteral);
350         font = fontForFamily(description, isFontWeightBold(description.weight()) ? hebrewBold : hebrewPlain, false);
351         break;
352     }
353     case LanguageSpecificFont::Indic: {
354         static NeverDestroyed<AtomicString> devanagariFont("KohinoorDevanagari-Book", AtomicString::ConstructFromLiteral);
355         static NeverDestroyed<AtomicString> bengaliFont("BanglaSangamMN", AtomicString::ConstructFromLiteral);
356         static NeverDestroyed<AtomicString> gurmukhiFont("GurmukhiMN", AtomicString::ConstructFromLiteral); // Might be replaced in a future release with a Sangam version.
357         static NeverDestroyed<AtomicString> gujaratiFont("GujaratiSangamMN", AtomicString::ConstructFromLiteral);
358         static NeverDestroyed<AtomicString> oriyaFont("OriyaSangamMN", AtomicString::ConstructFromLiteral);
359         static NeverDestroyed<AtomicString> tamilFont("TamilSangamMN", AtomicString::ConstructFromLiteral);
360         static NeverDestroyed<AtomicString> teluguFont("TeluguSangamMN", AtomicString::ConstructFromLiteral);
361         static NeverDestroyed<AtomicString> kannadaFont("KannadaSangamMN", AtomicString::ConstructFromLiteral);
362         static NeverDestroyed<AtomicString> malayalamFont("MalayalamSangamMN", AtomicString::ConstructFromLiteral);
363         static NeverDestroyed<AtomicString> sinhalaFont("SinhalaSangamMN", AtomicString::ConstructFromLiteral);
364
365         static NeverDestroyed<AtomicString> devanagariFontBold("KohinoorDevanagari-Medium", AtomicString::ConstructFromLiteral);
366         static NeverDestroyed<AtomicString> bengaliFontBold("BanglaSangamMN-Bold", AtomicString::ConstructFromLiteral);
367         static NeverDestroyed<AtomicString> gurmukhiFontBold("GurmukhiMN-Bold", AtomicString::ConstructFromLiteral); // Might be replaced in a future release with a Sangam version.
368         static NeverDestroyed<AtomicString> gujaratiFontBold("GujaratiSangamMN-Bold", AtomicString::ConstructFromLiteral);
369         static NeverDestroyed<AtomicString> oriyaFontBold("OriyaSangamMN-Bold", AtomicString::ConstructFromLiteral);
370         static NeverDestroyed<AtomicString> tamilFontBold("TamilSangamMN-Bold", AtomicString::ConstructFromLiteral);
371         static NeverDestroyed<AtomicString> teluguFontBold("TeluguSangamMN-Bold", AtomicString::ConstructFromLiteral);
372         static NeverDestroyed<AtomicString> kannadaFontBold("KannadaSangamMN-Bold", AtomicString::ConstructFromLiteral);
373         static NeverDestroyed<AtomicString> malayalamFontBold("MalayalamSangamMN-Bold", AtomicString::ConstructFromLiteral);
374         static NeverDestroyed<AtomicString> sinhalaFontBold("SinhalaSangamMN-Bold", AtomicString::ConstructFromLiteral);
375
376         static AtomicString* indicUnicodePageFonts[] = {
377             &devanagariFont.get(),
378             &bengaliFont.get(),
379             &gurmukhiFont.get(),
380             &gujaratiFont.get(),
381             &oriyaFont.get(),
382             &tamilFont.get(),
383             &teluguFont.get(),
384             &kannadaFont.get(),
385             &malayalamFont.get(),
386             &sinhalaFont.get()
387         };
388
389         static AtomicString* indicUnicodePageFontsBold[] = {
390             &devanagariFontBold.get(),
391             &bengaliFontBold.get(),
392             &gurmukhiFontBold.get(),
393             &gujaratiFontBold.get(),
394             &oriyaFontBold.get(),
395             &tamilFontBold.get(),
396             &teluguFontBold.get(),
397             &kannadaFontBold.get(),
398             &malayalamFontBold.get(),
399             &sinhalaFontBold.get()
400         };
401
402         uint32_t indicPageOrderIndex = (c - 0x0900) / 0x0080; // Indic scripts start at 0x0900 in Unicode. Each script is allocalted a block of 0x80 characters.
403         if (indicPageOrderIndex < (sizeof(indicUnicodePageFonts) / sizeof(AtomicString*))) {
404             AtomicString* indicFontString = isFontWeightBold(description.weight()) ? indicUnicodePageFontsBold[indicPageOrderIndex] : indicUnicodePageFonts[indicPageOrderIndex];
405             if (indicFontString)
406                 font = fontForFamily(description, *indicFontString, false);
407         }
408         break;
409     }
410     case LanguageSpecificFont::Thai: {
411         static NeverDestroyed<AtomicString> thaiPlain("Thonburi", AtomicString::ConstructFromLiteral);
412         static NeverDestroyed<AtomicString> thaiBold("Thonburi-Bold", AtomicString::ConstructFromLiteral);
413         font = fontForFamily(description, isFontWeightBold(description.weight()) ? thaiBold : thaiPlain, false);
414         break;
415     }
416     case LanguageSpecificFont::Tibetan: {
417         static NeverDestroyed<AtomicString> tibetanPlain("Kailasa", AtomicString::ConstructFromLiteral);
418         static NeverDestroyed<AtomicString> tibetanBold("Kailasa-Bold", AtomicString::ConstructFromLiteral);
419         font = fontForFamily(description, isFontWeightBold(description.weight()) ? tibetanBold : tibetanPlain, false);
420         break;
421     }
422     case LanguageSpecificFont::CanadianAboriginalSyllabic: {
423         static NeverDestroyed<AtomicString> casPlain("EuphemiaUCAS", AtomicString::ConstructFromLiteral);
424         static NeverDestroyed<AtomicString> casBold("EuphemiaUCAS-Bold", AtomicString::ConstructFromLiteral);
425         font = fontForFamily(description, isFontWeightBold(description.weight()) ? casBold : casPlain, false);
426         break;
427     }
428     case LanguageSpecificFont::Khmer: {
429         static NeverDestroyed<AtomicString> khmer("KhmerSangamMN", AtomicString::ConstructFromLiteral);
430         font = fontForFamily(description, khmer, false);
431         break;
432     }
433     case LanguageSpecificFont::Lao: {
434         static NeverDestroyed<AtomicString> lao("LaoSangamMN", AtomicString::ConstructFromLiteral);
435         font = fontForFamily(description, lao, false);
436         break;
437     }
438     default: {
439         static NeverDestroyed<AtomicString> appleColorEmoji("AppleColorEmoji", AtomicString::ConstructFromLiteral);
440         bool useEmojiFont = languageSpecificFont == LanguageSpecificFont::Emoji;
441         if (!useEmojiFont) {
442             if (!CFCharacterSetIsLongCharacterMember(phoneFallbackCharacterSet(), c))
443                 useEmojiFont = CFCharacterSetIsLongCharacterMember(appleColorEmojiCharacterSet(), c);
444         }
445         if (useEmojiFont)
446             font = fontForFamily(description, appleColorEmoji, false);
447         else {
448             RetainPtr<CTFontRef> fallbackFont = adoptCF(CTFontCreateForCharacters(originalFontData->getCTFont(), characters, length, nullptr));
449             if (RetainPtr<CFStringRef> foundFontName = adoptCF(CTFontCopyPostScriptName(fallbackFont.get())))
450                 font = fontForFamily(description, foundFontName.get(), false);
451         }
452         break;
453     }
454     }
455 #else
456     RetainPtr<CTFontDescriptorRef> fallbackFontDescriptor = adoptCF(CTFontCreatePhysicalFontDescriptorForCharactersWithLanguage(originalFontData->getCTFont(), characters, length, nullptr, nullptr));
457     if (auto foundFontName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(fallbackFontDescriptor.get(), kCTFontNameAttribute)))) {
458         if (c >= 0x0600 && c <= 0x06ff) { // Arabic
459             auto familyName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(fallbackFontDescriptor.get(), kCTFontFamilyNameAttribute)));
460             if (fontFamilyShouldNotBeUsedForArabic(familyName.get()))
461                 foundFontName = isFontWeightBold(description.weight()) ? CFSTR("GeezaPro-Bold") : CFSTR("GeezaPro");
462         }
463         font = fontForFamily(description, foundFontName.get(), false);
464     }
465 #endif
466
467     if (font)
468         return font.release();
469
470     return lastResortFallbackFont(description);
471 }
472
473 Vector<String> FontCache::systemFontFamilies()
474 {
475     // FIXME: <https://webkit.org/b/147033> Web Inspector: [iOS] Allow inspector to retrieve a list of system fonts
476     Vector<String> fontFamilies;
477     return fontFamilies;
478 }
479
480 RefPtr<Font> FontCache::similarFont(const FontDescription& description)
481 {
482     // Attempt to find an appropriate font using a match based on the presence of keywords in
483     // the requested names. For example, we'll match any name that contains "Arabic" to Geeza Pro.
484     RefPtr<Font> font;
485     for (unsigned i = 0; i < description.familyCount(); ++i) {
486         const AtomicString& family = description.familyAt(i);
487         if (family.isEmpty())
488             continue;
489
490         // Substitute the default monospace font for well-known monospace fonts.
491         static NeverDestroyed<AtomicString> monaco("monaco", AtomicString::ConstructFromLiteral);
492         static NeverDestroyed<AtomicString> menlo("menlo", AtomicString::ConstructFromLiteral);
493         static NeverDestroyed<AtomicString> courier("courier", AtomicString::ConstructFromLiteral);
494         if (equalIgnoringCase(family, monaco) || equalIgnoringCase(family, menlo)) {
495             font = fontForFamily(description, courier);
496             continue;
497         }
498
499         // Substitute Verdana for Lucida Grande.
500         static NeverDestroyed<AtomicString> lucidaGrande("lucida grande", AtomicString::ConstructFromLiteral);
501         static NeverDestroyed<AtomicString> verdana("verdana", AtomicString::ConstructFromLiteral);
502         if (equalIgnoringCase(family, lucidaGrande)) {
503             font = fontForFamily(description, verdana);
504             continue;
505         }
506
507         static NeverDestroyed<String> arabic(ASCIILiteral("Arabic"));
508         static NeverDestroyed<String> pashto(ASCIILiteral("Pashto"));
509         static NeverDestroyed<String> urdu(ASCIILiteral("Urdu"));
510         static String* matchWords[3] = { &arabic.get(), &pashto.get(), &urdu.get() };
511         static NeverDestroyed<AtomicString> geezaPlain("GeezaPro", AtomicString::ConstructFromLiteral);
512         static NeverDestroyed<AtomicString> geezaBold("GeezaPro-Bold", AtomicString::ConstructFromLiteral);
513         for (unsigned j = 0; j < 3 && !font; ++j) {
514             if (family.contains(*matchWords[j], false))
515                 font = fontForFamily(description, isFontWeightBold(description.weight()) ? geezaBold : geezaPlain);
516         }
517     }
518
519     return font.release();
520 }
521
522 Ref<Font> FontCache::lastResortFallbackFont(const FontDescription& fontDescription)
523 {
524     static NeverDestroyed<AtomicString> fallbackFontFamily(".PhoneFallback", AtomicString::ConstructFromLiteral);
525     return *fontForFamily(fontDescription, fallbackFontFamily, false);
526 }
527
528 FontPlatformData* FontCache::getCustomFallbackFont(const UInt32 c, const FontDescription& description)
529 {
530     ASSERT(requiresCustomFallbackFont(c));
531
532     static NeverDestroyed<AtomicString> helveticaFamily("Helvetica Neue", AtomicString::ConstructFromLiteral);
533     static NeverDestroyed<AtomicString> lockClockFamily("LockClock-Light", AtomicString::ConstructFromLiteral);
534     static NeverDestroyed<AtomicString> timesNewRomanPSMTFamily("TimesNewRomanPSMT", AtomicString::ConstructFromLiteral);
535
536     AtomicString* family = nullptr;
537     switch (c) {
538     case AppleLogo:
539         family = &helveticaFamily.get();
540         break;
541     case blackCircle:
542         family = &lockClockFamily.get();
543         break;
544     case narrowNonBreakingSpace:
545         family = &timesNewRomanPSMTFamily.get();
546         break;
547     default:
548         ASSERT_NOT_REACHED();
549         return nullptr;
550     }
551     ASSERT(family);
552     if (!family)
553         return nullptr;
554     return getCachedFontPlatformData(description, *family);
555 }
556
557 static inline FontTraitsMask toTraitsMask(CTFontSymbolicTraits ctFontTraits)
558 {
559     return static_cast<FontTraitsMask>(((ctFontTraits & kCTFontTraitItalic) ? FontStyleItalicMask : FontStyleNormalMask)
560         | FontVariantNormalMask
561         // FontWeight600 or higher is bold for CTFonts, so choose middle values for
562         // bold (600-900) and non-bold (100-500)
563         | ((ctFontTraits & kCTFontTraitBold) ? FontWeight700Mask : FontWeight300Mask));
564 }
565
566 void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
567 {
568     RetainPtr<CFStringRef> familyNameStr = familyName.string().createCFString();
569     NSDictionary *attributes = @{ (id)kCTFontFamilyNameAttribute: (NSString*)familyNameStr.get() };
570     RetainPtr<CTFontDescriptorRef> fontDescriptor = adoptCF(CTFontDescriptorCreateWithAttributes((CFDictionaryRef)attributes));
571     RetainPtr<NSArray> matchedDescriptors = adoptNS((NSArray *)CTFontDescriptorCreateMatchingFontDescriptors(fontDescriptor.get(), nullptr));
572
573     NSInteger numMatches = [matchedDescriptors.get() count];
574     if (!matchedDescriptors || !numMatches)
575         return;
576
577     for (NSInteger i = 0; i < numMatches; ++i) {
578         RetainPtr<CFDictionaryRef> traits = adoptCF((CFDictionaryRef)CTFontDescriptorCopyAttribute((CTFontDescriptorRef)[matchedDescriptors.get() objectAtIndex:i], kCTFontTraitsAttribute));
579         CFNumberRef resultRef = (CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait);
580         if (resultRef) {
581             CTFontSymbolicTraits symbolicTraits;
582             CFNumberGetValue(resultRef, kCFNumberIntType, &symbolicTraits);
583             traitsMasks.append(toTraitsMask(symbolicTraits));
584         }
585     }
586 }
587
588 float FontCache::weightOfCTFont(CTFontRef font)
589 {
590     float result = 0;
591     RetainPtr<CFDictionaryRef> traits = adoptCF(CTFontCopyTraits(font));
592     if (!traits)
593         return result;
594
595     CFNumberRef resultRef = (CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontWeightTrait);
596     if (resultRef)
597         CFNumberGetValue(resultRef, kCFNumberFloatType, &result);
598
599     return result;
600 }
601
602 static CTFontRef createCTFontWithTextStyle(const String& familyName, CTFontSymbolicTraits traits, CGFloat size)
603 {
604     if (familyName.isNull())
605         return nullptr;
606
607     CTFontSymbolicTraits symbolicTraits = 0;
608     if (traits & kCTFontBoldTrait)
609         symbolicTraits |= kCTFontBoldTrait;
610     if (traits & kCTFontTraitItalic)
611         symbolicTraits |= kCTFontTraitItalic;
612     RetainPtr<CFStringRef> familyNameStr = familyName.createCFString();
613     RetainPtr<CTFontDescriptorRef> fontDescriptor = adoptCF(CTFontDescriptorCreateWithTextStyle(familyNameStr.get(), RenderThemeIOS::contentSizeCategory(), nullptr));
614     if (symbolicTraits)
615         fontDescriptor = adoptCF(CTFontDescriptorCreateCopyWithSymbolicTraits(fontDescriptor.get(), symbolicTraits, symbolicTraits));
616
617     return CTFontCreateWithFontDescriptor(fontDescriptor.get(), size, nullptr);
618 }
619
620 static CTFontRef createCTFontWithFamilyNameAndWeight(const String& familyName, CTFontSymbolicTraits traits, float size, uint16_t weight)
621 {
622     if (familyName.isNull())
623         return nullptr;
624
625     static NeverDestroyed<AtomicString> systemUIFontWithWebKitPrefix("-webkit-system-font", AtomicString::ConstructFromLiteral);
626     static NeverDestroyed<AtomicString> systemUIFontWithApplePrefix("-apple-system", AtomicString::ConstructFromLiteral);
627     static NeverDestroyed<AtomicString> systemUIFontWithAppleAlternatePrefix("-apple-system-font", AtomicString::ConstructFromLiteral);
628     if (equalIgnoringCase(familyName, systemUIFontWithWebKitPrefix) || equalIgnoringCase(familyName, systemUIFontWithApplePrefix) || equalIgnoringCase(familyName, systemUIFontWithAppleAlternatePrefix)) {
629         CTFontUIFontType fontType = kCTFontUIFontSystem;
630         if (weight > 300) {
631             // The comment below has been copied from CoreText/UIFoundation. However, in WebKit we synthesize the oblique,
632             // so we should investigate the result <rdar://problem/14449340>:
633             if (traits & kCTFontTraitBold)
634                 fontType = kCTFontUIFontEmphasizedSystem;
635         } else if (weight > 250)
636             fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemLight);
637         else if (weight > 150)
638             fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemThin);
639         else
640             fontType = static_cast<CTFontUIFontType>(kCTFontUIFontSystemUltraLight);
641         RetainPtr<CTFontDescriptorRef> fontDescriptor = adoptCF(CTFontDescriptorCreateForUIType(fontType, size, nullptr));
642         if (traits & kCTFontTraitItalic)
643             fontDescriptor = adoptCF(CTFontDescriptorCreateCopyWithSymbolicTraits(fontDescriptor.get(), kCTFontItalicTrait, kCTFontItalicTrait));
644         return CTFontCreateWithFontDescriptor(fontDescriptor.get(), size, nullptr);
645     }
646
647     static NeverDestroyed<AtomicString> systemUIMonospacedNumbersFontWithApplePrefix("-apple-system-monospaced-numbers", AtomicString::ConstructFromLiteral);
648     if (equalIgnoringCase(familyName, systemUIMonospacedNumbersFontWithApplePrefix)) {
649         RetainPtr<CTFontDescriptorRef> systemFontDescriptor = adoptCF(CTFontDescriptorCreateForUIType(kCTFontUIFontSystem, size, nullptr));
650         RetainPtr<CTFontDescriptorRef> monospaceFontDescriptor = adoptCF(CTFontDescriptorCreateCopyWithFeature(systemFontDescriptor.get(), (CFNumberRef)@(kNumberSpacingType), (CFNumberRef)@(kMonospacedNumbersSelector)));
651         return CTFontCreateWithFontDescriptor(monospaceFontDescriptor.get(), size, nullptr);
652     }
653
654
655     RetainPtr<CFStringRef> familyNameStr = familyName.createCFString();
656     CTFontSymbolicTraits requestedTraits = (CTFontSymbolicTraits)(traits & (kCTFontBoldTrait | kCTFontItalicTrait));
657     return CTFontCreateForCSS(familyNameStr.get(), weight, requestedTraits, size);
658 }
659
660 static uint16_t toCTFontWeight(FontWeight fontWeight)
661 {
662     switch (fontWeight) {
663     case FontWeight100:
664         return 100;
665     case FontWeight200:
666         return 200;
667     case FontWeight300:
668         return 300;
669     case FontWeight400:
670         return 400;
671     case FontWeight500:
672         return 500;
673     case FontWeight600:
674         return 600;
675     case FontWeight700:
676         return 700;
677     case FontWeight800:
678         return 800;
679     case FontWeight900:
680         return 900;
681     default:
682         return 400;
683     }
684 }
685
686 std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
687 {
688     CTFontSymbolicTraits traits = 0;
689     if (fontDescription.italic())
690         traits |= kCTFontTraitItalic;
691     if (isFontWeightBold(fontDescription.weight()))
692         traits |= kCTFontTraitBold;
693     float size = fontDescription.computedPixelSize();
694
695     RetainPtr<CTFontRef> ctFont;
696     if (family.startsWith("UICTFontTextStyle"))
697         ctFont = adoptCF(createCTFontWithTextStyle(family, traits, size));
698     else
699         ctFont = adoptCF(createCTFontWithFamilyNameAndWeight(family, traits, size, toCTFontWeight(fontDescription.weight())));
700     if (!ctFont)
701         return nullptr;
702
703     ctFont = applyFontFeatureSettings(ctFont.get(), fontDescription.featureSettings());
704
705     CTFontSymbolicTraits actualTraits = 0;
706     if (isFontWeightBold(fontDescription.weight()) || fontDescription.italic())
707         actualTraits = CTFontGetSymbolicTraits(ctFont.get());
708
709     bool isAppleColorEmoji = CTFontIsAppleColorEmoji(ctFont.get());
710
711     bool syntheticBold = (fontDescription.fontSynthesis() & FontSynthesisWeight) && (traits & kCTFontTraitBold) && !(actualTraits & kCTFontTraitBold) && !isAppleColorEmoji;
712     bool syntheticOblique = (fontDescription.fontSynthesis() & FontSynthesisStyle) && (traits & kCTFontTraitItalic) && !(actualTraits & kCTFontTraitItalic) && !isAppleColorEmoji;
713
714     auto result = std::make_unique<FontPlatformData>(ctFont.get(), size, syntheticBold, syntheticOblique, fontDescription.orientation(), fontDescription.widthVariant());
715     if (isAppleColorEmoji)
716         result->setIsEmoji(true);
717     return result;
718 }
719
720 } // namespace WebCore