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