NeverDestroyed<String>(ASCIILiteral(...)) is not thread safe.
[WebKit-https.git] / Source / WebCore / platform / graphics / cocoa / FontCacheCoreText.cpp
1 /*
2  * Copyright (C) 2015-2017 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "FontCache.h"
28
29 #include "CoreTextSPI.h"
30 #include "Font.h"
31
32 #include <CoreText/SFNTLayoutTypes.h>
33
34 #include <wtf/HashSet.h>
35 #include <wtf/MainThread.h>
36 #include <wtf/NeverDestroyed.h>
37
38 #define SHOULD_USE_CORE_TEXT_FONT_LOOKUP (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
39 #define HAS_CORE_TEXT_WIDTH_ATTRIBUTE ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000))
40
41 namespace WebCore {
42
43 static inline void appendRawTrueTypeFeature(CFMutableArrayRef features, int type, int selector)
44 {
45     auto typeNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &type));
46     auto selectorNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &selector));
47     CFTypeRef featureKeys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey };
48     CFTypeRef featureValues[] = { typeNumber.get(), selectorNumber.get() };
49     auto feature = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, featureKeys, featureValues, WTF_ARRAY_LENGTH(featureKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
50     CFArrayAppendValue(features, feature.get());
51 }
52
53 static inline bool tagEquals(FontTag tag, const char comparison[4])
54 {
55     return equalIgnoringASCIICase(tag.data(), comparison, 4);
56 }
57
58 static inline void appendTrueTypeFeature(CFMutableArrayRef features, const FontFeature& feature)
59 {
60     if (tagEquals(feature.tag(), "liga") || tagEquals(feature.tag(), "clig")) {
61         if (feature.enabled()) {
62             appendRawTrueTypeFeature(features, kLigaturesType, kCommonLigaturesOnSelector);
63             appendRawTrueTypeFeature(features, kLigaturesType, kContextualLigaturesOnSelector);
64         } else {
65             appendRawTrueTypeFeature(features, kLigaturesType, kCommonLigaturesOffSelector);
66             appendRawTrueTypeFeature(features, kLigaturesType, kContextualLigaturesOffSelector);
67         }
68     } else if (tagEquals(feature.tag(), "dlig")) {
69         if (feature.enabled())
70             appendRawTrueTypeFeature(features, kLigaturesType, kRareLigaturesOnSelector);
71         else
72             appendRawTrueTypeFeature(features, kLigaturesType, kRareLigaturesOffSelector);
73     } else if (tagEquals(feature.tag(), "hlig")) {
74         if (feature.enabled())
75             appendRawTrueTypeFeature(features, kLigaturesType, kHistoricalLigaturesOnSelector);
76         else
77             appendRawTrueTypeFeature(features, kLigaturesType, kHistoricalLigaturesOffSelector);
78     } else if (tagEquals(feature.tag(), "calt")) {
79         if (feature.enabled())
80             appendRawTrueTypeFeature(features, kContextualAlternatesType, kContextualAlternatesOnSelector);
81         else
82             appendRawTrueTypeFeature(features, kContextualAlternatesType, kContextualAlternatesOffSelector);
83     } else if (tagEquals(feature.tag(), "subs") && feature.enabled())
84         appendRawTrueTypeFeature(features, kVerticalPositionType, kInferiorsSelector);
85     else if (tagEquals(feature.tag(), "sups") && feature.enabled())
86         appendRawTrueTypeFeature(features, kVerticalPositionType, kSuperiorsSelector);
87     else if (tagEquals(feature.tag(), "smcp") && feature.enabled())
88         appendRawTrueTypeFeature(features, kLowerCaseType, kLowerCaseSmallCapsSelector);
89     else if (tagEquals(feature.tag(), "c2sc") && feature.enabled())
90         appendRawTrueTypeFeature(features, kUpperCaseType, kUpperCaseSmallCapsSelector);
91     else if (tagEquals(feature.tag(), "pcap") && feature.enabled())
92         appendRawTrueTypeFeature(features, kLowerCaseType, kLowerCasePetiteCapsSelector);
93     else if (tagEquals(feature.tag(), "c2pc") && feature.enabled())
94         appendRawTrueTypeFeature(features, kUpperCaseType, kUpperCasePetiteCapsSelector);
95     else if (tagEquals(feature.tag(), "unic") && feature.enabled())
96         appendRawTrueTypeFeature(features, kLetterCaseType, 14);
97     else if (tagEquals(feature.tag(), "titl") && feature.enabled())
98         appendRawTrueTypeFeature(features, kStyleOptionsType, kTitlingCapsSelector);
99     else if (tagEquals(feature.tag(), "lnum") && feature.enabled())
100         appendRawTrueTypeFeature(features, kNumberCaseType, kUpperCaseNumbersSelector);
101     else if (tagEquals(feature.tag(), "onum") && feature.enabled())
102         appendRawTrueTypeFeature(features, kNumberCaseType, kLowerCaseNumbersSelector);
103     else if (tagEquals(feature.tag(), "pnum") && feature.enabled())
104         appendRawTrueTypeFeature(features, kNumberSpacingType, kProportionalNumbersSelector);
105     else if (tagEquals(feature.tag(), "tnum") && feature.enabled())
106         appendRawTrueTypeFeature(features, kNumberSpacingType, kMonospacedNumbersSelector);
107     else if (tagEquals(feature.tag(), "frac") && feature.enabled())
108         appendRawTrueTypeFeature(features, kFractionsType, kDiagonalFractionsSelector);
109     else if (tagEquals(feature.tag(), "afrc") && feature.enabled())
110         appendRawTrueTypeFeature(features, kFractionsType, kVerticalFractionsSelector);
111     else if (tagEquals(feature.tag(), "ordn") && feature.enabled())
112         appendRawTrueTypeFeature(features, kVerticalPositionType, kOrdinalsSelector);
113     else if (tagEquals(feature.tag(), "zero") && feature.enabled())
114         appendRawTrueTypeFeature(features, kTypographicExtrasType, kSlashedZeroOnSelector);
115     else if (tagEquals(feature.tag(), "hist") && feature.enabled())
116         appendRawTrueTypeFeature(features, kLigaturesType, kHistoricalLigaturesOnSelector);
117     else if (tagEquals(feature.tag(), "jp78") && feature.enabled())
118         appendRawTrueTypeFeature(features, kCharacterShapeType, kJIS1978CharactersSelector);
119     else if (tagEquals(feature.tag(), "jp83") && feature.enabled())
120         appendRawTrueTypeFeature(features, kCharacterShapeType, kJIS1983CharactersSelector);
121     else if (tagEquals(feature.tag(), "jp90") && feature.enabled())
122         appendRawTrueTypeFeature(features, kCharacterShapeType, kJIS1990CharactersSelector);
123     else if (tagEquals(feature.tag(), "jp04") && feature.enabled())
124         appendRawTrueTypeFeature(features, kCharacterShapeType, kJIS2004CharactersSelector);
125     else if (tagEquals(feature.tag(), "smpl") && feature.enabled())
126         appendRawTrueTypeFeature(features, kCharacterShapeType, kSimplifiedCharactersSelector);
127     else if (tagEquals(feature.tag(), "trad") && feature.enabled())
128         appendRawTrueTypeFeature(features, kCharacterShapeType, kTraditionalCharactersSelector);
129     else if (tagEquals(feature.tag(), "fwid") && feature.enabled())
130         appendRawTrueTypeFeature(features, kTextSpacingType, kMonospacedTextSelector);
131     else if (tagEquals(feature.tag(), "pwid") && feature.enabled())
132         appendRawTrueTypeFeature(features, kTextSpacingType, kProportionalTextSelector);
133     else if (tagEquals(feature.tag(), "ruby") && feature.enabled())
134         appendRawTrueTypeFeature(features, kRubyKanaType, kRubyKanaOnSelector);
135 }
136
137 static inline void appendOpenTypeFeature(CFMutableArrayRef features, const FontFeature& feature)
138 {
139     auto featureKey = adoptCF(CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(feature.tag().data()), feature.tag().size() * sizeof(FontTag::value_type), kCFStringEncodingASCII, false));
140     int rawFeatureValue = feature.value();
141     auto featureValue = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &rawFeatureValue));
142     CFTypeRef featureDictionaryKeys[] = { kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureValue };
143     CFTypeRef featureDictionaryValues[] = { featureKey.get(), featureValue.get() };
144     auto featureDictionary = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, featureDictionaryKeys, featureDictionaryValues, WTF_ARRAY_LENGTH(featureDictionaryValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
145     CFArrayAppendValue(features, featureDictionary.get());
146 }
147
148 typedef HashMap<FontTag, int, FourCharacterTagHash, FourCharacterTagHashTraits> FeaturesMap;
149 #if ENABLE(VARIATION_FONTS)
150 typedef HashMap<FontTag, float, FourCharacterTagHash, FourCharacterTagHashTraits> VariationsMap;
151 #endif
152
153 static FeaturesMap computeFeatureSettingsFromVariants(const FontVariantSettings& variantSettings)
154 {
155     FeaturesMap result;
156
157     switch (variantSettings.commonLigatures) {
158     case FontVariantLigatures::Normal:
159         break;
160     case FontVariantLigatures::Yes:
161         result.add(fontFeatureTag("liga"), 1);
162         result.add(fontFeatureTag("clig"), 1);
163         break;
164     case FontVariantLigatures::No:
165         result.add(fontFeatureTag("liga"), 0);
166         result.add(fontFeatureTag("clig"), 0);
167         break;
168     default:
169         ASSERT_NOT_REACHED();
170     }
171
172     switch (variantSettings.discretionaryLigatures) {
173     case FontVariantLigatures::Normal:
174         break;
175     case FontVariantLigatures::Yes:
176         result.add(fontFeatureTag("dlig"), 1);
177         break;
178     case FontVariantLigatures::No:
179         result.add(fontFeatureTag("dlig"), 0);
180         break;
181     default:
182         ASSERT_NOT_REACHED();
183     }
184
185     switch (variantSettings.historicalLigatures) {
186     case FontVariantLigatures::Normal:
187         break;
188     case FontVariantLigatures::Yes:
189         result.add(fontFeatureTag("hlig"), 1);
190         break;
191     case FontVariantLigatures::No:
192         result.add(fontFeatureTag("hlig"), 0);
193         break;
194     default:
195         ASSERT_NOT_REACHED();
196     }
197
198     switch (variantSettings.contextualAlternates) {
199     case FontVariantLigatures::Normal:
200         break;
201     case FontVariantLigatures::Yes:
202         result.add(fontFeatureTag("calt"), 1);
203         break;
204     case FontVariantLigatures::No:
205         result.add(fontFeatureTag("calt"), 0);
206         break;
207     default:
208         ASSERT_NOT_REACHED();
209     }
210
211     switch (variantSettings.position) {
212     case FontVariantPosition::Normal:
213         break;
214     case FontVariantPosition::Subscript:
215         result.add(fontFeatureTag("subs"), 1);
216         break;
217     case FontVariantPosition::Superscript:
218         result.add(fontFeatureTag("sups"), 1);
219         break;
220     default:
221         ASSERT_NOT_REACHED();
222     }
223
224     switch (variantSettings.caps) {
225     case FontVariantCaps::Normal:
226         break;
227     case FontVariantCaps::AllSmall:
228         result.add(fontFeatureTag("c2sc"), 1);
229         FALLTHROUGH;
230     case FontVariantCaps::Small:
231         result.add(fontFeatureTag("smcp"), 1);
232         break;
233     case FontVariantCaps::AllPetite:
234         result.add(fontFeatureTag("c2pc"), 1);
235         FALLTHROUGH;
236     case FontVariantCaps::Petite:
237         result.add(fontFeatureTag("pcap"), 1);
238         break;
239     case FontVariantCaps::Unicase:
240         result.add(fontFeatureTag("unic"), 1);
241         break;
242     case FontVariantCaps::Titling:
243         result.add(fontFeatureTag("titl"), 1);
244         break;
245     default:
246         ASSERT_NOT_REACHED();
247     }
248
249     switch (variantSettings.numericFigure) {
250     case FontVariantNumericFigure::Normal:
251         break;
252     case FontVariantNumericFigure::LiningNumbers:
253         result.add(fontFeatureTag("lnum"), 1);
254         break;
255     case FontVariantNumericFigure::OldStyleNumbers:
256         result.add(fontFeatureTag("onum"), 1);
257         break;
258     default:
259         ASSERT_NOT_REACHED();
260     }
261
262     switch (variantSettings.numericSpacing) {
263     case FontVariantNumericSpacing::Normal:
264         break;
265     case FontVariantNumericSpacing::ProportionalNumbers:
266         result.add(fontFeatureTag("pnum"), 1);
267         break;
268     case FontVariantNumericSpacing::TabularNumbers:
269         result.add(fontFeatureTag("tnum"), 1);
270         break;
271     default:
272         ASSERT_NOT_REACHED();
273     }
274
275     switch (variantSettings.numericFraction) {
276     case FontVariantNumericFraction::Normal:
277         break;
278     case FontVariantNumericFraction::DiagonalFractions:
279         result.add(fontFeatureTag("frac"), 1);
280         break;
281     case FontVariantNumericFraction::StackedFractions:
282         result.add(fontFeatureTag("afrc"), 1);
283         break;
284     default:
285         ASSERT_NOT_REACHED();
286     }
287
288     switch (variantSettings.numericOrdinal) {
289     case FontVariantNumericOrdinal::Normal:
290         break;
291     case FontVariantNumericOrdinal::Yes:
292         result.add(fontFeatureTag("ordn"), 1);
293         break;
294     default:
295         ASSERT_NOT_REACHED();
296     }
297
298     switch (variantSettings.numericSlashedZero) {
299     case FontVariantNumericSlashedZero::Normal:
300         break;
301     case FontVariantNumericSlashedZero::Yes:
302         result.add(fontFeatureTag("zero"), 1);
303         break;
304     default:
305         ASSERT_NOT_REACHED();
306     }
307
308     switch (variantSettings.alternates) {
309     case FontVariantAlternates::Normal:
310         break;
311     case FontVariantAlternates::HistoricalForms:
312         result.add(fontFeatureTag("hist"), 1);
313         break;
314     default:
315         ASSERT_NOT_REACHED();
316     }
317
318     switch (variantSettings.eastAsianVariant) {
319     case FontVariantEastAsianVariant::Normal:
320         break;
321     case FontVariantEastAsianVariant::Jis78:
322         result.add(fontFeatureTag("jp78"), 1);
323         break;
324     case FontVariantEastAsianVariant::Jis83:
325         result.add(fontFeatureTag("jp83"), 1);
326         break;
327     case FontVariantEastAsianVariant::Jis90:
328         result.add(fontFeatureTag("jp90"), 1);
329         break;
330     case FontVariantEastAsianVariant::Jis04:
331         result.add(fontFeatureTag("jp04"), 1);
332         break;
333     case FontVariantEastAsianVariant::Simplified:
334         result.add(fontFeatureTag("smpl"), 1);
335         break;
336     case FontVariantEastAsianVariant::Traditional:
337         result.add(fontFeatureTag("trad"), 1);
338         break;
339     default:
340         ASSERT_NOT_REACHED();
341     }
342
343     switch (variantSettings.eastAsianWidth) {
344     case FontVariantEastAsianWidth::Normal:
345         break;
346     case FontVariantEastAsianWidth::Full:
347         result.add(fontFeatureTag("fwid"), 1);
348         break;
349     case FontVariantEastAsianWidth::Proportional:
350         result.add(fontFeatureTag("pwid"), 1);
351         break;
352     default:
353         ASSERT_NOT_REACHED();
354     }
355
356     switch (variantSettings.eastAsianRuby) {
357     case FontVariantEastAsianRuby::Normal:
358         break;
359     case FontVariantEastAsianRuby::Yes:
360         result.add(fontFeatureTag("ruby"), 1);
361         break;
362     default:
363         ASSERT_NOT_REACHED();
364     }
365
366     return result;
367 }
368
369 #if ENABLE(VARIATION_FONTS)
370 struct VariationDefaults {
371     float defaultValue;
372     float minimumValue;
373     float maximumValue;
374 };
375
376 typedef HashMap<FontTag, VariationDefaults, FourCharacterTagHash, FourCharacterTagHashTraits> VariationDefaultsMap;
377
378 static VariationDefaultsMap defaultVariationValues(CTFontRef font)
379 {
380     VariationDefaultsMap result;
381     auto axes = adoptCF(CTFontCopyVariationAxes(font));
382     if (!axes)
383         return result;
384     auto size = CFArrayGetCount(axes.get());
385     for (CFIndex i = 0; i < size; ++i) {
386         CFDictionaryRef axis = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(axes.get(), i));
387         CFNumberRef axisIdentifier = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisIdentifierKey));
388         CFNumberRef defaultValue = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisDefaultValueKey));
389         CFNumberRef minimumValue = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisMinimumValueKey));
390         CFNumberRef maximumValue = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisMaximumValueKey));
391         uint32_t rawAxisIdentifier = 0;
392         Boolean success = CFNumberGetValue(axisIdentifier, kCFNumberSInt32Type, &rawAxisIdentifier);
393         ASSERT_UNUSED(success, success);
394         float rawDefaultValue = 0;
395         float rawMinimumValue = 0;
396         float rawMaximumValue = 0;
397         CFNumberGetValue(defaultValue, kCFNumberFloatType, &rawDefaultValue);
398         CFNumberGetValue(minimumValue, kCFNumberFloatType, &rawMinimumValue);
399         CFNumberGetValue(maximumValue, kCFNumberFloatType, &rawMaximumValue);
400
401         // FIXME: Remove when <rdar://problem/28893836> is fixed
402 #define WORKAROUND_CORETEXT_VARIATIONS_EXTENTS_BUG ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < 110000))
403 #if WORKAROUND_CORETEXT_VARIATIONS_EXTENTS_BUG
404         float epsilon = 0.001;
405         rawMinimumValue += epsilon;
406         rawMaximumValue -= epsilon;
407 #endif
408 #undef WORKAROUND_CORETEXT_VARIATIONS_EXTENTS_BUG
409
410         if (rawMinimumValue > rawMaximumValue)
411             std::swap(rawMinimumValue, rawMaximumValue);
412
413         auto b1 = rawAxisIdentifier >> 24;
414         auto b2 = (rawAxisIdentifier & 0xFF0000) >> 16;
415         auto b3 = (rawAxisIdentifier & 0xFF00) >> 8;
416         auto b4 = rawAxisIdentifier & 0xFF;
417         FontTag resultKey = {{ static_cast<char>(b1), static_cast<char>(b2), static_cast<char>(b3), static_cast<char>(b4) }};
418         VariationDefaults resultValues = { rawDefaultValue, rawMinimumValue, rawMaximumValue };
419         result.set(resultKey, resultValues);
420     }
421     return result;
422 }
423
424 static inline bool fontIsSystemFont(CTFontRef font)
425 {
426     if (CTFontDescriptorIsSystemUIFont(adoptCF(CTFontCopyFontDescriptor(font)).get()))
427         return true;
428     auto name = adoptCF(CTFontCopyPostScriptName(font));
429     return CFStringGetLength(name.get()) > 0 && CFStringGetCharacterAtIndex(name.get(), 0) == '.';
430 }
431
432 static inline bool isGXVariableFont(CTFontRef font)
433 {
434     auto tables = adoptCF(CTFontCopyAvailableTables(font, kCTFontTableOptionNoOptions));
435     if (!tables)
436         return false;
437     auto size = CFArrayGetCount(tables.get());
438     for (CFIndex i = 0; i < size; ++i) {
439         // This is so yucky.
440         // https://developer.apple.com/reference/coretext/1510774-ctfontcopyavailabletables
441         // "The returned set will contain unboxed values, which can be extracted like so:"
442         // "CTFontTableTag tag = (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tags, index);"
443         CTFontTableTag tableTag = static_cast<CTFontTableTag>(reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(tables.get(), i)));
444         if (tableTag == 'STAT')
445             return false;
446     }
447     return true;
448 }
449
450 // These values were calculated by performing a linear regression on the CSS weights/widths/slopes and Core Text weights/widths/slopes of San Francisco.
451 // FIXME: <rdar://problem/31312602> Get the real values from Core Text.
452 static inline float normalizeWeight(float value)
453 {
454     return 523.7 * value - 109.3;
455 }
456
457 static inline float normalizeSlope(float value)
458 {
459     return value * 300;
460 }
461
462 static inline float denormalizeWeight(float value)
463 {
464     return (value + 109.3) / 523.7;
465 }
466
467 static inline float denormalizeSlope(float value)
468 {
469     return value / 300;
470 }
471
472 static inline float denormalizeVariationWidth(float value)
473 {
474     if (value <= 125)
475         return value / 100;
476     if (value <= 150)
477         return (value + 125) / 200;
478     return (value + 400) / 400;
479 }
480 #endif
481
482 #if ENABLE(VARIATION_FONTS) || !HAS_CORE_TEXT_WIDTH_ATTRIBUTE
483 static inline float normalizeVariationWidth(float value)
484 {
485     if (value <= 1.25)
486         return value * 100;
487     if (value <= 1.375)
488         return value * 200 - 125;
489     return value * 400 - 400;
490 }
491 #endif
492
493 #if !HAS_CORE_TEXT_WIDTH_ATTRIBUTE
494 static inline float normalizeWidth(float value)
495 {
496     return normalizeVariationWidth(value + 1);
497 }
498 #endif
499
500 RetainPtr<CTFontRef> preparePlatformFont(CTFontRef originalFont, TextRenderingMode textRenderingMode, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, FontSelectionSpecifiedCapabilities fontFaceCapabilities, const FontFeatureSettings& features, const FontVariantSettings& variantSettings, FontSelectionRequest fontSelectionRequest, const FontVariationSettings& variations, FontOpticalSizing fontOpticalSizing, float size)
501 {
502     bool alwaysAddVariations = false;
503
504     // FIXME: Remove when <rdar://problem/29859207> is fixed
505 #if ENABLE(VARIATION_FONTS)
506     auto defaultValues = defaultVariationValues(originalFont);
507     alwaysAddVariations = !defaultValues.isEmpty();
508 #else
509     UNUSED_PARAM(fontSelectionRequest);
510     UNUSED_PARAM(fontOpticalSizing);
511     UNUSED_PARAM(fontFaceCapabilities);
512     UNUSED_PARAM(size);
513 #endif
514
515     if (!originalFont || (!features.size() && (!alwaysAddVariations && variations.isEmpty()) && (textRenderingMode == AutoTextRendering) && variantSettings.isAllNormal()
516         && (!fontFaceFeatures || !fontFaceFeatures->size()) && (!fontFaceVariantSettings || fontFaceVariantSettings->isAllNormal())))
517         return originalFont;
518
519     // This algorithm is described at http://www.w3.org/TR/css3-fonts/#feature-precedence
520     FeaturesMap featuresToBeApplied;
521
522     // Step 1: CoreText handles default features (such as required ligatures).
523
524     // Step 2: Consult with font-variant-* inside @font-face
525     if (fontFaceVariantSettings)
526         featuresToBeApplied = computeFeatureSettingsFromVariants(*fontFaceVariantSettings);
527
528     // Step 3: Consult with font-feature-settings inside @font-face
529     if (fontFaceFeatures) {
530         for (auto& fontFaceFeature : *fontFaceFeatures)
531             featuresToBeApplied.set(fontFaceFeature.tag(), fontFaceFeature.value());
532     }
533
534     // Step 4: Font-variant
535     for (auto& newFeature : computeFeatureSettingsFromVariants(variantSettings))
536         featuresToBeApplied.set(newFeature.key, newFeature.value);
537
538     // Step 5: Other properties (text-rendering)
539     if (textRenderingMode == OptimizeSpeed) {
540         featuresToBeApplied.set(fontFeatureTag("liga"), 0);
541         featuresToBeApplied.set(fontFeatureTag("clig"), 0);
542         featuresToBeApplied.set(fontFeatureTag("dlig"), 0);
543         featuresToBeApplied.set(fontFeatureTag("hlig"), 0);
544         featuresToBeApplied.set(fontFeatureTag("calt"), 0);
545     }
546
547     // Step 6: Font-feature-settings
548     for (auto& newFeature : features)
549         featuresToBeApplied.set(newFeature.tag(), newFeature.value());
550
551 #if ENABLE(VARIATION_FONTS)
552     VariationsMap variationsToBeApplied;
553
554     bool needsConversion = isGXVariableFont(originalFont);
555     auto applyVariationValue = [&](const FontTag& tag, float value, bool isDefaultValue) {
556         // FIXME: Remove when <rdar://problem/28707822> is fixed
557 #define WORKAROUND_CORETEXT_VARIATIONS_DEFAULT_VALUE_BUG ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < 110000))
558 #if WORKAROUND_CORETEXT_VARIATIONS_DEFAULT_VALUE_BUG
559         if (isDefaultValue)
560             value += 0.0001;
561 #else
562         UNUSED_PARAM(isDefaultValue);
563 #endif
564 #undef WORKAROUND_CORETEXT_VARIATIONS_DEFAULT_VALUE_BUG
565         variationsToBeApplied.set(tag, value);
566     };
567
568     auto applyVariation = [&](const FontTag& tag, float value) {
569         auto iterator = defaultValues.find(tag);
570         if (iterator == defaultValues.end())
571             return;
572         float valueToApply = clampTo(value, iterator->value.minimumValue, iterator->value.maximumValue);
573         bool isDefaultValue = valueToApply == iterator->value.defaultValue;
574         applyVariationValue(tag, valueToApply, isDefaultValue);
575     };
576
577     // The system font is somewhat magical. Don't mess with its variations.
578     if (!fontIsSystemFont(originalFont)) {
579         float weight = fontSelectionRequest.weight;
580         float width = fontSelectionRequest.width;
581         float slope = fontSelectionRequest.slope;
582         if (auto weightValue = fontFaceCapabilities.weight)
583             weight = std::max(std::min(weight, static_cast<float>(weightValue->maximum)), static_cast<float>(weightValue->minimum));
584         if (auto widthValue = fontFaceCapabilities.width)
585             width = std::max(std::min(width, static_cast<float>(widthValue->maximum)), static_cast<float>(widthValue->minimum));
586         if (auto slopeValue = fontFaceCapabilities.weight)
587             slope = std::max(std::min(slope, static_cast<float>(slopeValue->maximum)), static_cast<float>(slopeValue->minimum));
588         if (needsConversion) {
589             weight = denormalizeWeight(weight);
590             width = denormalizeVariationWidth(width);
591             slope = denormalizeSlope(slope);
592         }
593         applyVariation({{'w', 'g', 'h', 't'}}, weight);
594         applyVariation({{'w', 'd', 't', 'h'}}, width);
595         applyVariation({{'s', 'l', 'n', 't'}}, slope);
596     }
597
598     if (fontOpticalSizing == FontOpticalSizing::Enabled) {
599         const float pxToPtRatio = 3.0f / 4;
600         applyVariation({{'o', 'p', 's', 'z'}}, size * pxToPtRatio);
601     }
602
603     for (auto& newVariation : variations)
604         applyVariation(newVariation.tag(), newVariation.value());
605
606 #define WORKAROUND_CORETEXT_VARIATIONS_UNSPECIFIED_VALUE_BUG ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < 110000))
607 #if WORKAROUND_CORETEXT_VARIATIONS_UNSPECIFIED_VALUE_BUG
608     if (!fontIsSystemFont(originalFont)) {
609         for (auto& defaultValue : defaultValues) {
610             if (!variationsToBeApplied.contains(defaultValue.key))
611                 applyVariationValue(defaultValue.key, defaultValue.value.defaultValue, true);
612         }
613     }
614 #endif
615 #undef WORKAROUND_CORETEXT_VARIATIONS_UNSPECIFIED_VALUE_BUG
616
617 #endif // ENABLE(VARIATION_FONTS)
618
619     auto attributes = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
620     if (!featuresToBeApplied.isEmpty()) {
621         auto featureArray = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, features.size(), &kCFTypeArrayCallBacks));
622         for (auto& p : featuresToBeApplied) {
623             auto feature = FontFeature(p.key, p.value);
624             appendTrueTypeFeature(featureArray.get(), feature);
625             appendOpenTypeFeature(featureArray.get(), feature);
626         }
627         CFDictionaryAddValue(attributes.get(), kCTFontFeatureSettingsAttribute, featureArray.get());
628     }
629
630 #if ENABLE(VARIATION_FONTS)
631     if (!variationsToBeApplied.isEmpty()) {
632         auto variationDictionary = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
633         for (auto& p : variationsToBeApplied) {
634             long long bitwiseTag = p.key[0] << 24 | p.key[1] << 16 | p.key[2] << 8 | p.key[3];
635             auto tagNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &bitwiseTag));
636             auto valueNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &p.value));
637             CFDictionarySetValue(variationDictionary.get(), tagNumber.get(), valueNumber.get());
638         }
639         CFDictionaryAddValue(attributes.get(), kCTFontVariationAttribute, variationDictionary.get());
640     }
641 #endif
642
643     if (textRenderingMode == OptimizeLegibility) {
644         CGFloat size = CTFontGetSize(originalFont);
645         auto sizeNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &size));
646         CFDictionaryAddValue(attributes.get(), kCTFontOpticalSizeAttribute, sizeNumber.get());
647     }
648     auto descriptor = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
649     auto result = adoptCF(CTFontCreateCopyWithAttributes(originalFont, CTFontGetSize(originalFont), nullptr, descriptor.get()));
650     return result;
651 }
652
653 RefPtr<Font> FontCache::similarFont(const FontDescription& description, const AtomicString& family)
654 {
655     // Attempt to find an appropriate font using a match based on the presence of keywords in
656     // the requested names. For example, we'll match any name that contains "Arabic" to Geeza Pro.
657     if (family.isEmpty())
658         return nullptr;
659
660 #if PLATFORM(IOS)
661     // Substitute the default monospace font for well-known monospace fonts.
662     if (equalLettersIgnoringASCIICase(family, "monaco") || equalLettersIgnoringASCIICase(family, "menlo")) {
663         static NeverDestroyed<AtomicString> courier("courier", AtomicString::ConstructFromLiteral);
664         return fontForFamily(description, courier);
665     }
666
667     // Substitute Verdana for Lucida Grande.
668     if (equalLettersIgnoringASCIICase(family, "lucida grande")) {
669         static NeverDestroyed<AtomicString> verdana("verdana", AtomicString::ConstructFromLiteral);
670         return fontForFamily(description, verdana);
671     }
672 #endif
673
674     static NeverDestroyed<String> arabic(MAKE_STATIC_STRING_IMPL("Arabic"));
675     static NeverDestroyed<String> pashto(MAKE_STATIC_STRING_IMPL("Pashto"));
676     static NeverDestroyed<String> urdu(MAKE_STATIC_STRING_IMPL("Urdu"));
677     static String* matchWords[3] = { &arabic.get(), &pashto.get(), &urdu.get() };
678     static NeverDestroyed<AtomicString> geezaPlain("GeezaPro", AtomicString::ConstructFromLiteral);
679     static NeverDestroyed<AtomicString> geezaBold("GeezaPro-Bold", AtomicString::ConstructFromLiteral);
680     for (String* matchWord : matchWords) {
681         if (family.contains(*matchWord, false))
682             return fontForFamily(description, isFontWeightBold(description.weight()) ? geezaBold : geezaPlain);
683     }
684     return nullptr;
685 }
686
687 #if !HAS_CORE_TEXT_WIDTH_ATTRIBUTE
688 static float stretchFromCoreTextTraits(CFDictionaryRef traits)
689 {
690     auto widthNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits, kCTFontWidthTrait));
691     if (!widthNumber)
692         return normalStretchValue();
693
694     float ctWidth;
695     auto success = CFNumberGetValue(widthNumber, kCFNumberFloatType, &ctWidth);
696     ASSERT_UNUSED(success, success);
697     return normalizeWidth(ctWidth);
698 }
699 #endif
700
701 static void invalidateFontCache();
702
703 static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef name, const void *, CFDictionaryRef)
704 {
705     ASSERT_UNUSED(observer, observer == &FontCache::singleton());
706     ASSERT_UNUSED(name, CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification));
707
708     invalidateFontCache();
709 }
710
711 void FontCache::platformInit()
712 {
713     CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this, fontCacheRegisteredFontsChangedNotificationCallback, kCTFontManagerRegisteredFontsChangedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately);
714 }
715
716 Vector<String> FontCache::systemFontFamilies()
717 {
718     // FIXME: <rdar://problem/21890188>
719     auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, nullptr, nullptr, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
720     auto emptyFontDescriptor = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
721     auto matchedDescriptors = adoptCF(CTFontDescriptorCreateMatchingFontDescriptors(emptyFontDescriptor.get(), nullptr));
722     if (!matchedDescriptors)
723         return { };
724
725     CFIndex numMatches = CFArrayGetCount(matchedDescriptors.get());
726     if (!numMatches)
727         return { };
728
729     HashSet<String> visited;
730     for (CFIndex i = 0; i < numMatches; ++i) {
731         auto fontDescriptor = static_cast<CTFontDescriptorRef>(CFArrayGetValueAtIndex(matchedDescriptors.get(), i));
732         if (auto familyName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute))))
733             visited.add(familyName.get());
734     }
735
736     Vector<String> result;
737     copyToVector(visited, result);
738     return result;
739 }
740
741 static CTFontSymbolicTraits computeTraits(const FontDescription& fontDescription)
742 {
743     CTFontSymbolicTraits traits = 0;
744     if (fontDescription.italic())
745         traits |= kCTFontTraitItalic;
746     if (isFontWeightBold(fontDescription.weight()))
747         traits |= kCTFontTraitBold;
748     return traits;
749 }
750
751 SynthesisPair computeNecessarySynthesis(CTFontRef font, const FontDescription& fontDescription, bool isPlatformFont)
752 {
753 #if PLATFORM(IOS)
754     if (CTFontIsAppleColorEmoji(font))
755         return SynthesisPair(false, false);
756 #endif
757
758     if (isPlatformFont)
759         return SynthesisPair(false, false);
760
761     CTFontSymbolicTraits desiredTraits = computeTraits(fontDescription);
762
763     CTFontSymbolicTraits actualTraits = 0;
764     if (isFontWeightBold(fontDescription.weight()) || isItalic(fontDescription.italic()))
765         actualTraits = CTFontGetSymbolicTraits(font);
766
767     bool needsSyntheticBold = (fontDescription.fontSynthesis() & FontSynthesisWeight) && (desiredTraits & kCTFontTraitBold) && !(actualTraits & kCTFontTraitBold);
768     bool needsSyntheticOblique = (fontDescription.fontSynthesis() & FontSynthesisStyle) && (desiredTraits & kCTFontTraitItalic) && !(actualTraits & kCTFontTraitItalic);
769
770     return SynthesisPair(needsSyntheticBold, needsSyntheticOblique);
771 }
772
773 typedef HashSet<String, ASCIICaseInsensitiveHash> Whitelist;
774 static Whitelist& fontWhitelist()
775 {
776     static NeverDestroyed<Whitelist> whitelist;
777     return whitelist;
778 }
779
780 void FontCache::setFontWhitelist(const Vector<String>& inputWhitelist)
781 {
782     Whitelist& whitelist = fontWhitelist();
783     whitelist.clear();
784     for (auto& item : inputWhitelist)
785         whitelist.add(item);
786 }
787
788 static inline bool isSystemFont(const AtomicString& family)
789 {
790     // AtomicString's operator[] handles out-of-bounds by returning 0.
791     return family[0] == '.';
792 }
793
794 #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP
795 static float fontWeightFromCoreText(CGFloat weight)
796 {
797     if (weight < -0.6)
798         return 100;
799     if (weight < -0.365)
800         return 200;
801     if (weight < -0.115)
802         return 300;
803     if (weight <  0.130)
804         return 400;
805     if (weight <  0.235)
806         return 500;
807     if (weight <  0.350)
808         return 600;
809     if (weight <  0.500)
810         return 700;
811     if (weight <  0.700)
812         return 800;
813     return 900;
814 }
815 #endif
816
817 class FontDatabase {
818 public:
819     static FontDatabase& singleton()
820     {
821         static NeverDestroyed<FontDatabase> database;
822         return database;
823     }
824
825     FontDatabase(const FontDatabase&) = delete;
826     FontDatabase& operator=(const FontDatabase&) = delete;
827
828     struct InstalledFont {
829         InstalledFont() = default;
830
831         InstalledFont(CTFontDescriptorRef fontDescriptor)
832             : fontDescriptor(fontDescriptor)
833             , capabilities(capabilitiesForFontDescriptor(fontDescriptor))
834         {
835         }
836
837         RetainPtr<CTFontDescriptorRef> fontDescriptor;
838         FontSelectionCapabilities capabilities;
839     };
840
841     struct InstalledFontFamily {
842         InstalledFontFamily() = default;
843
844         explicit InstalledFontFamily(Vector<InstalledFont>&& installedFonts)
845             : installedFonts(WTFMove(installedFonts))
846         {
847             for (auto& font : this->installedFonts)
848                 expand(font);
849         }
850
851         void expand(const InstalledFont& installedFont)
852         {
853             capabilities.expand(installedFont.capabilities);
854         }
855
856         bool isEmpty() const
857         {
858             return installedFonts.isEmpty();
859         }
860
861         size_t size() const
862         {
863             return installedFonts.size();
864         }
865
866         Vector<InstalledFont> installedFonts;
867         FontSelectionCapabilities capabilities;
868     };
869
870     const InstalledFontFamily& collectionForFamily(const String& familyName)
871     {
872         auto folded = familyName.foldCase();
873         return m_familyNameToFontDescriptors.ensure(folded, [&] {
874             auto familyNameString = folded.createCFString();
875             CFTypeRef keys[] = { kCTFontFamilyNameAttribute };
876             CFTypeRef values[] = { familyNameString.get() };
877             auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
878             auto fontDescriptorToMatch = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
879             if (auto matches = adoptCF(CTFontDescriptorCreateMatchingFontDescriptors(fontDescriptorToMatch.get(), nullptr))) {
880                 auto count = CFArrayGetCount(matches.get());
881                 Vector<InstalledFont> result;
882                 result.reserveInitialCapacity(count);
883                 for (CFIndex i = 0; i < count; ++i) {
884                     InstalledFont installedFont(static_cast<CTFontDescriptorRef>(CFArrayGetValueAtIndex(matches.get(), i)));
885                     result.uncheckedAppend(WTFMove(installedFont));
886                 }
887                 return InstalledFontFamily(WTFMove(result));
888             }
889             return InstalledFontFamily();
890         }).iterator->value;
891     }
892
893     const InstalledFont& fontForPostScriptName(const AtomicString& postScriptName)
894     {
895         auto folded = postScriptName.string().foldCase();
896         return m_postScriptNameToFontDescriptors.ensure(folded, [&] {
897             auto postScriptNameString = folded.createCFString();
898             CFTypeRef keys[] = { kCTFontEnabledAttribute, kCTFontNameAttribute };
899             CFTypeRef values[] = { kCFBooleanTrue, postScriptNameString.get() };
900             auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
901             auto fontDescriptorToMatch = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
902             auto match = adoptCF(static_cast<CTFontDescriptorRef>(CTFontDescriptorCreateMatchingFontDescriptor(fontDescriptorToMatch.get(), nullptr)));
903             return InstalledFont(match.get());
904         }).iterator->value;
905     }
906
907     void clear()
908     {
909         m_familyNameToFontDescriptors.clear();
910         m_postScriptNameToFontDescriptors.clear();
911     }
912
913 private:
914     friend class NeverDestroyed<FontDatabase>;
915
916     FontDatabase() = default;
917
918     HashMap<String, InstalledFontFamily> m_familyNameToFontDescriptors;
919     HashMap<String, InstalledFont> m_postScriptNameToFontDescriptors;
920 };
921
922 // Because this struct holds intermediate values which may be in the compressed -1 - 1 GX range, we don't want to use the relatively large
923 // quantization of FontSelectionValue. Instead, do this logic with floats.
924 struct MinMax {
925     float minimum;
926     float maximum;
927 };
928
929 struct VariationCapabilities {
930     std::optional<MinMax> weight;
931     std::optional<MinMax> width;
932     std::optional<MinMax> slope;
933 };
934
935 #if ENABLE(VARIATION_FONTS)
936 static std::optional<MinMax> extractVariationBounds(CFDictionaryRef axis)
937 {
938     CFNumberRef minimumValue = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisMinimumValueKey));
939     CFNumberRef maximumValue = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisMaximumValueKey));
940     float rawMinimumValue = 0;
941     float rawMaximumValue = 0;
942     CFNumberGetValue(minimumValue, kCFNumberFloatType, &rawMinimumValue);
943     CFNumberGetValue(maximumValue, kCFNumberFloatType, &rawMaximumValue);
944     if (rawMinimumValue < rawMaximumValue)
945         return {{ rawMinimumValue, rawMaximumValue }};
946     return std::nullopt;
947 }
948 #endif
949
950 static VariationCapabilities variationCapabilitiesForFontDescriptor(CTFontDescriptorRef fontDescriptor)
951 {
952     VariationCapabilities result;
953
954 #if ENABLE(VARIATION_FONTS)
955     if (!adoptCF(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontVariationAttribute)))
956         return result;
957
958     auto font = adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor, 0, nullptr));
959     auto variations = adoptCF(CTFontCopyVariationAxes(font.get()));
960     if (!variations)
961         return result;
962
963     auto axisCount = CFArrayGetCount(variations.get());
964     if (!axisCount)
965         return result;
966
967     for (CFIndex i = 0; i < axisCount; ++i) {
968         CFDictionaryRef axis = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(variations.get(), i));
969         CFNumberRef axisIdentifier = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisIdentifierKey));
970         uint32_t rawAxisIdentifier = 0;
971         Boolean success = CFNumberGetValue(axisIdentifier, kCFNumberSInt32Type, &rawAxisIdentifier);
972         ASSERT_UNUSED(success, success);
973         if (rawAxisIdentifier == 0x77676874) // 'wght'
974             result.weight = extractVariationBounds(axis);
975         else if (rawAxisIdentifier == 0x77647468) // 'wdth'
976             result.width = extractVariationBounds(axis);
977         else if (rawAxisIdentifier == 0x736C6E74) // 'slnt'
978             result.slope = extractVariationBounds(axis);
979     }
980
981     if (isGXVariableFont(font.get())) {
982         if (result.weight)
983             result.weight = {{ normalizeWeight(result.weight.value().minimum), normalizeWeight(result.weight.value().maximum) }};
984         if (result.width)
985             result.width = {{ normalizeVariationWidth(result.width.value().minimum), normalizeVariationWidth(result.width.value().maximum) }};
986         if (result.slope)
987             result.slope = {{ normalizeSlope(result.slope.value().minimum), normalizeSlope(result.slope.value().maximum) }};
988     }
989 #else
990     UNUSED_PARAM(fontDescriptor);
991 #endif
992
993     return result;
994 }
995
996 #if !SHOULD_USE_CORE_TEXT_FONT_LOOKUP || HAS_CORE_TEXT_WIDTH_ATTRIBUTE
997 static float getCSSAttribute(CTFontDescriptorRef fontDescriptor, const CFStringRef attribute, float fallback)
998 {
999     auto number = adoptCF(static_cast<CFNumberRef>(CTFontDescriptorCopyAttribute(fontDescriptor, attribute)));
1000     if (!number)
1001         return fallback;
1002     float cssValue;
1003     auto success = CFNumberGetValue(number.get(), kCFNumberFloatType, &cssValue);
1004     ASSERT_UNUSED(success, success);
1005     return cssValue;
1006 }
1007 #endif
1008
1009 FontSelectionCapabilities capabilitiesForFontDescriptor(CTFontDescriptorRef fontDescriptor)
1010 {
1011     if (!fontDescriptor)
1012         return { };
1013
1014     VariationCapabilities variationCapabilities = variationCapabilitiesForFontDescriptor(fontDescriptor);
1015
1016 #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP || !HAS_CORE_TEXT_WIDTH_ATTRIBUTE
1017     bool weightOrWidthComeFromTraits = !variationCapabilities.weight || !variationCapabilities.width;
1018 #else
1019     bool weightOrWidthComeFromTraits = false;
1020 #endif
1021
1022     if (!variationCapabilities.slope || weightOrWidthComeFromTraits) {
1023         auto traits = adoptCF(static_cast<CFDictionaryRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontTraitsAttribute)));
1024         if (traits) {
1025 #if !HAS_CORE_TEXT_WIDTH_ATTRIBUTE
1026             if (!variationCapabilities.width) {
1027                 auto widthValue = stretchFromCoreTextTraits(traits.get());
1028                 variationCapabilities.width = {{ widthValue, widthValue }};
1029             }
1030 #endif
1031
1032             if (!variationCapabilities.slope) {
1033                 auto symbolicTraitsNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait));
1034                 if (symbolicTraitsNumber) {
1035                     int32_t symbolicTraits;
1036                     auto success = CFNumberGetValue(symbolicTraitsNumber, kCFNumberSInt32Type, &symbolicTraits);
1037                     ASSERT_UNUSED(success, success);
1038                     auto slopeValue = static_cast<float>(symbolicTraits & kCTFontTraitItalic ? italicValue() : normalItalicValue());
1039                     variationCapabilities.slope = {{ slopeValue, slopeValue }};
1040                 } else
1041                     variationCapabilities.slope = {{ static_cast<float>(normalItalicValue()), static_cast<float>(normalItalicValue()) }};
1042             }
1043
1044 #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP
1045             if (!variationCapabilities.weight) {
1046                 auto weightNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontWeightTrait));
1047                 if (weightNumber) {
1048                     CGFloat ctWeight;
1049                     auto success = CFNumberGetValue(weightNumber, kCFNumberCGFloatType, &ctWeight);
1050                     ASSERT_UNUSED(success, success);
1051                     auto weightValue = fontWeightFromCoreText(ctWeight);
1052                     variationCapabilities.weight = {{ weightValue, weightValue }};
1053                 } else
1054                     variationCapabilities.weight = {{ static_cast<float>(normalWeightValue()), static_cast<float>(normalWeightValue()) }};
1055             }
1056 #endif
1057         }
1058     }
1059
1060 #if !SHOULD_USE_CORE_TEXT_FONT_LOOKUP
1061     if (!variationCapabilities.weight) {
1062         auto value = getCSSAttribute(fontDescriptor, kCTFontCSSWeightAttribute, static_cast<float>(normalWeightValue()));
1063         variationCapabilities.weight = {{ value, value }};
1064     }
1065 #endif
1066
1067 #if HAS_CORE_TEXT_WIDTH_ATTRIBUTE
1068     if (!variationCapabilities.width) {
1069         auto value = getCSSAttribute(fontDescriptor, kCTFontCSSWidthAttribute, static_cast<float>(normalStretchValue()));
1070         variationCapabilities.width = {{ value, value }};
1071     }
1072 #endif
1073
1074     return {{ FontSelectionValue(variationCapabilities.weight.value().minimum), FontSelectionValue(variationCapabilities.weight.value().maximum) },
1075         { FontSelectionValue(variationCapabilities.width.value().minimum), FontSelectionValue(variationCapabilities.width.value().maximum) },
1076         { FontSelectionValue(variationCapabilities.slope.value().minimum), FontSelectionValue(variationCapabilities.slope.value().maximum) }};
1077 }
1078
1079 #if !SHOULD_USE_CORE_TEXT_FONT_LOOKUP
1080 static const FontDatabase::InstalledFont* findClosestFont(const FontDatabase::InstalledFontFamily& familyFonts, FontSelectionRequest fontSelectionRequest)
1081 {
1082     Vector<FontSelectionCapabilities> capabilities;
1083     capabilities.reserveInitialCapacity(familyFonts.size());
1084     for (auto& font : familyFonts.installedFonts)
1085         capabilities.uncheckedAppend(font.capabilities);
1086     FontSelectionAlgorithm fontSelectionAlgorithm(fontSelectionRequest, capabilities, familyFonts.capabilities);
1087     return &familyFonts.installedFonts[fontSelectionAlgorithm.indexOfBestCapabilities()];
1088 }
1089 #endif
1090
1091 Vector<FontSelectionCapabilities> FontCache::getFontSelectionCapabilitiesInFamily(const AtomicString& familyName)
1092 {
1093     const auto& fonts = FontDatabase::singleton().collectionForFamily(familyName.string());
1094     if (fonts.isEmpty())
1095         return { };
1096
1097     Vector<FontSelectionCapabilities> result;
1098     result.reserveInitialCapacity(fonts.size());
1099     for (const auto& font : fonts.installedFonts)
1100         result.uncheckedAppend(font.capabilities);
1101     return result;
1102 }
1103
1104 static RetainPtr<CTFontRef> platformFontLookupWithFamily(const AtomicString& family, FontSelectionRequest request, float size)
1105 {
1106     const auto& whitelist = fontWhitelist();
1107     if (!isSystemFont(family) && whitelist.size() && !whitelist.contains(family))
1108         return nullptr;
1109
1110 #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP
1111     CTFontSymbolicTraits traits = (isFontWeightBold(request.weight) ? kCTFontTraitBold : 0) | (isItalic(request.slope) ? kCTFontTraitItalic : 0);
1112     return adoptCF(CTFontCreateForCSS(family.string().createCFString().get(), static_cast<float>(request.weight), traits, size));
1113 #else
1114     const auto& familyFonts = FontDatabase::singleton().collectionForFamily(family.string());
1115     if (familyFonts.isEmpty()) {
1116         // The CSS spec states that font-family only accepts a name of an actual font family. However, in WebKit, we claim to also
1117         // support supplying a PostScript name instead. However, this creates problems when the other properties (font-weight,
1118         // font-style) disagree with the traits of the PostScript-named font. The solution we have come up with is, when the default
1119         // values for font-weight and font-style are supplied, honor the PostScript name, but if font-weight specifies bold or
1120         // font-style specifies italic, then we run the regular matching algorithm on the family of the PostScript font. This way,
1121         // if content simply states "font-family: PostScriptName;" without specifying the other font properties, it will be honored,
1122         // but if a <b> appears as a descendent element, it will be honored too.
1123         const auto& postScriptFont = FontDatabase::singleton().fontForPostScriptName(family);
1124         if (!postScriptFont.fontDescriptor)
1125             return nullptr;
1126         if ((isItalic(request.slope) && !isItalic(postScriptFont.capabilities.slope.maximum))
1127             || (isFontWeightBold(request.weight) && !isFontWeightBold(postScriptFont.capabilities.weight.maximum))) {
1128             auto postScriptFamilyName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(postScriptFont.fontDescriptor.get(), kCTFontFamilyNameAttribute)));
1129             if (!postScriptFamilyName)
1130                 return nullptr;
1131             const auto& familyFonts = FontDatabase::singleton().collectionForFamily(String(postScriptFamilyName.get()));
1132             if (familyFonts.isEmpty())
1133                 return nullptr;
1134             if (const auto* installedFont = findClosestFont(familyFonts, request)) {
1135                 if (!installedFont->fontDescriptor)
1136                     return nullptr;
1137                 return adoptCF(CTFontCreateWithFontDescriptor(installedFont->fontDescriptor.get(), size, nullptr));
1138             }
1139             return nullptr;
1140         }
1141         return adoptCF(CTFontCreateWithFontDescriptor(postScriptFont.fontDescriptor.get(), size, nullptr));
1142     }
1143
1144     if (const auto* installedFont = findClosestFont(familyFonts, request))
1145         return adoptCF(CTFontCreateWithFontDescriptor(installedFont->fontDescriptor.get(), size, nullptr));
1146
1147     return nullptr;
1148 #endif
1149 }
1150
1151 static void invalidateFontCache()
1152 {
1153     if (!isMainThread()) {
1154         callOnMainThread([] {
1155             invalidateFontCache();
1156         });
1157         return;
1158     }
1159
1160     FontDatabase::singleton().clear();
1161
1162     FontCache::singleton().invalidate();
1163 }
1164
1165 static RetainPtr<CTFontRef> fontWithFamily(const AtomicString& family, FontSelectionRequest request, const FontFeatureSettings& featureSettings, const FontVariantSettings& variantSettings, const FontVariationSettings& variationSettings, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, FontSelectionSpecifiedCapabilities fontFaceCapabilities, const TextRenderingMode& textRenderingMode, FontSelectionRequest fontSelectionRequest, FontOpticalSizing fontOpticalSizing, float size)
1166 {
1167     if (family.isEmpty())
1168         return nullptr;
1169
1170     auto foundFont = platformFontWithFamilySpecialCase(family, request, size);
1171     if (!foundFont)
1172         foundFont = platformFontLookupWithFamily(family, request, size);
1173     return preparePlatformFont(foundFont.get(), textRenderingMode, fontFaceFeatures, fontFaceVariantSettings, fontFaceCapabilities, featureSettings, variantSettings, fontSelectionRequest, variationSettings, fontOpticalSizing, size);
1174 }
1175
1176 #if PLATFORM(MAC)
1177 static bool shouldAutoActivateFontIfNeeded(const AtomicString& family)
1178 {
1179 #ifndef NDEBUG
1180     // This cache is not thread safe so the following assertion is there to
1181     // make sure this function is always called from the same thread.
1182     static ThreadIdentifier initThreadId = currentThread();
1183     ASSERT(currentThread() == initThreadId);
1184 #endif
1185
1186     static NeverDestroyed<HashSet<AtomicString>> knownFamilies;
1187     static const unsigned maxCacheSize = 128;
1188     ASSERT(knownFamilies.get().size() <= maxCacheSize);
1189     if (knownFamilies.get().size() == maxCacheSize)
1190         knownFamilies.get().remove(knownFamilies.get().begin());
1191
1192     // Only attempt to auto-activate fonts once for performance reasons.
1193     return knownFamilies.get().add(family).isNewEntry;
1194 }
1195
1196 static void autoActivateFont(const String& name, CGFloat size)
1197 {
1198     auto fontName = name.createCFString();
1199     CFTypeRef keys[] = { kCTFontNameAttribute };
1200     CFTypeRef values[] = { fontName.get() };
1201     auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
1202     auto descriptor = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
1203     if (auto newFont = CTFontCreateWithFontDescriptor(descriptor.get(), size, nullptr))
1204         CFRelease(newFont);
1205 }
1206 #endif
1207
1208 std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, FontSelectionSpecifiedCapabilities fontFaceCapabilities)
1209 {
1210     float size = fontDescription.computedPixelSize();
1211
1212     auto font = fontWithFamily(family, fontDescription.fontSelectionRequest(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontDescription.variationSettings(), fontFaceFeatures, fontFaceVariantSettings, fontFaceCapabilities, fontDescription.textRenderingMode(), fontDescription.fontSelectionRequest(), fontDescription.opticalSizing(), size);
1213
1214 #if PLATFORM(MAC)
1215     if (!font) {
1216         if (!shouldAutoActivateFontIfNeeded(family))
1217             return nullptr;
1218
1219         // Auto activate the font before looking for it a second time.
1220         // Ignore the result because we want to use our own algorithm to actually find the font.
1221         autoActivateFont(family.string(), size);
1222
1223         font = fontWithFamily(family, fontDescription.fontSelectionRequest(), fontDescription.featureSettings(), fontDescription.variantSettings(), fontDescription.variationSettings(), fontFaceFeatures, fontFaceVariantSettings, fontFaceCapabilities, fontDescription.textRenderingMode(), fontDescription.fontSelectionRequest(), fontDescription.opticalSizing(), size);
1224     }
1225 #endif
1226
1227     if (!font)
1228         return nullptr;
1229
1230     bool syntheticBold, syntheticOblique;
1231     std::tie(syntheticBold, syntheticOblique) = computeNecessarySynthesis(font.get(), fontDescription).boldObliquePair();
1232
1233     return std::make_unique<FontPlatformData>(font.get(), size, syntheticBold, syntheticOblique, fontDescription.orientation(), fontDescription.widthVariant(), fontDescription.textRenderingMode());
1234 }
1235
1236 typedef HashSet<RetainPtr<CTFontRef>, WTF::RetainPtrObjectHash<CTFontRef>, WTF::RetainPtrObjectHashTraits<CTFontRef>> FallbackDedupSet;
1237 static FallbackDedupSet& fallbackDedupSet()
1238 {
1239     static NeverDestroyed<FallbackDedupSet> dedupSet;
1240     return dedupSet.get();
1241 }
1242
1243 void FontCache::platformPurgeInactiveFontData()
1244 {
1245     Vector<CTFontRef> toRemove;
1246     for (auto& font : fallbackDedupSet()) {
1247         if (CFGetRetainCount(font.get()) == 1)
1248             toRemove.append(font.get());
1249     }
1250     for (auto& font : toRemove)
1251         fallbackDedupSet().remove(font);
1252 }
1253
1254 #if PLATFORM(IOS)
1255 static inline bool isArabicCharacter(UChar character)
1256 {
1257     return character >= 0x0600 && character <= 0x06FF;
1258 }
1259 #endif
1260
1261 static RetainPtr<CTFontRef> lookupFallbackFont(CTFontRef font, FontSelectionValue fontWeight, const AtomicString& locale, const UChar* characters, unsigned length)
1262 {
1263     ASSERT(length > 0);
1264
1265     RetainPtr<CFStringRef> localeString;
1266 #if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
1267     if (!locale.isNull())
1268         localeString = locale.string().createCFString();
1269 #else
1270     UNUSED_PARAM(locale);
1271 #endif
1272
1273     CFIndex coveredLength = 0;
1274     auto result = adoptCF(CTFontCreateForCharactersWithLanguage(font, characters, length, localeString.get(), &coveredLength));
1275
1276 #if PLATFORM(IOS)
1277     // Callers of this function won't include multiple code points. "Length" is to know how many code units
1278     // are in the code point.
1279     UChar firstCharacter = characters[0];
1280     if (isArabicCharacter(firstCharacter)) {
1281         auto familyName = adoptCF(static_cast<CFStringRef>(CTFontCopyAttribute(result.get(), kCTFontFamilyNameAttribute)));
1282         if (fontFamilyShouldNotBeUsedForArabic(familyName.get())) {
1283             CFStringRef newFamilyName = isFontWeightBold(fontWeight) ? CFSTR("GeezaPro-Bold") : CFSTR("GeezaPro");
1284             CFTypeRef keys[] = { kCTFontNameAttribute };
1285             CFTypeRef values[] = { newFamilyName };
1286             auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
1287             auto modification = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
1288             result = adoptCF(CTFontCreateCopyWithAttributes(result.get(), CTFontGetSize(result.get()), nullptr, modification.get()));
1289         }
1290     }
1291 #else
1292     UNUSED_PARAM(fontWeight);
1293 #endif
1294
1295     return result;
1296 }
1297
1298 RefPtr<Font> FontCache::systemFallbackForCharacters(const FontDescription& description, const Font* originalFontData, bool isPlatformFont, const UChar* characters, unsigned length)
1299 {
1300 #if PLATFORM(IOS)
1301     if (length && requiresCustomFallbackFont(*characters)) {
1302         auto* fallback = getCustomFallbackFont(*characters, description);
1303         if (!fallback)
1304             return nullptr;
1305         return fontForPlatformData(*fallback);
1306     }
1307 #endif
1308
1309     const FontPlatformData& platformData = originalFontData->platformData();
1310     auto result = lookupFallbackFont(platformData.font(), description.weight(), description.locale(), characters, length);
1311     result = preparePlatformFont(result.get(), description.textRenderingMode(), nullptr, nullptr, { }, description.featureSettings(), description.variantSettings(), description.fontSelectionRequest(), description.variationSettings(), description.opticalSizing(), description.computedSize());
1312     if (!result)
1313         return lastResortFallbackFont(description);
1314
1315     // FontCascade::drawGlyphBuffer() requires that there are no duplicate Font objects which refer to the same thing. This is enforced in
1316     // FontCache::fontForPlatformData(), where our equality check is based on hashing the FontPlatformData, whose hash includes the raw CoreText
1317     // font pointer.
1318     CTFontRef substituteFont = fallbackDedupSet().add(result).iterator->get();
1319
1320     bool syntheticBold, syntheticOblique;
1321     std::tie(syntheticBold, syntheticOblique) = computeNecessarySynthesis(substituteFont, description, isPlatformFont).boldObliquePair();
1322
1323     FontPlatformData alternateFont(substituteFont, platformData.size(), syntheticBold, syntheticOblique, platformData.orientation(), platformData.widthVariant(), platformData.textRenderingMode());
1324
1325     return fontForPlatformData(alternateFont);
1326 }
1327
1328 const AtomicString& FontCache::platformAlternateFamilyName(const AtomicString& familyName)
1329 {
1330     static const UChar heitiString[] = { 0x9ed1, 0x4f53 };
1331     static const UChar songtiString[] = { 0x5b8b, 0x4f53 };
1332     static const UChar weiruanXinXiMingTi[] = { 0x5fae, 0x8edf, 0x65b0, 0x7d30, 0x660e, 0x9ad4 };
1333     static const UChar weiruanYaHeiString[] = { 0x5fae, 0x8f6f, 0x96c5, 0x9ed1 };
1334     static const UChar weiruanZhengHeitiString[] = { 0x5fae, 0x8edf, 0x6b63, 0x9ed1, 0x9ad4 };
1335
1336     static NeverDestroyed<AtomicString> songtiSC("Songti SC", AtomicString::ConstructFromLiteral);
1337     static NeverDestroyed<AtomicString> songtiTC("Songti TC", AtomicString::ConstructFromLiteral);
1338 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101100
1339     static NeverDestroyed<AtomicString> heitiSCReplacement("Heiti SC", AtomicString::ConstructFromLiteral);
1340     static NeverDestroyed<AtomicString> heitiTCReplacement("Heiti TC", AtomicString::ConstructFromLiteral);
1341 #else
1342     static NeverDestroyed<AtomicString> heitiSCReplacement("PingFang SC", AtomicString::ConstructFromLiteral);
1343     static NeverDestroyed<AtomicString> heitiTCReplacement("PingFang TC", AtomicString::ConstructFromLiteral);
1344 #endif
1345
1346     switch (familyName.length()) {
1347     case 2:
1348         if (equal(familyName, songtiString))
1349             return songtiSC;
1350         if (equal(familyName, heitiString))
1351             return heitiSCReplacement;
1352         break;
1353     case 4:
1354         if (equal(familyName, weiruanYaHeiString))
1355             return heitiSCReplacement;
1356         break;
1357     case 5:
1358         if (equal(familyName, weiruanZhengHeitiString))
1359             return heitiTCReplacement;
1360         break;
1361     case 6:
1362         if (equalLettersIgnoringASCIICase(familyName, "simsun"))
1363             return songtiSC;
1364         if (equal(familyName, weiruanXinXiMingTi))
1365             return songtiTC;
1366         break;
1367     case 10:
1368         if (equalLettersIgnoringASCIICase(familyName, "ms mingliu"))
1369             return songtiTC;
1370         if (equalIgnoringASCIICase(familyName, "\\5b8b\\4f53"))
1371             return songtiSC;
1372         break;
1373 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101100
1374     case 15:
1375         if (equalLettersIgnoringASCIICase(familyName, "microsoft yahei"))
1376             return heitiSCReplacement;
1377         break;
1378 #endif
1379     case 18:
1380         if (equalLettersIgnoringASCIICase(familyName, "microsoft jhenghei"))
1381             return heitiTCReplacement;
1382         break;
1383     }
1384
1385     return nullAtom;
1386 }
1387
1388 }