• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "include/core/SkTypes.h"
9 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
10 
11 #ifdef SK_BUILD_FOR_MAC
12 #import <ApplicationServices/ApplicationServices.h>
13 #endif
14 
15 #ifdef SK_BUILD_FOR_IOS
16 #include <CoreText/CoreText.h>
17 #include <CoreText/CTFontManager.h>
18 #include <CoreGraphics/CoreGraphics.h>
19 #include <CoreFoundation/CoreFoundation.h>
20 #include <dlfcn.h>
21 #endif
22 
23 #include "include/core/SkData.h"
24 #include "include/core/SkFontArguments.h"
25 #include "include/core/SkFontMgr.h"
26 #include "include/core/SkFontStyle.h"
27 #include "include/core/SkStream.h"
28 #include "include/core/SkString.h"
29 #include "include/core/SkTypeface.h"
30 #include "include/ports/SkFontMgr_mac_ct.h"
31 #include "include/private/SkFixed.h"
32 #include "include/private/SkOnce.h"
33 #include "include/private/SkTPin.h"
34 #include "include/private/SkTemplates.h"
35 #include "include/private/SkTo.h"
36 #include "src/core/SkFontDescriptor.h"
37 #include "src/ports/SkTypeface_mac_ct.h"
38 #include "src/utils/SkUTF.h"
39 
40 #include <string.h>
41 #include <memory>
42 
43 #if (defined(SK_BUILD_FOR_IOS) && defined(__IPHONE_14_0) &&  \
44       __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_14_0) ||  \
45     (defined(SK_BUILD_FOR_MAC) && defined(__MAC_11_0) &&     \
46       __MAC_OS_VERSION_MIN_REQUIRED >= __MAC_11_0)
47 
SkGetCoreTextVersion()48 static uint32_t SkGetCoreTextVersion() {
49     // If compiling for iOS 14.0+ or macOS 11.0+, the CoreText version number
50     // must be derived from the OS version number.
51     static const uint32_t kCoreTextVersionNEWER = 0x000D0000;
52     return kCoreTextVersionNEWER;
53 }
54 
55 #else
56 
SkGetCoreTextVersion()57 static uint32_t SkGetCoreTextVersion() {
58     // Check for CoreText availability before calling CTGetCoreTextVersion().
59     if (&CTGetCoreTextVersion) {
60         return CTGetCoreTextVersion();
61     }
62 
63     // Default to a value that's smaller than any known CoreText version.
64     static const uint32_t kCoreTextVersionUNKNOWN = 0;
65     return kCoreTextVersionUNKNOWN;
66 }
67 
68 #endif
69 
make_CFString(const char s[])70 static SkUniqueCFRef<CFStringRef> make_CFString(const char s[]) {
71     return SkUniqueCFRef<CFStringRef>(CFStringCreateWithCString(nullptr, s, kCFStringEncodingUTF8));
72 }
73 
74 /** Creates a typeface from a descriptor, searching the cache. */
create_from_desc(CTFontDescriptorRef desc)75 static sk_sp<SkTypeface> create_from_desc(CTFontDescriptorRef desc) {
76     SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr));
77     if (!ctFont) {
78         return nullptr;
79     }
80 
81     return SkTypeface_Mac::Make(std::move(ctFont), OpszVariation(), nullptr);
82 }
83 
create_descriptor(const char familyName[],const SkFontStyle & style)84 static SkUniqueCFRef<CTFontDescriptorRef> create_descriptor(const char familyName[],
85                                                             const SkFontStyle& style) {
86     SkUniqueCFRef<CFMutableDictionaryRef> cfAttributes(
87             CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
88                                       &kCFTypeDictionaryKeyCallBacks,
89                                       &kCFTypeDictionaryValueCallBacks));
90 
91     SkUniqueCFRef<CFMutableDictionaryRef> cfTraits(
92             CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
93                                       &kCFTypeDictionaryKeyCallBacks,
94                                       &kCFTypeDictionaryValueCallBacks));
95 
96     if (!cfAttributes || !cfTraits) {
97         return nullptr;
98     }
99 
100     // TODO(crbug.com/1018581) Some CoreText versions have errant behavior when
101     // certain traits set.  Temporary workaround to omit specifying trait for those
102     // versions.
103     // Long term solution will involve serializing typefaces instead of relying upon
104     // this to match between processes.
105     //
106     // Compare CoreText.h in an up to date SDK for where these values come from.
107     static const uint32_t kSkiaLocalCTVersionNumber10_14 = 0x000B0000;
108     static const uint32_t kSkiaLocalCTVersionNumber10_15 = 0x000C0000;
109 
110     // CTFontTraits (symbolic)
111     // macOS 14 and iOS 12 seem to behave badly when kCTFontSymbolicTrait is set.
112     // macOS 15 yields LastResort font instead of a good default font when
113     // kCTFontSymbolicTrait is set.
114     if (SkGetCoreTextVersion() < kSkiaLocalCTVersionNumber10_14) {
115         CTFontSymbolicTraits ctFontTraits = 0;
116         if (style.weight() >= SkFontStyle::kBold_Weight) {
117             ctFontTraits |= kCTFontBoldTrait;
118         }
119         if (style.slant() != SkFontStyle::kUpright_Slant) {
120             ctFontTraits |= kCTFontItalicTrait;
121         }
122         SkUniqueCFRef<CFNumberRef> cfFontTraits(
123                 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits));
124         if (cfFontTraits) {
125             CFDictionaryAddValue(cfTraits.get(), kCTFontSymbolicTrait, cfFontTraits.get());
126         }
127     }
128 
129     // CTFontTraits (weight)
130     CGFloat ctWeight = SkCTFontCTWeightForCSSWeight(style.weight());
131     SkUniqueCFRef<CFNumberRef> cfFontWeight(
132             CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWeight));
133     if (cfFontWeight) {
134         CFDictionaryAddValue(cfTraits.get(), kCTFontWeightTrait, cfFontWeight.get());
135     }
136     // CTFontTraits (width)
137     CGFloat ctWidth = SkCTFontCTWidthForCSSWidth(style.width());
138     SkUniqueCFRef<CFNumberRef> cfFontWidth(
139             CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWidth));
140     if (cfFontWidth) {
141         CFDictionaryAddValue(cfTraits.get(), kCTFontWidthTrait, cfFontWidth.get());
142     }
143     // CTFontTraits (slant)
144     // macOS 15 behaves badly when kCTFontSlantTrait is set.
145     if (SkGetCoreTextVersion() != kSkiaLocalCTVersionNumber10_15) {
146         CGFloat ctSlant = style.slant() == SkFontStyle::kUpright_Slant ? 0 : 1;
147         SkUniqueCFRef<CFNumberRef> cfFontSlant(
148                 CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctSlant));
149         if (cfFontSlant) {
150             CFDictionaryAddValue(cfTraits.get(), kCTFontSlantTrait, cfFontSlant.get());
151         }
152     }
153     // CTFontTraits
154     CFDictionaryAddValue(cfAttributes.get(), kCTFontTraitsAttribute, cfTraits.get());
155 
156     // CTFontFamilyName
157     if (familyName) {
158         SkUniqueCFRef<CFStringRef> cfFontName = make_CFString(familyName);
159         if (cfFontName) {
160             CFDictionaryAddValue(cfAttributes.get(), kCTFontFamilyNameAttribute, cfFontName.get());
161         }
162     }
163 
164     return SkUniqueCFRef<CTFontDescriptorRef>(
165             CTFontDescriptorCreateWithAttributes(cfAttributes.get()));
166 }
167 
168 // Same as the above function except style is included so we can
169 // compare whether the created font conforms to the style. If not, we need
170 // to recreate the font with symbolic traits. This is needed due to MacOS 10.11
171 // font creation problem https://bugs.chromium.org/p/skia/issues/detail?id=8447.
create_from_desc_and_style(CTFontDescriptorRef desc,const SkFontStyle & style)172 static sk_sp<SkTypeface> create_from_desc_and_style(CTFontDescriptorRef desc,
173                                                     const SkFontStyle& style) {
174     SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr));
175     if (!ctFont) {
176         return nullptr;
177     }
178 
179     const CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctFont.get());
180     CTFontSymbolicTraits expected_traits = traits;
181     if (style.slant() != SkFontStyle::kUpright_Slant) {
182         expected_traits |= kCTFontItalicTrait;
183     }
184     if (style.weight() >= SkFontStyle::kBold_Weight) {
185         expected_traits |= kCTFontBoldTrait;
186     }
187 
188     if (expected_traits != traits) {
189         SkUniqueCFRef<CTFontRef> ctNewFont(CTFontCreateCopyWithSymbolicTraits(
190                     ctFont.get(), 0, nullptr, expected_traits, expected_traits));
191         if (ctNewFont) {
192             ctFont = std::move(ctNewFont);
193         }
194     }
195 
196     return SkTypeface_Mac::Make(std::move(ctFont), OpszVariation(), nullptr);
197 }
198 
199 /** Creates a typeface from a name, searching the cache. */
create_from_name(const char familyName[],const SkFontStyle & style)200 static sk_sp<SkTypeface> create_from_name(const char familyName[], const SkFontStyle& style) {
201     SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
202     if (!desc) {
203         return nullptr;
204     }
205     return create_from_desc_and_style(desc.get(), style);
206 }
207 
map_css_names(const char * name)208 static const char* map_css_names(const char* name) {
209     static const struct {
210         const char* fFrom;  // name the caller specified
211         const char* fTo;    // "canonical" name we map to
212     } gPairs[] = {
213         { "sans-serif", "Helvetica" },
214         { "serif",      "Times"     },
215         { "monospace",  "Courier"   }
216     };
217 
218     for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
219         if (strcmp(name, gPairs[i].fFrom) == 0) {
220             return gPairs[i].fTo;
221         }
222     }
223     return name;    // no change
224 }
225 
226 namespace {
227 
skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream)228 static sk_sp<SkData> skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream) {
229     size_t size = stream->getLength();
230     if (const void* base = stream->getMemoryBase()) {
231         return SkData::MakeWithProc(base, size,
232                                     [](const void*, void* ctx) -> void {
233                                         delete (SkStreamAsset*)ctx;
234                                     }, stream.release());
235     }
236     return SkData::MakeFromStream(stream.get(), size);
237 }
238 
cfdata_from_skdata(sk_sp<SkData> data)239 static SkUniqueCFRef<CFDataRef> cfdata_from_skdata(sk_sp<SkData> data) {
240     void const * const addr = data->data();
241     size_t const size = data->size();
242 
243     CFAllocatorContext ctx = {
244         0, // CFIndex version
245         data.release(), // void* info
246         nullptr, // const void *(*retain)(const void *info);
247         nullptr, // void (*release)(const void *info);
248         nullptr, // CFStringRef (*copyDescription)(const void *info);
249         nullptr, // void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info);
250         nullptr, // void*(*reallocate)(void* ptr,CFIndex newsize,CFOptionFlags hint,void* info);
251         [](void*,void* info) -> void { // void (*deallocate)(void *ptr, void *info);
252             SkASSERT(info);
253             ((SkData*)info)->unref();
254         },
255         nullptr, // CFIndex (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info);
256     };
257     SkUniqueCFRef<CFAllocatorRef> alloc(CFAllocatorCreate(kCFAllocatorDefault, &ctx));
258     return SkUniqueCFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(
259             kCFAllocatorDefault, (const UInt8 *)addr, size, alloc.get()));
260 }
261 
ctfont_from_skdata(sk_sp<SkData> data,int ttcIndex)262 static SkUniqueCFRef<CTFontRef> ctfont_from_skdata(sk_sp<SkData> data, int ttcIndex) {
263     // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available.
264     if (ttcIndex != 0) {
265         return nullptr;
266     }
267 
268     SkUniqueCFRef<CFDataRef> cfData(cfdata_from_skdata(std::move(data)));
269 
270     SkUniqueCFRef<CTFontDescriptorRef> desc(
271             CTFontManagerCreateFontDescriptorFromData(cfData.get()));
272     if (!desc) {
273         return nullptr;
274     }
275     return SkUniqueCFRef<CTFontRef>(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
276 }
277 
find_desc_str(CTFontDescriptorRef desc,CFStringRef name,SkString * value)278 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
279     SkUniqueCFRef<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
280     if (!ref) {
281         return false;
282     }
283     SkStringFromCFString(ref.get(), value);
284     return true;
285 }
286 
sqr(int value)287 static inline int sqr(int value) {
288     SkASSERT(SkAbs32(value) < 0x7FFF);  // check for overflow
289     return value * value;
290 }
291 
292 // We normalize each axis (weight, width, italic) to be base-900
compute_metric(const SkFontStyle & a,const SkFontStyle & b)293 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
294     return sqr(a.weight() - b.weight()) +
295            sqr((a.width() - b.width()) * 100) +
296            sqr((a.slant() != b.slant()) * 900);
297 }
298 
299 class SkFontStyleSet_Mac : public SkFontStyleSet {
300 public:
SkFontStyleSet_Mac(CTFontDescriptorRef desc)301     SkFontStyleSet_Mac(CTFontDescriptorRef desc)
302         : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, nullptr))
303         , fCount(0)
304     {
305         if (!fArray) {
306             fArray.reset(CFArrayCreate(nullptr, nullptr, 0, nullptr));
307         }
308         fCount = SkToInt(CFArrayGetCount(fArray.get()));
309     }
310 
count()311     int count() override {
312         return fCount;
313     }
314 
getStyle(int index,SkFontStyle * style,SkString * name)315     void getStyle(int index, SkFontStyle* style, SkString* name) override {
316         SkASSERT((unsigned)index < (unsigned)fCount);
317         CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
318         if (style) {
319             *style = SkCTFontDescriptorGetSkFontStyle(desc, false);
320         }
321         if (name) {
322             if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
323                 name->reset();
324             }
325         }
326     }
327 
createTypeface(int index)328     SkTypeface* createTypeface(int index) override {
329         SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray.get()));
330         CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
331 
332         return create_from_desc(desc).release();
333     }
334 
matchStyle(const SkFontStyle & pattern)335     SkTypeface* matchStyle(const SkFontStyle& pattern) override {
336         if (0 == fCount) {
337             return nullptr;
338         }
339         return create_from_desc(findMatchingDesc(pattern)).release();
340     }
341 
342 private:
343     SkUniqueCFRef<CFArrayRef> fArray;
344     int fCount;
345 
findMatchingDesc(const SkFontStyle & pattern) const346     CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
347         int bestMetric = SK_MaxS32;
348         CTFontDescriptorRef bestDesc = nullptr;
349 
350         for (int i = 0; i < fCount; ++i) {
351             CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), i);
352             int metric = compute_metric(pattern, SkCTFontDescriptorGetSkFontStyle(desc, false));
353             if (0 == metric) {
354                 return desc;
355             }
356             if (metric < bestMetric) {
357                 bestMetric = metric;
358                 bestDesc = desc;
359             }
360         }
361         SkASSERT(bestDesc);
362         return bestDesc;
363     }
364 };
365 
SkCopyAvailableFontFamilyNames(CTFontCollectionRef collection)366 SkUniqueCFRef<CFArrayRef> SkCopyAvailableFontFamilyNames(CTFontCollectionRef collection) {
367     // Create a CFArray of all available font descriptors.
368     SkUniqueCFRef<CFArrayRef> descriptors(
369         CTFontCollectionCreateMatchingFontDescriptors(collection));
370 
371     // Copy the font family names of the font descriptors into a CFSet.
372     auto addDescriptorFamilyNameToSet = [](const void* value, void* context) -> void {
373         CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(value);
374         CFMutableSetRef familyNameSet = static_cast<CFMutableSetRef>(context);
375         SkUniqueCFRef<CFTypeRef> familyName(
376             CTFontDescriptorCopyAttribute(descriptor, kCTFontFamilyNameAttribute));
377         if (familyName) {
378             CFSetAddValue(familyNameSet, familyName.get());
379         }
380     };
381     SkUniqueCFRef<CFMutableSetRef> familyNameSet(
382         CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks));
383     CFArrayApplyFunction(descriptors.get(), CFRangeMake(0, CFArrayGetCount(descriptors.get())),
384                          addDescriptorFamilyNameToSet, familyNameSet.get());
385 
386     // Get the set of family names into an array; this does not retain.
387     CFIndex count = CFSetGetCount(familyNameSet.get());
388     std::unique_ptr<const void*[]> familyNames(new const void*[count]);
389     CFSetGetValues(familyNameSet.get(), familyNames.get());
390 
391     // Sort the array of family names (to match CTFontManagerCopyAvailableFontFamilyNames).
392     std::sort(familyNames.get(), familyNames.get() + count, [](const void* a, const void* b){
393         return CFStringCompare((CFStringRef)a, (CFStringRef)b, 0) == kCFCompareLessThan;
394     });
395 
396     // Copy family names into a CFArray; this does retain.
397     return SkUniqueCFRef<CFArrayRef>(
398         CFArrayCreate(kCFAllocatorDefault, familyNames.get(), count, &kCFTypeArrayCallBacks));
399 }
400 
401 /** Use CTFontManagerCopyAvailableFontFamilyNames if available, simulate if not. */
SkCTFontManagerCopyAvailableFontFamilyNames()402 SkUniqueCFRef<CFArrayRef> SkCTFontManagerCopyAvailableFontFamilyNames() {
403 #ifdef SK_BUILD_FOR_IOS
404     using CTFontManagerCopyAvailableFontFamilyNamesProc = CFArrayRef (*)(void);
405     CTFontManagerCopyAvailableFontFamilyNamesProc ctFontManagerCopyAvailableFontFamilyNames;
406     *(void**)(&ctFontManagerCopyAvailableFontFamilyNames) =
407         dlsym(RTLD_DEFAULT, "CTFontManagerCopyAvailableFontFamilyNames");
408     if (ctFontManagerCopyAvailableFontFamilyNames) {
409         return SkUniqueCFRef<CFArrayRef>(ctFontManagerCopyAvailableFontFamilyNames());
410     }
411     SkUniqueCFRef<CTFontCollectionRef> collection(
412         CTFontCollectionCreateFromAvailableFonts(nullptr));
413     return SkUniqueCFRef<CFArrayRef>(SkCopyAvailableFontFamilyNames(collection.get()));
414 #else
415     return SkUniqueCFRef<CFArrayRef>(CTFontManagerCopyAvailableFontFamilyNames());
416 #endif
417 }
418 
419 } // namespace
420 
421 class SkFontMgr_Mac : public SkFontMgr {
422     SkUniqueCFRef<CFArrayRef> fNames;
423     int fCount;
424 
getFamilyNameAt(int index) const425     CFStringRef getFamilyNameAt(int index) const {
426         SkASSERT((unsigned)index < (unsigned)fCount);
427         return (CFStringRef)CFArrayGetValueAtIndex(fNames.get(), index);
428     }
429 
CreateSet(CFStringRef cfFamilyName)430     static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) {
431         SkUniqueCFRef<CFMutableDictionaryRef> cfAttr(
432                  CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
433                                            &kCFTypeDictionaryKeyCallBacks,
434                                            &kCFTypeDictionaryValueCallBacks));
435 
436         CFDictionaryAddValue(cfAttr.get(), kCTFontFamilyNameAttribute, cfFamilyName);
437 
438         SkUniqueCFRef<CTFontDescriptorRef> desc(
439                 CTFontDescriptorCreateWithAttributes(cfAttr.get()));
440         return new SkFontStyleSet_Mac(desc.get());
441     }
442 
443 public:
444     SkUniqueCFRef<CTFontCollectionRef> fFontCollection;
SkFontMgr_Mac(CTFontCollectionRef fontCollection)445     SkFontMgr_Mac(CTFontCollectionRef fontCollection)
446         : fNames(fontCollection ? SkCopyAvailableFontFamilyNames(fontCollection)
447                                 : SkCTFontManagerCopyAvailableFontFamilyNames())
448         , fCount(fNames ? SkToInt(CFArrayGetCount(fNames.get())) : 0)
449         , fFontCollection(fontCollection ? (CTFontCollectionRef)CFRetain(fontCollection)
450                                          : CTFontCollectionCreateFromAvailableFonts(nullptr))
451     {}
452 
453 protected:
onCountFamilies() const454     int onCountFamilies() const override {
455         return fCount;
456     }
457 
onGetFamilyName(int index,SkString * familyName) const458     void onGetFamilyName(int index, SkString* familyName) const override {
459         if ((unsigned)index < (unsigned)fCount) {
460             SkStringFromCFString(this->getFamilyNameAt(index), familyName);
461         } else {
462             familyName->reset();
463         }
464     }
465 
onCreateStyleSet(int index) const466     SkFontStyleSet* onCreateStyleSet(int index) const override {
467         if ((unsigned)index >= (unsigned)fCount) {
468             return nullptr;
469         }
470         return CreateSet(this->getFamilyNameAt(index));
471     }
472 
onMatchFamily(const char familyName[]) const473     SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
474         if (!familyName) {
475             return nullptr;
476         }
477         SkUniqueCFRef<CFStringRef> cfName = make_CFString(familyName);
478         return CreateSet(cfName.get());
479     }
480 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const481     SkTypeface* onMatchFamilyStyle(const char familyName[],
482                                    const SkFontStyle& style) const override {
483         SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
484         return create_from_desc(desc.get()).release();
485     }
486 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const487     SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
488                                             const SkFontStyle& style,
489                                             const char* bcp47[], int bcp47Count,
490                                             SkUnichar character) const override {
491         SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
492         SkUniqueCFRef<CTFontRef> familyFont(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
493 
494         // kCFStringEncodingUTF32 is BE unless there is a BOM.
495         // Since there is no machine endian option, explicitly state machine endian.
496 #ifdef SK_CPU_LENDIAN
497         constexpr CFStringEncoding encoding = kCFStringEncodingUTF32LE;
498 #else
499         constexpr CFStringEncoding encoding = kCFStringEncodingUTF32BE;
500 #endif
501         SkUniqueCFRef<CFStringRef> string(CFStringCreateWithBytes(
502                 kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(&character), sizeof(character),
503                 encoding, false));
504         // If 0xD800 <= codepoint <= 0xDFFF || 0x10FFFF < codepoint 'string' may be nullptr.
505         // No font should be covering such codepoints (even the magic fallback font).
506         if (!string) {
507             return nullptr;
508         }
509         CFRange range = CFRangeMake(0, CFStringGetLength(string.get()));  // in UniChar units.
510         SkUniqueCFRef<CTFontRef> fallbackFont(
511                 CTFontCreateForString(familyFont.get(), string.get(), range));
512         return SkTypeface_Mac::Make(std::move(fallbackFont), OpszVariation(), nullptr).release();
513     }
514 
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const515     sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
516         if (ttcIndex != 0) {
517             return nullptr;
518         }
519 
520         SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(data, ttcIndex);
521         if (!ct) {
522             return nullptr;
523         }
524 
525         return SkTypeface_Mac::Make(std::move(ct), OpszVariation(),
526                                     SkMemoryStream::Make(std::move(data)));
527     }
528 
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const529     sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
530                                             int ttcIndex) const override {
531         if (ttcIndex != 0) {
532             return nullptr;
533         }
534 
535         sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate());
536         if (!data) {
537             return nullptr;
538         }
539         SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex);
540         if (!ct) {
541             return nullptr;
542         }
543 
544         return SkTypeface_Mac::Make(std::move(ct), OpszVariation(), std::move(stream));
545     }
546 
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const547     sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
548                                            const SkFontArguments& args) const override
549     {
550         // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available.
551         int ttcIndex = args.getCollectionIndex();
552         if (ttcIndex != 0) {
553             return nullptr;
554         }
555 
556         sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate());
557         if (!data) {
558             return nullptr;
559         }
560         SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex);
561         if (!ct) {
562             return nullptr;
563         }
564 
565         CTFontVariation ctVariation = SkCTVariationFromSkFontArguments(ct.get(), args);
566 
567         SkUniqueCFRef<CTFontRef> ctVariant;
568         if (ctVariation.variation) {
569             SkUniqueCFRef<CFMutableDictionaryRef> attributes(
570                     CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
571                                               &kCFTypeDictionaryKeyCallBacks,
572                                               &kCFTypeDictionaryValueCallBacks));
573             CFDictionaryAddValue(attributes.get(),
574                                  kCTFontVariationAttribute, ctVariation.variation.get());
575             SkUniqueCFRef<CTFontDescriptorRef> varDesc(
576                     CTFontDescriptorCreateWithAttributes(attributes.get()));
577             ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get()));
578         } else {
579             ctVariant.reset(ct.release());
580         }
581         if (!ctVariant) {
582             return nullptr;
583         }
584 
585         return SkTypeface_Mac::Make(std::move(ctVariant), ctVariation.opsz, std::move(stream));
586     }
587 
onMakeFromFile(const char path[],int ttcIndex) const588     sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
589         if (ttcIndex != 0) {
590             return nullptr;
591         }
592 
593         sk_sp<SkData> data = SkData::MakeFromFileName(path);
594         if (!data) {
595             return nullptr;
596         }
597 
598         return this->onMakeFromData(std::move(data), ttcIndex);
599     }
600 
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const601     sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
602         if (familyName) {
603             familyName = map_css_names(familyName);
604         }
605 
606         sk_sp<SkTypeface> face = create_from_name(familyName, style);
607         if (face) {
608             return face;
609         }
610 
611         static SkTypeface* gDefaultFace;
612         static SkOnce lookupDefault;
613         static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
614         lookupDefault([]{
615             gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle()).release();
616         });
617         return sk_ref_sp(gDefaultFace);
618     }
619 };
620 
SkFontMgr_New_CoreText(CTFontCollectionRef fontCollection)621 sk_sp<SkFontMgr> SkFontMgr_New_CoreText(CTFontCollectionRef fontCollection) {
622     return sk_make_sp<SkFontMgr_Mac>(fontCollection);
623 }
624 
625 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
626