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