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