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