Flutter Engine
The Flutter Engine
SkCTFontCreateExactCopy.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
10
12
15
16// In macOS 10.12 and later any variation on the CGFont which has default axis value will be
17// dropped when creating the CTFont. Unfortunately, in macOS 10.15 the priority of setting
18// the optical size (and opsz variation) is
19// 1. the value of kCTFontOpticalSizeAttribute in the CTFontDescriptor (undocumented)
20// 2. the opsz axis default value if kCTFontOpticalSizeAttribute is 'none' (undocumented)
21// 3. the opsz variation on the nascent CTFont from the CGFont (was dropped if default)
22// 4. the opsz variation in kCTFontVariationAttribute in CTFontDescriptor (crashes 10.10)
23// 5. the size requested (can fudge in SkTypeface but not SkScalerContext)
24// The first one which is found will be used to set the opsz variation (after clamping).
25static void add_opsz_attr(CFMutableDictionaryRef attr, double opsz) {
26 SkUniqueCFRef<CFNumberRef> opszValueNumber(
27 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &opsz));
28 // Avoid using kCTFontOpticalSizeAttribute directly
29 CFStringRef SkCTFontOpticalSizeAttribute = CFSTR("NSCTFontOpticalSizeAttribute");
30 CFDictionarySetValue(attr, SkCTFontOpticalSizeAttribute, opszValueNumber.get());
31}
32
33// This turns off application of the 'trak' table to advances, but also all other tracking.
34static void add_notrak_attr(CFMutableDictionaryRef attr) {
35 int zero = 0;
36 SkUniqueCFRef<CFNumberRef> unscaledTrackingNumber(
37 CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &zero));
38 CFStringRef SkCTFontUnscaledTrackingAttribute = CFSTR("NSCTFontUnscaledTrackingAttribute");
39 CFDictionarySetValue(attr, SkCTFontUnscaledTrackingAttribute, unscaledTrackingNumber.get());
40}
41
42SkUniqueCFRef<CTFontRef> SkCTFontCreateExactCopy(CTFontRef baseFont, CGFloat textSize,
43 OpszVariation opszVariation)
44{
45 SkUniqueCFRef<CFMutableDictionaryRef> attr(
46 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
47 &kCFTypeDictionaryKeyCallBacks,
48 &kCFTypeDictionaryValueCallBacks));
49
50 if (opszVariation.isSet) {
51 add_opsz_attr(attr.get(), opszVariation.value);
52 } else {
53 // On (at least) 10.10 though 10.14 the default system font was SFNSText/SFNSDisplay.
54 // The CTFont is backed by both; optical size < 20 means SFNSText else SFNSDisplay.
55 // On at least 10.11 the glyph ids in these fonts became non-interchangable.
56 // To keep glyph ids stable over size changes, preserve the optical size.
57 // In 10.15 this was replaced with use of variable fonts with an opsz axis.
58 // A CTFont backed by multiple fonts picked by opsz where the multiple backing fonts are
59 // variable fonts with opsz axis and non-interchangeable glyph ids would break the
60 // opsz.isSet branch above, but hopefully that never happens.
61 // See https://crbug.com/524646 .
62 CFStringRef SkCTFontOpticalSizeAttribute = CFSTR("NSCTFontOpticalSizeAttribute");
63 SkUniqueCFRef<CFTypeRef> opsz(CTFontCopyAttribute(baseFont, SkCTFontOpticalSizeAttribute));
64 double opsz_val;
65 if (!opsz ||
66 CFGetTypeID(opsz.get()) != CFNumberGetTypeID() ||
67 !CFNumberGetValue(static_cast<CFNumberRef>(opsz.get()),kCFNumberDoubleType,&opsz_val) ||
68 opsz_val <= 0)
69 {
70 opsz_val = CTFontGetSize(baseFont);
71 }
72 add_opsz_attr(attr.get(), opsz_val);
73 }
74 add_notrak_attr(attr.get());
75
76 SkUniqueCFRef<CTFontDescriptorRef> desc(CTFontDescriptorCreateWithAttributes(attr.get()));
77
78 return SkUniqueCFRef<CTFontRef>(
79 CTFontCreateCopyWithAttributes(baseFont, textSize, nullptr, desc.get()));
80}
81
82#endif
83