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