611edfb472c8b9e7b0542d68e20ef9e75bb0d5ce
[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 "Font.h"
30 #include <pal/spi/cocoa/CoreTextSPI.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         if (rawMinimumValue > rawMaximumValue)
402             std::swap(rawMinimumValue, rawMaximumValue);
403
404         auto b1 = rawAxisIdentifier >> 24;
405         auto b2 = (rawAxisIdentifier & 0xFF0000) >> 16;
406         auto b3 = (rawAxisIdentifier & 0xFF00) >> 8;
407         auto b4 = rawAxisIdentifier & 0xFF;
408         FontTag resultKey = {{ static_cast<char>(b1), static_cast<char>(b2), static_cast<char>(b3), static_cast<char>(b4) }};
409         VariationDefaults resultValues = { rawDefaultValue, rawMinimumValue, rawMaximumValue };
410         result.set(resultKey, resultValues);
411     }
412     return result;
413 }
414
415 static inline bool fontIsSystemFont(CTFontRef font)
416 {
417     if (CTFontDescriptorIsSystemUIFont(adoptCF(CTFontCopyFontDescriptor(font)).get()))
418         return true;
419     auto name = adoptCF(CTFontCopyPostScriptName(font));
420     return CFStringGetLength(name.get()) > 0 && CFStringGetCharacterAtIndex(name.get(), 0) == '.';
421 }
422
423 // These values were calculated by performing a linear regression on the CSS weights/widths/slopes and Core Text weights/widths/slopes of San Francisco.
424 // FIXME: <rdar://problem/31312602> Get the real values from Core Text.
425 static inline float normalizeWeight(float value)
426 {
427     return 523.7 * value - 109.3;
428 }
429
430 static inline float normalizeSlope(float value)
431 {
432     return value * 300;
433 }
434
435 static inline float denormalizeWeight(float value)
436 {
437     return (value + 109.3) / 523.7;
438 }
439
440 static inline float denormalizeSlope(float value)
441 {
442     return value / 300;
443 }
444
445 static inline float denormalizeVariationWidth(float value)
446 {
447     if (value <= 125)
448         return value / 100;
449     if (value <= 150)
450         return (value + 125) / 200;
451     return (value + 400) / 400;
452 }
453 #endif
454
455 #if ENABLE(VARIATION_FONTS) || !HAS_CORE_TEXT_WIDTH_ATTRIBUTE
456 static inline float normalizeVariationWidth(float value)
457 {
458     if (value <= 1.25)
459         return value * 100;
460     if (value <= 1.375)
461         return value * 200 - 125;
462     return value * 400 - 400;
463 }
464 #endif
465
466 #if !HAS_CORE_TEXT_WIDTH_ATTRIBUTE
467 static inline float normalizeWidth(float value)
468 {
469     return normalizeVariationWidth(value + 1);
470 }
471 #endif
472
473 struct FontType {
474     FontType(CTFontRef font)
475     {
476         auto tables = adoptCF(CTFontCopyAvailableTables(font, kCTFontTableOptionNoOptions));
477         if (!tables)
478             return;
479         auto size = CFArrayGetCount(tables.get());
480         for (CFIndex i = 0; i < size; ++i) {
481             // This is so yucky.
482             // https://developer.apple.com/reference/coretext/1510774-ctfontcopyavailabletables
483             // "The returned set will contain unboxed values, which can be extracted like so:"
484             // "CTFontTableTag tag = (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tags, index);"
485             CTFontTableTag tableTag = static_cast<CTFontTableTag>(reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(tables.get(), i)));
486             switch (tableTag) {
487             case 'fvar':
488                 if (variationType == VariationType::NotVariable)
489                     variationType = VariationType::TrueTypeGX;
490                 break;
491             case 'STAT':
492                 variationType = VariationType::OpenType18;
493                 break;
494             case 'morx':
495             case 'mort':
496                 aatShaping = true;
497                 break;
498             case 'GPOS':
499             case 'GSUB':
500                 openTypeShaping = true;
501                 break;
502             }
503         }
504     }
505
506     enum class VariationType {
507         NotVariable,
508         TrueTypeGX,
509         OpenType18
510     };
511     VariationType variationType { VariationType::NotVariable };
512     bool openTypeShaping { false };
513     bool aatShaping { false };
514 };
515
516 RetainPtr<CTFontRef> preparePlatformFont(CTFontRef originalFont, const FontDescription& fontDescription, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, FontSelectionSpecifiedCapabilities fontFaceCapabilities, float size, bool applyWeightWidthSlopeVariations)
517 {
518     bool alwaysAddVariations = false;
519
520     // FIXME: Remove when <rdar://problem/29859207> is fixed
521 #if ENABLE(VARIATION_FONTS)
522     auto defaultValues = defaultVariationValues(originalFont);
523     alwaysAddVariations = !defaultValues.isEmpty();
524
525     auto fontSelectionRequest = fontDescription.fontSelectionRequest();
526     auto fontOpticalSizing = fontDescription.opticalSizing();
527     auto fontStyleAxis = fontDescription.fontStyleAxis();
528 #else
529     UNUSED_PARAM(fontFaceCapabilities);
530     UNUSED_PARAM(size);
531     UNUSED_PARAM(applyWeightWidthSlopeVariations);
532 #endif
533
534     const auto& features = fontDescription.featureSettings();
535     const auto& variantSettings = fontDescription.variantSettings();
536     const auto& variations = fontDescription.variationSettings();
537     auto textRenderingMode = fontDescription.textRenderingMode();
538
539     if (!originalFont || (!features.size() && (!alwaysAddVariations && variations.isEmpty()) && (textRenderingMode == AutoTextRendering) && variantSettings.isAllNormal()
540         && (!fontFaceFeatures || !fontFaceFeatures->size()) && (!fontFaceVariantSettings || fontFaceVariantSettings->isAllNormal())))
541         return originalFont;
542
543     // This algorithm is described at http://www.w3.org/TR/css3-fonts/#feature-precedence
544     FeaturesMap featuresToBeApplied;
545
546     // Step 1: CoreText handles default features (such as required ligatures).
547
548     // Step 2: Consult with font-variant-* inside @font-face
549     if (fontFaceVariantSettings)
550         featuresToBeApplied = computeFeatureSettingsFromVariants(*fontFaceVariantSettings);
551
552     // Step 3: Consult with font-feature-settings inside @font-face
553     if (fontFaceFeatures) {
554         for (auto& fontFaceFeature : *fontFaceFeatures)
555             featuresToBeApplied.set(fontFaceFeature.tag(), fontFaceFeature.value());
556     }
557
558     // Step 4: Font-variant
559     for (auto& newFeature : computeFeatureSettingsFromVariants(variantSettings))
560         featuresToBeApplied.set(newFeature.key, newFeature.value);
561
562     // Step 5: Other properties (text-rendering)
563     if (textRenderingMode == OptimizeSpeed) {
564         featuresToBeApplied.set(fontFeatureTag("liga"), 0);
565         featuresToBeApplied.set(fontFeatureTag("clig"), 0);
566         featuresToBeApplied.set(fontFeatureTag("dlig"), 0);
567         featuresToBeApplied.set(fontFeatureTag("hlig"), 0);
568         featuresToBeApplied.set(fontFeatureTag("calt"), 0);
569     }
570
571     // Step 6: Font-feature-settings
572     for (auto& newFeature : features)
573         featuresToBeApplied.set(newFeature.tag(), newFeature.value());
574
575     FontType fontType(originalFont);
576
577 #if ENABLE(VARIATION_FONTS)
578     VariationsMap variationsToBeApplied;
579
580     bool needsConversion = fontType.variationType == FontType::VariationType::TrueTypeGX;
581
582     auto applyVariation = [&](const FontTag& tag, float value) {
583         auto iterator = defaultValues.find(tag);
584         if (iterator == defaultValues.end())
585             return;
586         float valueToApply = clampTo(value, iterator->value.minimumValue, iterator->value.maximumValue);
587         variationsToBeApplied.set(tag, valueToApply);
588     };
589
590     // The system font is somewhat magical. Don't mess with its variations.
591     if (applyWeightWidthSlopeVariations && !fontIsSystemFont(originalFont)) {
592         float weight = fontSelectionRequest.weight;
593         float width = fontSelectionRequest.width;
594         float slope = fontSelectionRequest.slope;
595         if (auto weightValue = fontFaceCapabilities.weight)
596             weight = std::max(std::min(weight, static_cast<float>(weightValue->maximum)), static_cast<float>(weightValue->minimum));
597         if (auto widthValue = fontFaceCapabilities.width)
598             width = std::max(std::min(width, static_cast<float>(widthValue->maximum)), static_cast<float>(widthValue->minimum));
599         if (auto slopeValue = fontFaceCapabilities.weight)
600             slope = std::max(std::min(slope, static_cast<float>(slopeValue->maximum)), static_cast<float>(slopeValue->minimum));
601         if (needsConversion) {
602             weight = denormalizeWeight(weight);
603             width = denormalizeVariationWidth(width);
604             slope = denormalizeSlope(slope);
605         }
606         applyVariation({{'w', 'g', 'h', 't'}}, weight);
607         applyVariation({{'w', 'd', 't', 'h'}}, width);
608         if (fontStyleAxis == FontStyleAxis::ital)
609             applyVariation({{'i', 't', 'a', 'l'}}, 1);
610         else
611             applyVariation({{'s', 'l', 'n', 't'}}, slope);
612     }
613
614     if (fontOpticalSizing == FontOpticalSizing::Enabled) {
615         const float pxToPtRatio = 3.0f / 4;
616         applyVariation({{'o', 'p', 's', 'z'}}, size * pxToPtRatio);
617     }
618
619     for (auto& newVariation : variations)
620         applyVariation(newVariation.tag(), newVariation.value());
621
622 #endif // ENABLE(VARIATION_FONTS)
623
624     auto attributes = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
625     if (!featuresToBeApplied.isEmpty()) {
626         auto featureArray = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, features.size(), &kCFTypeArrayCallBacks));
627         for (auto& p : featuresToBeApplied) {
628             auto feature = FontFeature(p.key, p.value);
629             if (fontType.aatShaping)
630                 appendTrueTypeFeature(featureArray.get(), feature);
631             if (fontType.openTypeShaping)
632                 appendOpenTypeFeature(featureArray.get(), feature);
633         }
634         CFDictionaryAddValue(attributes.get(), kCTFontFeatureSettingsAttribute, featureArray.get());
635     }
636
637 #if ENABLE(VARIATION_FONTS)
638     if (!variationsToBeApplied.isEmpty()) {
639         auto variationDictionary = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
640         for (auto& p : variationsToBeApplied) {
641             long long bitwiseTag = p.key[0] << 24 | p.key[1] << 16 | p.key[2] << 8 | p.key[3];
642             auto tagNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &bitwiseTag));
643             auto valueNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &p.value));
644             CFDictionarySetValue(variationDictionary.get(), tagNumber.get(), valueNumber.get());
645         }
646         CFDictionaryAddValue(attributes.get(), kCTFontVariationAttribute, variationDictionary.get());
647     }
648 #endif
649
650     if (textRenderingMode == OptimizeLegibility) {
651         CGFloat size = CTFontGetSize(originalFont);
652         auto sizeNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &size));
653         CFDictionaryAddValue(attributes.get(), kCTFontOpticalSizeAttribute, sizeNumber.get());
654     }
655     auto descriptor = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
656     auto result = adoptCF(CTFontCreateCopyWithAttributes(originalFont, CTFontGetSize(originalFont), nullptr, descriptor.get()));
657     return result;
658 }
659
660 RefPtr<Font> FontCache::similarFont(const FontDescription& description, const AtomicString& family)
661 {
662     // Attempt to find an appropriate font using a match based on the presence of keywords in
663     // the requested names. For example, we'll match any name that contains "Arabic" to Geeza Pro.
664     if (family.isEmpty())
665         return nullptr;
666
667 #if PLATFORM(IOS)
668     // Substitute the default monospace font for well-known monospace fonts.
669     if (equalLettersIgnoringASCIICase(family, "monaco") || equalLettersIgnoringASCIICase(family, "menlo")) {
670         static NeverDestroyed<AtomicString> courier("courier", AtomicString::ConstructFromLiteral);
671         return fontForFamily(description, courier);
672     }
673
674     // Substitute Verdana for Lucida Grande.
675     if (equalLettersIgnoringASCIICase(family, "lucida grande")) {
676         static NeverDestroyed<AtomicString> verdana("verdana", AtomicString::ConstructFromLiteral);
677         return fontForFamily(description, verdana);
678     }
679 #endif
680
681     static NeverDestroyed<String> arabic(MAKE_STATIC_STRING_IMPL("Arabic"));
682     static NeverDestroyed<String> pashto(MAKE_STATIC_STRING_IMPL("Pashto"));
683     static NeverDestroyed<String> urdu(MAKE_STATIC_STRING_IMPL("Urdu"));
684     static String* matchWords[3] = { &arabic.get(), &pashto.get(), &urdu.get() };
685     static NeverDestroyed<AtomicString> geezaPlain("GeezaPro", AtomicString::ConstructFromLiteral);
686     static NeverDestroyed<AtomicString> geezaBold("GeezaPro-Bold", AtomicString::ConstructFromLiteral);
687     for (String* matchWord : matchWords) {
688         if (family.containsIgnoringASCIICase(*matchWord))
689             return fontForFamily(description, isFontWeightBold(description.weight()) ? geezaBold : geezaPlain);
690     }
691     return nullptr;
692 }
693
694 #if !HAS_CORE_TEXT_WIDTH_ATTRIBUTE
695 static float stretchFromCoreTextTraits(CFDictionaryRef traits)
696 {
697     auto widthNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits, kCTFontWidthTrait));
698     if (!widthNumber)
699         return normalStretchValue();
700
701     float ctWidth;
702     auto success = CFNumberGetValue(widthNumber, kCFNumberFloatType, &ctWidth);
703     ASSERT_UNUSED(success, success);
704     return normalizeWidth(ctWidth);
705 }
706 #endif
707
708 static void invalidateFontCache();
709
710 static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef, const void *, CFDictionaryRef)
711 {
712     ASSERT_UNUSED(observer, observer == &FontCache::singleton());
713
714     invalidateFontCache();
715 }
716
717 void FontCache::platformInit()
718 {
719     CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this, &fontCacheRegisteredFontsChangedNotificationCallback, kCTFontManagerRegisteredFontsChangedNotification, nullptr, CFNotificationSuspensionBehaviorDeliverImmediately);
720
721 #if PLATFORM(MAC)
722     CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
723     const CFStringRef notificationName = kCFLocaleCurrentLocaleDidChangeNotification;
724 #else
725     CFNotificationCenterRef center = CFNotificationCenterGetDarwinNotifyCenter();
726     const CFStringRef notificationName = CFSTR("com.apple.language.changed");
727 #endif
728     CFNotificationCenterAddObserver(center, this, &fontCacheRegisteredFontsChangedNotificationCallback, notificationName, nullptr, CFNotificationSuspensionBehaviorDeliverImmediately);
729 }
730
731 Vector<String> FontCache::systemFontFamilies()
732 {
733     // FIXME: <rdar://problem/21890188>
734     auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, nullptr, nullptr, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
735     auto emptyFontDescriptor = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
736     auto matchedDescriptors = adoptCF(CTFontDescriptorCreateMatchingFontDescriptors(emptyFontDescriptor.get(), nullptr));
737     if (!matchedDescriptors)
738         return { };
739
740     CFIndex numMatches = CFArrayGetCount(matchedDescriptors.get());
741     if (!numMatches)
742         return { };
743
744     HashSet<String> visited;
745     for (CFIndex i = 0; i < numMatches; ++i) {
746         auto fontDescriptor = static_cast<CTFontDescriptorRef>(CFArrayGetValueAtIndex(matchedDescriptors.get(), i));
747         if (auto familyName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute))))
748             visited.add(familyName.get());
749     }
750
751     return copyToVector(visited);
752 }
753
754 static CTFontSymbolicTraits computeTraits(const FontDescription& fontDescription)
755 {
756     CTFontSymbolicTraits traits = 0;
757     if (fontDescription.italic())
758         traits |= kCTFontTraitItalic;
759     if (isFontWeightBold(fontDescription.weight()))
760         traits |= kCTFontTraitBold;
761     return traits;
762 }
763
764 SynthesisPair computeNecessarySynthesis(CTFontRef font, const FontDescription& fontDescription, bool isPlatformFont)
765 {
766 #if PLATFORM(IOS)
767     if (CTFontIsAppleColorEmoji(font))
768         return SynthesisPair(false, false);
769 #endif
770
771     if (isPlatformFont)
772         return SynthesisPair(false, false);
773
774     CTFontSymbolicTraits desiredTraits = computeTraits(fontDescription);
775
776     CTFontSymbolicTraits actualTraits = 0;
777     if (isFontWeightBold(fontDescription.weight()) || isItalic(fontDescription.italic()))
778         actualTraits = CTFontGetSymbolicTraits(font);
779
780     bool needsSyntheticBold = (fontDescription.fontSynthesis() & FontSynthesisWeight) && (desiredTraits & kCTFontTraitBold) && !(actualTraits & kCTFontTraitBold);
781     bool needsSyntheticOblique = (fontDescription.fontSynthesis() & FontSynthesisStyle) && (desiredTraits & kCTFontTraitItalic) && !(actualTraits & kCTFontTraitItalic);
782
783     return SynthesisPair(needsSyntheticBold, needsSyntheticOblique);
784 }
785
786 typedef HashSet<String, ASCIICaseInsensitiveHash> Whitelist;
787 static Whitelist& fontWhitelist()
788 {
789     static NeverDestroyed<Whitelist> whitelist;
790     return whitelist;
791 }
792
793 void FontCache::setFontWhitelist(const Vector<String>& inputWhitelist)
794 {
795     Whitelist& whitelist = fontWhitelist();
796     whitelist.clear();
797     for (auto& item : inputWhitelist)
798         whitelist.add(item);
799 }
800
801 static inline bool isSystemFont(const AtomicString& family)
802 {
803     // AtomicString's operator[] handles out-of-bounds by returning 0.
804     return family[0] == '.';
805 }
806
807 #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP
808 static float fontWeightFromCoreText(CGFloat weight)
809 {
810     if (weight < -0.6)
811         return 100;
812     if (weight < -0.365)
813         return 200;
814     if (weight < -0.115)
815         return 300;
816     if (weight <  0.130)
817         return 400;
818     if (weight <  0.235)
819         return 500;
820     if (weight <  0.350)
821         return 600;
822     if (weight <  0.500)
823         return 700;
824     if (weight <  0.700)
825         return 800;
826     return 900;
827 }
828 #endif
829
830 class FontDatabase {
831 public:
832     static FontDatabase& singleton()
833     {
834         static NeverDestroyed<FontDatabase> database;
835         return database;
836     }
837
838     FontDatabase(const FontDatabase&) = delete;
839     FontDatabase& operator=(const FontDatabase&) = delete;
840
841     struct InstalledFont {
842         InstalledFont() = default;
843
844         InstalledFont(CTFontDescriptorRef fontDescriptor)
845             : fontDescriptor(fontDescriptor)
846             , capabilities(capabilitiesForFontDescriptor(fontDescriptor))
847         {
848         }
849
850         RetainPtr<CTFontDescriptorRef> fontDescriptor;
851         FontSelectionCapabilities capabilities;
852     };
853
854     struct InstalledFontFamily {
855         InstalledFontFamily() = default;
856
857         explicit InstalledFontFamily(Vector<InstalledFont>&& installedFonts)
858             : installedFonts(WTFMove(installedFonts))
859         {
860             for (auto& font : this->installedFonts)
861                 expand(font);
862         }
863
864         void expand(const InstalledFont& installedFont)
865         {
866             capabilities.expand(installedFont.capabilities);
867         }
868
869         bool isEmpty() const
870         {
871             return installedFonts.isEmpty();
872         }
873
874         size_t size() const
875         {
876             return installedFonts.size();
877         }
878
879         Vector<InstalledFont> installedFonts;
880         FontSelectionCapabilities capabilities;
881     };
882
883     const InstalledFontFamily& collectionForFamily(const String& familyName)
884     {
885         auto folded = familyName.foldCase();
886         return m_familyNameToFontDescriptors.ensure(folded, [&] {
887             auto familyNameString = folded.createCFString();
888             CFTypeRef keys[] = { kCTFontFamilyNameAttribute };
889             CFTypeRef values[] = { familyNameString.get() };
890             auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
891             auto fontDescriptorToMatch = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
892             if (auto matches = adoptCF(CTFontDescriptorCreateMatchingFontDescriptors(fontDescriptorToMatch.get(), nullptr))) {
893                 auto count = CFArrayGetCount(matches.get());
894                 Vector<InstalledFont> result;
895                 result.reserveInitialCapacity(count);
896                 for (CFIndex i = 0; i < count; ++i) {
897                     InstalledFont installedFont(static_cast<CTFontDescriptorRef>(CFArrayGetValueAtIndex(matches.get(), i)));
898                     result.uncheckedAppend(WTFMove(installedFont));
899                 }
900                 return InstalledFontFamily(WTFMove(result));
901             }
902             return InstalledFontFamily();
903         }).iterator->value;
904     }
905
906     const InstalledFont& fontForPostScriptName(const AtomicString& postScriptName)
907     {
908         const auto& folded = FontCascadeDescription::foldedFamilyName(postScriptName);
909         return m_postScriptNameToFontDescriptors.ensure(folded, [&] {
910             auto postScriptNameString = folded.createCFString();
911 #if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300)
912             CFStringRef nameAttribute = kCTFontPostScriptNameAttribute;
913 #else
914             CFStringRef nameAttribute = kCTFontNameAttribute;
915 #endif
916             CFTypeRef keys[] = { kCTFontEnabledAttribute, nameAttribute };
917             CFTypeRef values[] = { kCFBooleanTrue, postScriptNameString.get() };
918             auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
919             auto fontDescriptorToMatch = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
920             auto match = adoptCF(static_cast<CTFontDescriptorRef>(CTFontDescriptorCreateMatchingFontDescriptor(fontDescriptorToMatch.get(), nullptr)));
921             return InstalledFont(match.get());
922         }).iterator->value;
923     }
924
925     void clear()
926     {
927         m_familyNameToFontDescriptors.clear();
928         m_postScriptNameToFontDescriptors.clear();
929     }
930
931 private:
932     friend class NeverDestroyed<FontDatabase>;
933
934     FontDatabase() = default;
935
936     HashMap<String, InstalledFontFamily> m_familyNameToFontDescriptors;
937     HashMap<String, InstalledFont> m_postScriptNameToFontDescriptors;
938 };
939
940 // 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
941 // quantization of FontSelectionValue. Instead, do this logic with floats.
942 struct MinMax {
943     float minimum;
944     float maximum;
945 };
946
947 struct VariationCapabilities {
948     std::optional<MinMax> weight;
949     std::optional<MinMax> width;
950     std::optional<MinMax> slope;
951 };
952
953 #if ENABLE(VARIATION_FONTS)
954 static std::optional<MinMax> extractVariationBounds(CFDictionaryRef axis)
955 {
956     CFNumberRef minimumValue = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisMinimumValueKey));
957     CFNumberRef maximumValue = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisMaximumValueKey));
958     float rawMinimumValue = 0;
959     float rawMaximumValue = 0;
960     CFNumberGetValue(minimumValue, kCFNumberFloatType, &rawMinimumValue);
961     CFNumberGetValue(maximumValue, kCFNumberFloatType, &rawMaximumValue);
962     if (rawMinimumValue < rawMaximumValue)
963         return {{ rawMinimumValue, rawMaximumValue }};
964     return std::nullopt;
965 }
966 #endif
967
968 static VariationCapabilities variationCapabilitiesForFontDescriptor(CTFontDescriptorRef fontDescriptor)
969 {
970     VariationCapabilities result;
971
972 #if ENABLE(VARIATION_FONTS)
973     if (!adoptCF(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontVariationAttribute)))
974         return result;
975
976     auto font = adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor, 0, nullptr));
977     auto variations = adoptCF(CTFontCopyVariationAxes(font.get()));
978     if (!variations)
979         return result;
980
981     auto axisCount = CFArrayGetCount(variations.get());
982     if (!axisCount)
983         return result;
984
985     for (CFIndex i = 0; i < axisCount; ++i) {
986         CFDictionaryRef axis = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(variations.get(), i));
987         CFNumberRef axisIdentifier = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisIdentifierKey));
988         uint32_t rawAxisIdentifier = 0;
989         Boolean success = CFNumberGetValue(axisIdentifier, kCFNumberSInt32Type, &rawAxisIdentifier);
990         ASSERT_UNUSED(success, success);
991         if (rawAxisIdentifier == 0x77676874) // 'wght'
992             result.weight = extractVariationBounds(axis);
993         else if (rawAxisIdentifier == 0x77647468) // 'wdth'
994             result.width = extractVariationBounds(axis);
995         else if (rawAxisIdentifier == 0x736C6E74) // 'slnt'
996             result.slope = extractVariationBounds(axis);
997     }
998
999     bool optOutFromGXNormalization = false;
1000 #if ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000))
1001     optOutFromGXNormalization = CTFontDescriptorIsSystemUIFont(fontDescriptor);
1002 #endif
1003
1004     if (FontType(font.get()).variationType == FontType::VariationType::TrueTypeGX && !optOutFromGXNormalization) {
1005         if (result.weight)
1006             result.weight = {{ normalizeWeight(result.weight.value().minimum), normalizeWeight(result.weight.value().maximum) }};
1007         if (result.width)
1008             result.width = {{ normalizeVariationWidth(result.width.value().minimum), normalizeVariationWidth(result.width.value().maximum) }};
1009         if (result.slope)
1010             result.slope = {{ normalizeSlope(result.slope.value().minimum), normalizeSlope(result.slope.value().maximum) }};
1011     }
1012
1013     auto minimum = static_cast<float>(FontSelectionValue::minimumValue());
1014     auto maximum = static_cast<float>(FontSelectionValue::maximumValue());
1015     if (result.weight && (result.weight.value().minimum < minimum || result.weight.value().maximum > maximum))
1016         result.weight = { };
1017     if (result.width && (result.width.value().minimum < minimum || result.width.value().maximum > maximum))
1018         result.width = { };
1019     if (result.slope && (result.slope.value().minimum < minimum || result.slope.value().maximum > maximum))
1020         result.slope = { };
1021 #else
1022     UNUSED_PARAM(fontDescriptor);
1023 #endif
1024
1025     return result;
1026 }
1027
1028 #if !SHOULD_USE_CORE_TEXT_FONT_LOOKUP || HAS_CORE_TEXT_WIDTH_ATTRIBUTE
1029 static float getCSSAttribute(CTFontDescriptorRef fontDescriptor, const CFStringRef attribute, float fallback)
1030 {
1031     auto number = adoptCF(static_cast<CFNumberRef>(CTFontDescriptorCopyAttribute(fontDescriptor, attribute)));
1032     if (!number)
1033         return fallback;
1034     float cssValue;
1035     auto success = CFNumberGetValue(number.get(), kCFNumberFloatType, &cssValue);
1036     ASSERT_UNUSED(success, success);
1037     return cssValue;
1038 }
1039 #endif
1040
1041 FontSelectionCapabilities capabilitiesForFontDescriptor(CTFontDescriptorRef fontDescriptor)
1042 {
1043     if (!fontDescriptor)
1044         return { };
1045
1046     VariationCapabilities variationCapabilities = variationCapabilitiesForFontDescriptor(fontDescriptor);
1047
1048 #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP || !HAS_CORE_TEXT_WIDTH_ATTRIBUTE
1049     bool weightOrWidthComeFromTraits = !variationCapabilities.weight || !variationCapabilities.width;
1050 #else
1051     bool weightOrWidthComeFromTraits = false;
1052 #endif
1053
1054     if (!variationCapabilities.slope || weightOrWidthComeFromTraits) {
1055         auto traits = adoptCF(static_cast<CFDictionaryRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontTraitsAttribute)));
1056         if (traits) {
1057 #if !HAS_CORE_TEXT_WIDTH_ATTRIBUTE
1058             if (!variationCapabilities.width) {
1059                 auto widthValue = stretchFromCoreTextTraits(traits.get());
1060                 variationCapabilities.width = {{ widthValue, widthValue }};
1061             }
1062 #endif
1063
1064             if (!variationCapabilities.slope) {
1065                 auto symbolicTraitsNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait));
1066                 if (symbolicTraitsNumber) {
1067                     int32_t symbolicTraits;
1068                     auto success = CFNumberGetValue(symbolicTraitsNumber, kCFNumberSInt32Type, &symbolicTraits);
1069                     ASSERT_UNUSED(success, success);
1070                     auto slopeValue = static_cast<float>(symbolicTraits & kCTFontTraitItalic ? italicValue() : normalItalicValue());
1071                     variationCapabilities.slope = {{ slopeValue, slopeValue }};
1072                 } else
1073                     variationCapabilities.slope = {{ static_cast<float>(normalItalicValue()), static_cast<float>(normalItalicValue()) }};
1074             }
1075
1076 #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP
1077             if (!variationCapabilities.weight) {
1078                 auto weightNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontWeightTrait));
1079                 if (weightNumber) {
1080                     CGFloat ctWeight;
1081                     auto success = CFNumberGetValue(weightNumber, kCFNumberCGFloatType, &ctWeight);
1082                     ASSERT_UNUSED(success, success);
1083                     auto weightValue = fontWeightFromCoreText(ctWeight);
1084                     variationCapabilities.weight = {{ weightValue, weightValue }};
1085                 } else
1086                     variationCapabilities.weight = {{ static_cast<float>(normalWeightValue()), static_cast<float>(normalWeightValue()) }};
1087             }
1088 #endif
1089         }
1090     }
1091
1092 #if !SHOULD_USE_CORE_TEXT_FONT_LOOKUP
1093     if (!variationCapabilities.weight) {
1094         auto value = getCSSAttribute(fontDescriptor, kCTFontCSSWeightAttribute, static_cast<float>(normalWeightValue()));
1095         variationCapabilities.weight = {{ value, value }};
1096     }
1097 #endif
1098
1099 #if HAS_CORE_TEXT_WIDTH_ATTRIBUTE
1100     if (!variationCapabilities.width) {
1101         auto value = getCSSAttribute(fontDescriptor, kCTFontCSSWidthAttribute, static_cast<float>(normalStretchValue()));
1102         variationCapabilities.width = {{ value, value }};
1103     }
1104 #endif
1105
1106     FontSelectionCapabilities result = {{ FontSelectionValue(variationCapabilities.weight.value().minimum), FontSelectionValue(variationCapabilities.weight.value().maximum) },
1107         { FontSelectionValue(variationCapabilities.width.value().minimum), FontSelectionValue(variationCapabilities.width.value().maximum) },
1108         { FontSelectionValue(variationCapabilities.slope.value().minimum), FontSelectionValue(variationCapabilities.slope.value().maximum) }};
1109     ASSERT(result.weight.isValid());
1110     ASSERT(result.width.isValid());
1111     ASSERT(result.slope.isValid());
1112     return result;
1113 }
1114
1115 #if !SHOULD_USE_CORE_TEXT_FONT_LOOKUP
1116 static const FontDatabase::InstalledFont* findClosestFont(const FontDatabase::InstalledFontFamily& familyFonts, FontSelectionRequest fontSelectionRequest)
1117 {
1118     Vector<FontSelectionCapabilities> capabilities;
1119     capabilities.reserveInitialCapacity(familyFonts.size());
1120     for (auto& font : familyFonts.installedFonts)
1121         capabilities.uncheckedAppend(font.capabilities);
1122     FontSelectionAlgorithm fontSelectionAlgorithm(fontSelectionRequest, capabilities, familyFonts.capabilities);
1123     return &familyFonts.installedFonts[fontSelectionAlgorithm.indexOfBestCapabilities()];
1124 }
1125 #endif
1126
1127 Vector<FontSelectionCapabilities> FontCache::getFontSelectionCapabilitiesInFamily(const AtomicString& familyName)
1128 {
1129     const auto& fonts = FontDatabase::singleton().collectionForFamily(familyName.string());
1130     if (fonts.isEmpty())
1131         return { };
1132
1133     Vector<FontSelectionCapabilities> result;
1134     result.reserveInitialCapacity(fonts.size());
1135     for (const auto& font : fonts.installedFonts)
1136         result.uncheckedAppend(font.capabilities);
1137     return result;
1138 }
1139
1140 struct FontLookup {
1141     RetainPtr<CTFontRef> result;
1142     bool createdFromPostScriptName { false };
1143 };
1144
1145 static FontLookup platformFontLookupWithFamily(const AtomicString& family, FontSelectionRequest request, float size)
1146 {
1147     const auto& whitelist = fontWhitelist();
1148     if (!isSystemFont(family) && whitelist.size() && !whitelist.contains(family))
1149         return { nullptr };
1150
1151 #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP
1152     CTFontSymbolicTraits traits = (isFontWeightBold(request.weight) ? kCTFontTraitBold : 0) | (isItalic(request.slope) ? kCTFontTraitItalic : 0);
1153     return { adoptCF(CTFontCreateForCSS(family.string().createCFString().get(), static_cast<float>(request.weight), traits, size)) };
1154 #else
1155     const auto& familyFonts = FontDatabase::singleton().collectionForFamily(family.string());
1156     if (familyFonts.isEmpty()) {
1157         // The CSS spec states that font-family only accepts a name of an actual font family. However, in WebKit, we claim to also
1158         // support supplying a PostScript name instead. However, this creates problems when the other properties (font-weight,
1159         // font-style) disagree with the traits of the PostScript-named font. The solution we have come up with is, when the default
1160         // values for font-weight and font-style are supplied, honor the PostScript name, but if font-weight specifies bold or
1161         // font-style specifies italic, then we run the regular matching algorithm on the family of the PostScript font. This way,
1162         // if content simply states "font-family: PostScriptName;" without specifying the other font properties, it will be honored,
1163         // but if a <b> appears as a descendent element, it will be honored too.
1164         const auto& postScriptFont = FontDatabase::singleton().fontForPostScriptName(family);
1165         if (!postScriptFont.fontDescriptor)
1166             return { nullptr };
1167         if ((isItalic(request.slope) && !isItalic(postScriptFont.capabilities.slope.maximum))
1168             || (isFontWeightBold(request.weight) && !isFontWeightBold(postScriptFont.capabilities.weight.maximum))) {
1169             auto postScriptFamilyName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(postScriptFont.fontDescriptor.get(), kCTFontFamilyNameAttribute)));
1170             if (!postScriptFamilyName)
1171                 return { nullptr };
1172             const auto& familyFonts = FontDatabase::singleton().collectionForFamily(String(postScriptFamilyName.get()));
1173             if (familyFonts.isEmpty())
1174                 return { nullptr };
1175             if (const auto* installedFont = findClosestFont(familyFonts, request)) {
1176                 if (!installedFont->fontDescriptor)
1177                     return { nullptr };
1178                 return { adoptCF(CTFontCreateWithFontDescriptor(installedFont->fontDescriptor.get(), size, nullptr)), true };
1179             }
1180             return { nullptr };
1181         }
1182         return { adoptCF(CTFontCreateWithFontDescriptor(postScriptFont.fontDescriptor.get(), size, nullptr)), true };
1183     }
1184
1185     if (const auto* installedFont = findClosestFont(familyFonts, request))
1186         return { adoptCF(CTFontCreateWithFontDescriptor(installedFont->fontDescriptor.get(), size, nullptr)), false };
1187
1188     return { nullptr };
1189 #endif
1190 }
1191
1192 static void invalidateFontCache()
1193 {
1194     if (!isMainThread()) {
1195         callOnMainThread([] {
1196             invalidateFontCache();
1197         });
1198         return;
1199     }
1200
1201     FontDescription::invalidateCaches();
1202
1203     FontDatabase::singleton().clear();
1204
1205     FontCache::singleton().invalidate();
1206 }
1207
1208 static RetainPtr<CTFontRef> fontWithFamily(const AtomicString& family, const FontDescription& fontDescription, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, FontSelectionSpecifiedCapabilities fontFaceCapabilities, float size)
1209 {
1210     if (family.isEmpty())
1211         return nullptr;
1212
1213     const auto& request = fontDescription.fontSelectionRequest();
1214     FontLookup fontLookup;
1215     fontLookup.result = platformFontWithFamilySpecialCase(family, request, size);
1216     if (!fontLookup.result)
1217         fontLookup = platformFontLookupWithFamily(family, request, size);
1218     return preparePlatformFont(fontLookup.result.get(), fontDescription, fontFaceFeatures, fontFaceVariantSettings, fontFaceCapabilities, size, !fontLookup.createdFromPostScriptName);
1219 }
1220
1221 #if PLATFORM(MAC)
1222 static bool shouldAutoActivateFontIfNeeded(const AtomicString& family)
1223 {
1224 #ifndef NDEBUG
1225     // This cache is not thread safe so the following assertion is there to
1226     // make sure this function is always called from the same thread.
1227     static Thread* initThread = &Thread::current();
1228     ASSERT(initThread == &Thread::current());
1229 #endif
1230
1231     static NeverDestroyed<HashSet<AtomicString>> knownFamilies;
1232     static const unsigned maxCacheSize = 128;
1233     ASSERT(knownFamilies.get().size() <= maxCacheSize);
1234     if (knownFamilies.get().size() == maxCacheSize)
1235         knownFamilies.get().remove(knownFamilies.get().begin());
1236
1237     // Only attempt to auto-activate fonts once for performance reasons.
1238     return knownFamilies.get().add(family).isNewEntry;
1239 }
1240
1241 static void autoActivateFont(const String& name, CGFloat size)
1242 {
1243     auto fontName = name.createCFString();
1244     CFTypeRef keys[] = { kCTFontNameAttribute };
1245     CFTypeRef values[] = { fontName.get() };
1246     auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
1247     auto descriptor = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
1248     if (auto newFont = CTFontCreateWithFontDescriptor(descriptor.get(), size, nullptr))
1249         CFRelease(newFont);
1250 }
1251 #endif
1252
1253 std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, FontSelectionSpecifiedCapabilities fontFaceCapabilities)
1254 {
1255     float size = fontDescription.computedPixelSize();
1256
1257     auto font = fontWithFamily(family, fontDescription, fontFaceFeatures, fontFaceVariantSettings, fontFaceCapabilities, size);
1258
1259 #if PLATFORM(MAC)
1260     if (!font) {
1261         if (!shouldAutoActivateFontIfNeeded(family))
1262             return nullptr;
1263
1264         // Auto activate the font before looking for it a second time.
1265         // Ignore the result because we want to use our own algorithm to actually find the font.
1266         autoActivateFont(family.string(), size);
1267
1268         font = fontWithFamily(family, fontDescription, fontFaceFeatures, fontFaceVariantSettings, fontFaceCapabilities, size);
1269     }
1270 #endif
1271
1272     if (!font)
1273         return nullptr;
1274
1275     bool syntheticBold, syntheticOblique;
1276     std::tie(syntheticBold, syntheticOblique) = computeNecessarySynthesis(font.get(), fontDescription).boldObliquePair();
1277
1278     return std::make_unique<FontPlatformData>(font.get(), size, syntheticBold, syntheticOblique, fontDescription.orientation(), fontDescription.widthVariant(), fontDescription.textRenderingMode());
1279 }
1280
1281 typedef HashSet<RetainPtr<CTFontRef>, WTF::RetainPtrObjectHash<CTFontRef>, WTF::RetainPtrObjectHashTraits<CTFontRef>> FallbackDedupSet;
1282 static FallbackDedupSet& fallbackDedupSet()
1283 {
1284     static NeverDestroyed<FallbackDedupSet> dedupSet;
1285     return dedupSet.get();
1286 }
1287
1288 void FontCache::platformPurgeInactiveFontData()
1289 {
1290     Vector<CTFontRef> toRemove;
1291     for (auto& font : fallbackDedupSet()) {
1292         if (CFGetRetainCount(font.get()) == 1)
1293             toRemove.append(font.get());
1294     }
1295     for (auto& font : toRemove)
1296         fallbackDedupSet().remove(font);
1297 }
1298
1299 #if PLATFORM(IOS)
1300 static inline bool isArabicCharacter(UChar character)
1301 {
1302     return character >= 0x0600 && character <= 0x06FF;
1303 }
1304 #endif
1305
1306 static RetainPtr<CTFontRef> lookupFallbackFont(CTFontRef font, FontSelectionValue fontWeight, const AtomicString& locale, const UChar* characters, unsigned length)
1307 {
1308     ASSERT(length > 0);
1309
1310     RetainPtr<CFStringRef> localeString;
1311 #if (PLATFORM(IOS) && TARGET_OS_IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
1312     if (!locale.isNull())
1313         localeString = locale.string().createCFString();
1314 #else
1315     UNUSED_PARAM(locale);
1316 #endif
1317
1318     CFIndex coveredLength = 0;
1319     RetainPtr<CTFontRef> result;
1320 #if !USE_PLATFORM_SYSTEM_FALLBACK_LIST && ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) || (PLATFORM(IOS) && TARGET_OS_IOS))
1321     result = adoptCF(CTFontCreatePhysicalFontForCharactersWithLanguage(font, characters, length, localeString.get(), &coveredLength));
1322 #else
1323     result = adoptCF(CTFontCreateForCharactersWithLanguage(font, characters, length, localeString.get(), &coveredLength));
1324 #endif
1325
1326 #if PLATFORM(IOS)
1327     // Callers of this function won't include multiple code points. "Length" is to know how many code units
1328     // are in the code point.
1329     UChar firstCharacter = characters[0];
1330     if (isArabicCharacter(firstCharacter)) {
1331         auto familyName = adoptCF(static_cast<CFStringRef>(CTFontCopyAttribute(result.get(), kCTFontFamilyNameAttribute)));
1332         if (fontFamilyShouldNotBeUsedForArabic(familyName.get())) {
1333             CFStringRef newFamilyName = isFontWeightBold(fontWeight) ? CFSTR("GeezaPro-Bold") : CFSTR("GeezaPro");
1334             CFTypeRef keys[] = { kCTFontNameAttribute };
1335             CFTypeRef values[] = { newFamilyName };
1336             auto attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
1337             auto modification = adoptCF(CTFontDescriptorCreateWithAttributes(attributes.get()));
1338             result = adoptCF(CTFontCreateCopyWithAttributes(result.get(), CTFontGetSize(result.get()), nullptr, modification.get()));
1339         }
1340     }
1341 #else
1342     UNUSED_PARAM(fontWeight);
1343 #endif
1344
1345     return result;
1346 }
1347
1348 RefPtr<Font> FontCache::systemFallbackForCharacters(const FontDescription& description, const Font* originalFontData, bool isPlatformFont, const UChar* characters, unsigned length)
1349 {
1350 #if PLATFORM(IOS)
1351     if (length && requiresCustomFallbackFont(*characters)) {
1352         auto* fallback = getCustomFallbackFont(*characters, description);
1353         if (!fallback)
1354             return nullptr;
1355         return fontForPlatformData(*fallback);
1356     }
1357 #endif
1358
1359     const FontPlatformData& platformData = originalFontData->platformData();
1360     auto result = lookupFallbackFont(platformData.font(), description.weight(), description.locale(), characters, length);
1361     result = preparePlatformFont(result.get(), description, nullptr, nullptr, { }, description.computedSize());
1362     if (!result)
1363         return lastResortFallbackFont(description);
1364
1365     // FontCascade::drawGlyphBuffer() requires that there are no duplicate Font objects which refer to the same thing. This is enforced in
1366     // FontCache::fontForPlatformData(), where our equality check is based on hashing the FontPlatformData, whose hash includes the raw CoreText
1367     // font pointer.
1368     CTFontRef substituteFont = fallbackDedupSet().add(result).iterator->get();
1369
1370     bool syntheticBold, syntheticOblique;
1371     std::tie(syntheticBold, syntheticOblique) = computeNecessarySynthesis(substituteFont, description, isPlatformFont).boldObliquePair();
1372
1373     FontPlatformData alternateFont(substituteFont, platformData.size(), syntheticBold, syntheticOblique, platformData.orientation(), platformData.widthVariant(), platformData.textRenderingMode());
1374
1375     return fontForPlatformData(alternateFont);
1376 }
1377
1378 const AtomicString& FontCache::platformAlternateFamilyName(const AtomicString& familyName)
1379 {
1380     static const UChar heitiString[] = { 0x9ed1, 0x4f53 };
1381     static const UChar songtiString[] = { 0x5b8b, 0x4f53 };
1382     static const UChar weiruanXinXiMingTi[] = { 0x5fae, 0x8edf, 0x65b0, 0x7d30, 0x660e, 0x9ad4 };
1383     static const UChar weiruanYaHeiString[] = { 0x5fae, 0x8f6f, 0x96c5, 0x9ed1 };
1384     static const UChar weiruanZhengHeitiString[] = { 0x5fae, 0x8edf, 0x6b63, 0x9ed1, 0x9ad4 };
1385
1386     static NeverDestroyed<AtomicString> songtiSC("Songti SC", AtomicString::ConstructFromLiteral);
1387     static NeverDestroyed<AtomicString> songtiTC("Songti TC", AtomicString::ConstructFromLiteral);
1388     static NeverDestroyed<AtomicString> heitiSCReplacement("PingFang SC", AtomicString::ConstructFromLiteral);
1389     static NeverDestroyed<AtomicString> heitiTCReplacement("PingFang TC", AtomicString::ConstructFromLiteral);
1390
1391     switch (familyName.length()) {
1392     case 2:
1393         if (equal(familyName, songtiString))
1394             return songtiSC;
1395         if (equal(familyName, heitiString))
1396             return heitiSCReplacement;
1397         break;
1398     case 4:
1399         if (equal(familyName, weiruanYaHeiString))
1400             return heitiSCReplacement;
1401         break;
1402     case 5:
1403         if (equal(familyName, weiruanZhengHeitiString))
1404             return heitiTCReplacement;
1405         break;
1406     case 6:
1407         if (equalLettersIgnoringASCIICase(familyName, "simsun"))
1408             return songtiSC;
1409         if (equal(familyName, weiruanXinXiMingTi))
1410             return songtiTC;
1411         break;
1412     case 10:
1413         if (equalLettersIgnoringASCIICase(familyName, "ms mingliu"))
1414             return songtiTC;
1415         if (equalIgnoringASCIICase(familyName, "\\5b8b\\4f53"))
1416             return songtiSC;
1417         break;
1418     case 18:
1419         if (equalLettersIgnoringASCIICase(familyName, "microsoft jhenghei"))
1420             return heitiTCReplacement;
1421         break;
1422     }
1423
1424     return nullAtom();
1425 }
1426
1427 }