• 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/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 #if defined(CROSS_PLATFORM)
39 #include "src/ports/skia_ohos/HmSymbolConfig_ohos.h"
40 #endif
41 #include "src/ports/SkTypeface_mac_ct.h"
42 
43 #include <string.h>
44 #include <memory>
45 
46 using namespace skia_private;
47 
make_CFString(const char s[])48 static SkUniqueCFRef<CFStringRef> make_CFString(const char s[]) {
49     return SkUniqueCFRef<CFStringRef>(CFStringCreateWithCString(nullptr, s, kCFStringEncodingUTF8));
50 }
51 
52 /** Creates a typeface from a descriptor, searching the cache. */
create_from_desc(CTFontDescriptorRef desc)53 static sk_sp<SkTypeface> create_from_desc(CTFontDescriptorRef desc) {
54     SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr));
55     if (!ctFont) {
56         return nullptr;
57     }
58 
59     return SkTypeface_Mac::Make(std::move(ctFont), OpszVariation(), nullptr);
60 }
61 
create_descriptor(const char familyName[],const SkFontStyle & style)62 static SkUniqueCFRef<CTFontDescriptorRef> create_descriptor(const char familyName[],
63                                                             const SkFontStyle& style) {
64     SkUniqueCFRef<CFMutableDictionaryRef> cfAttributes(
65             CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
66                                       &kCFTypeDictionaryKeyCallBacks,
67                                       &kCFTypeDictionaryValueCallBacks));
68 
69     SkUniqueCFRef<CFMutableDictionaryRef> cfTraits(
70             CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
71                                       &kCFTypeDictionaryKeyCallBacks,
72                                       &kCFTypeDictionaryValueCallBacks));
73 
74     if (!cfAttributes || !cfTraits) {
75         return nullptr;
76     }
77 
78     // Setting both kCTFontSymbolicTrait and the specific WWS traits may lead to strange outcomes.
79 
80     // CTFontTraits (weight)
81     CGFloat ctWeight = SkCTFontCTWeightForCSSWeight(style.weight());
82     SkUniqueCFRef<CFNumberRef> cfFontWeight(
83             CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWeight));
84     if (cfFontWeight) {
85         CFDictionaryAddValue(cfTraits.get(), kCTFontWeightTrait, cfFontWeight.get());
86     }
87     // CTFontTraits (width)
88     CGFloat ctWidth = SkCTFontCTWidthForCSSWidth(style.width());
89     SkUniqueCFRef<CFNumberRef> cfFontWidth(
90             CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWidth));
91     if (cfFontWidth) {
92         CFDictionaryAddValue(cfTraits.get(), kCTFontWidthTrait, cfFontWidth.get());
93     }
94     // CTFontTraits (slant)
95     // Slope value set to 0.07 based on WebKit's implementation for better font matching
96     static const CGFloat kSystemFontItalicSlope = 0.07;
97     CGFloat ctSlant = style.slant() == SkFontStyle::kUpright_Slant ? 0 : kSystemFontItalicSlope;
98     SkUniqueCFRef<CFNumberRef> cfFontSlant(
99             CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctSlant));
100     if (cfFontSlant) {
101         CFDictionaryAddValue(cfTraits.get(), kCTFontSlantTrait, cfFontSlant.get());
102     }
103     // CTFontTraits
104     CFDictionaryAddValue(cfAttributes.get(), kCTFontTraitsAttribute, cfTraits.get());
105 
106     // CTFontFamilyName
107     if (familyName) {
108         SkUniqueCFRef<CFStringRef> cfFontName = make_CFString(familyName);
109         if (cfFontName) {
110             CFDictionaryAddValue(cfAttributes.get(), kCTFontFamilyNameAttribute, cfFontName.get());
111         }
112     }
113 
114     return SkUniqueCFRef<CTFontDescriptorRef>(
115             CTFontDescriptorCreateWithAttributes(cfAttributes.get()));
116 }
117 
118 // Same as the above function except style is included so we can
119 // compare whether the created font conforms to the style. If not, we need
120 // to recreate the font with symbolic traits. This is needed due to MacOS 10.11
121 // font creation problem https://bugs.chromium.org/p/skia/issues/detail?id=8447.
create_from_desc_and_style(CTFontDescriptorRef desc,const SkFontStyle & style)122 static sk_sp<SkTypeface> create_from_desc_and_style(CTFontDescriptorRef desc,
123                                                     const SkFontStyle& style) {
124     SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr));
125     if (!ctFont) {
126         return nullptr;
127     }
128 
129     const CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctFont.get());
130     CTFontSymbolicTraits expected_traits = traits;
131     if (style.slant() != SkFontStyle::kUpright_Slant) {
132         expected_traits |= kCTFontItalicTrait;
133     }
134     if (style.weight() >= SkFontStyle::kBold_Weight) {
135         expected_traits |= kCTFontBoldTrait;
136     }
137 
138     if (expected_traits != traits) {
139         SkUniqueCFRef<CTFontRef> ctNewFont(CTFontCreateCopyWithSymbolicTraits(
140                     ctFont.get(), 0, nullptr, expected_traits, expected_traits));
141         if (ctNewFont) {
142             ctFont = std::move(ctNewFont);
143         }
144     }
145 
146     return SkTypeface_Mac::Make(std::move(ctFont), OpszVariation(), nullptr);
147 }
148 
149 /** Creates a typeface from a name, searching the cache. */
create_from_name(const char familyName[],const SkFontStyle & style)150 static sk_sp<SkTypeface> create_from_name(const char familyName[], const SkFontStyle& style) {
151     SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
152     if (!desc) {
153         return nullptr;
154     }
155     return create_from_desc_and_style(desc.get(), style);
156 }
157 
map_css_names(const char * name)158 static const char* map_css_names(const char* name) {
159     static const struct {
160         const char* fFrom;  // name the caller specified
161         const char* fTo;    // "canonical" name we map to
162     } gPairs[] = {
163         { "sans-serif", "Helvetica" },
164         { "serif",      "Times"     },
165         { "monospace",  "Courier"   }
166     };
167 
168     for (size_t i = 0; i < std::size(gPairs); i++) {
169         if (strcmp(name, gPairs[i].fFrom) == 0) {
170             return gPairs[i].fTo;
171         }
172     }
173     return name;    // no change
174 }
175 
176 namespace {
177 
find_desc_str(CTFontDescriptorRef desc,CFStringRef name,SkString * value)178 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
179     SkUniqueCFRef<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
180     if (!ref) {
181         return false;
182     }
183     SkStringFromCFString(ref.get(), value);
184     return true;
185 }
186 
sqr(int value)187 static inline int sqr(int value) {
188     SkASSERT(SkAbs32(value) < 0x7FFF);  // check for overflow
189     return value * value;
190 }
191 
192 // We normalize each axis (weight, width, italic) to be base-900
compute_metric(const SkFontStyle & a,const SkFontStyle & b)193 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
194     return sqr(a.weight() - b.weight()) +
195            sqr((a.width() - b.width()) * 100) +
196            sqr((a.slant() != b.slant()) * 900);
197 }
198 
name_required()199 static SkUniqueCFRef<CFSetRef> name_required() {
200     CFStringRef set_values[] = {kCTFontFamilyNameAttribute};
201     return SkUniqueCFRef<CFSetRef>(CFSetCreate(kCFAllocatorDefault,
202         reinterpret_cast<const void**>(set_values), std::size(set_values),
203         &kCFTypeSetCallBacks));
204 }
205 
206 class SkFontStyleSet_Mac : public SkFontStyleSet {
207 public:
SkFontStyleSet_Mac(CTFontDescriptorRef desc)208     SkFontStyleSet_Mac(CTFontDescriptorRef desc)
209         : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, name_required().get()))
210         , fCount(0)
211     {
212         if (!fArray) {
213             fArray.reset(CFArrayCreate(nullptr, nullptr, 0, nullptr));
214         }
215         fCount = SkToInt(CFArrayGetCount(fArray.get()));
216     }
217 
count()218     int count() override {
219         return fCount;
220     }
221 
getStyle(int index,SkFontStyle * style,SkString * name)222     void getStyle(int index, SkFontStyle* style, SkString* name) override {
223         SkASSERT((unsigned)index < (unsigned)fCount);
224         CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
225         if (style) {
226             *style = SkCTFontDescriptorGetSkFontStyle(desc, false);
227         }
228         if (name) {
229             if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
230                 name->reset();
231             }
232         }
233     }
234 
createTypeface(int index)235     sk_sp<SkTypeface> createTypeface(int index) override {
236         SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray.get()));
237         CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
238 
239         return create_from_desc(desc);
240     }
241 
matchStyle(const SkFontStyle & pattern)242     sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override {
243         if (0 == fCount) {
244             return nullptr;
245         }
246         return create_from_desc(findMatchingDesc(pattern));
247     }
248 
249 private:
250     SkUniqueCFRef<CFArrayRef> fArray;
251     int fCount;
252 
findMatchingDesc(const SkFontStyle & pattern) const253     CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
254         int bestMetric = SK_MaxS32;
255         CTFontDescriptorRef bestDesc = nullptr;
256 
257         for (int i = 0; i < fCount; ++i) {
258             CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), i);
259             int metric = compute_metric(pattern, SkCTFontDescriptorGetSkFontStyle(desc, false));
260             if (0 == metric) {
261                 return desc;
262             }
263             if (metric < bestMetric) {
264                 bestMetric = metric;
265                 bestDesc = desc;
266             }
267         }
268         SkASSERT(bestDesc);
269         return bestDesc;
270     }
271 };
272 
SkCopyAvailableFontFamilyNames(CTFontCollectionRef collection)273 SkUniqueCFRef<CFArrayRef> SkCopyAvailableFontFamilyNames(CTFontCollectionRef collection) {
274     // Create a CFArray of all available font descriptors.
275     SkUniqueCFRef<CFArrayRef> descriptors(
276         CTFontCollectionCreateMatchingFontDescriptors(collection));
277 
278     // Copy the font family names of the font descriptors into a CFSet.
279     auto addDescriptorFamilyNameToSet = [](const void* value, void* context) -> void {
280         CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(value);
281         CFMutableSetRef familyNameSet = static_cast<CFMutableSetRef>(context);
282         SkUniqueCFRef<CFTypeRef> familyName(
283             CTFontDescriptorCopyAttribute(descriptor, kCTFontFamilyNameAttribute));
284         if (familyName) {
285             CFSetAddValue(familyNameSet, familyName.get());
286         }
287     };
288     SkUniqueCFRef<CFMutableSetRef> familyNameSet(
289         CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks));
290     CFArrayApplyFunction(descriptors.get(), CFRangeMake(0, CFArrayGetCount(descriptors.get())),
291                          addDescriptorFamilyNameToSet, familyNameSet.get());
292 
293     // Get the set of family names into an array; this does not retain.
294     CFIndex count = CFSetGetCount(familyNameSet.get());
295     std::unique_ptr<const void*[]> familyNames(new const void*[count]);
296     CFSetGetValues(familyNameSet.get(), familyNames.get());
297 
298     // Sort the array of family names (to match CTFontManagerCopyAvailableFontFamilyNames).
299     std::sort(familyNames.get(), familyNames.get() + count, [](const void* a, const void* b){
300         return CFStringCompare((CFStringRef)a, (CFStringRef)b, 0) == kCFCompareLessThan;
301     });
302 
303     // Copy family names into a CFArray; this does retain.
304     return SkUniqueCFRef<CFArrayRef>(
305         CFArrayCreate(kCFAllocatorDefault, familyNames.get(), count, &kCFTypeArrayCallBacks));
306 }
307 
308 /** Use CTFontManagerCopyAvailableFontFamilyNames if available, simulate if not. */
SkCTFontManagerCopyAvailableFontFamilyNames()309 SkUniqueCFRef<CFArrayRef> SkCTFontManagerCopyAvailableFontFamilyNames() {
310 #ifdef SK_BUILD_FOR_IOS
311     using CTFontManagerCopyAvailableFontFamilyNamesProc = CFArrayRef (*)(void);
312     CTFontManagerCopyAvailableFontFamilyNamesProc ctFontManagerCopyAvailableFontFamilyNames;
313     *(void**)(&ctFontManagerCopyAvailableFontFamilyNames) =
314         dlsym(RTLD_DEFAULT, "CTFontManagerCopyAvailableFontFamilyNames");
315     if (ctFontManagerCopyAvailableFontFamilyNames) {
316         return SkUniqueCFRef<CFArrayRef>(ctFontManagerCopyAvailableFontFamilyNames());
317     }
318     SkUniqueCFRef<CTFontCollectionRef> collection(
319         CTFontCollectionCreateFromAvailableFonts(nullptr));
320     return SkUniqueCFRef<CFArrayRef>(SkCopyAvailableFontFamilyNames(collection.get()));
321 #else
322     return SkUniqueCFRef<CFArrayRef>(CTFontManagerCopyAvailableFontFamilyNames());
323 #endif
324 }
325 
326 } // namespace
327 
328 class SkFontMgr_Mac : public SkFontMgr {
329     SkUniqueCFRef<CFArrayRef> fNames;
330     int fCount;
331 
getFamilyNameAt(int index) const332     CFStringRef getFamilyNameAt(int index) const {
333         SkASSERT((unsigned)index < (unsigned)fCount);
334         return (CFStringRef)CFArrayGetValueAtIndex(fNames.get(), index);
335     }
336 
CreateSet(CFStringRef cfFamilyName)337     static sk_sp<SkFontStyleSet> CreateSet(CFStringRef cfFamilyName) {
338         SkUniqueCFRef<CFMutableDictionaryRef> cfAttr(
339                  CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
340                                            &kCFTypeDictionaryKeyCallBacks,
341                                            &kCFTypeDictionaryValueCallBacks));
342 
343         CFDictionaryAddValue(cfAttr.get(), kCTFontFamilyNameAttribute, cfFamilyName);
344 
345         SkUniqueCFRef<CTFontDescriptorRef> desc(
346                 CTFontDescriptorCreateWithAttributes(cfAttr.get()));
347         return sk_sp<SkFontStyleSet>(new SkFontStyleSet_Mac(desc.get()));
348     }
349 
350 public:
351     SkUniqueCFRef<CTFontCollectionRef> fFontCollection;
SkFontMgr_Mac(CTFontCollectionRef fontCollection)352     SkFontMgr_Mac(CTFontCollectionRef fontCollection)
353         : fNames(fontCollection ? SkCopyAvailableFontFamilyNames(fontCollection)
354                                 : SkCTFontManagerCopyAvailableFontFamilyNames())
355         , fCount(fNames ? SkToInt(CFArrayGetCount(fNames.get())) : 0)
356         , fFontCollection(fontCollection ? (CTFontCollectionRef)CFRetain(fontCollection)
357                                          : CTFontCollectionCreateFromAvailableFonts(nullptr))
358     {
359 #if defined(CROSS_PLATFORM)
360         std::string path(SkFontMgr::containerFontPath);
361         if (path.empty()) {
362             return;
363         }
364         SkString fontDir(path.c_str());
365         path += "/HMSymbolVF.ttf";
366         sk_sp<SkTypeface> typeface = onMakeFromFile(path.c_str(), 0);
367         if (!typeface) {
368             return;
369         }
370         sk_sp<SkData> fontData = SkData::MakeFromFileName(path.c_str());
371         if (!fontData) {
372             return;
373         }
374         skia::text::HmSymbolConfig_OHOS::LoadSymbolConfig("hm_symbol_config_next.json", fontDir);
375         SkUniqueCFRef<CFDataRef> cfData =
376             SkUniqueCFRef<CFDataRef>(CFDataCreate(kCFAllocatorDefault, fontData->bytes(), fontData->size()));
377         if (!cfData) {
378             return;
379         }
380         SkUniqueCFRef<CGDataProviderRef> dataProvider =
381             SkUniqueCFRef<CGDataProviderRef>(CGDataProviderCreateWithCFData(cfData.get()));
382         if (!dataProvider) {
383             return;
384         }
385         SkUniqueCFRef<CGFontRef> cgFont = SkUniqueCFRef<CGFontRef>(CGFontCreateWithDataProvider(dataProvider.get()));
386         if (!cgFont) {
387             return;
388         }
389         CTFontManagerRegisterGraphicsFont(cgFont.get(), nullptr);
390 #endif
391     }
392 
393 protected:
onCountFamilies() const394     int onCountFamilies() const override {
395         return fCount;
396     }
397 
onGetFamilyName(int index,SkString * familyName) const398     void onGetFamilyName(int index, SkString* familyName) const override {
399         if ((unsigned)index < (unsigned)fCount) {
400             SkStringFromCFString(this->getFamilyNameAt(index), familyName);
401         } else {
402             familyName->reset();
403         }
404     }
405 
onCreateStyleSet(int index) const406     sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
407         if ((unsigned)index >= (unsigned)fCount) {
408             return nullptr;
409         }
410         return CreateSet(this->getFamilyNameAt(index));
411     }
412 
onMatchFamily(const char familyName[]) const413     sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override {
414         if (!familyName) {
415             return nullptr;
416         }
417         SkUniqueCFRef<CFStringRef> cfName = make_CFString(familyName);
418         return CreateSet(cfName.get());
419     }
420 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const421     sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
422                                    const SkFontStyle& style) const override {
423         SkUniqueCFRef<CTFontDescriptorRef> reqDesc = create_descriptor(familyName, style);
424         if (!familyName) {
425             return create_from_desc(reqDesc.get());
426         }
427         SkUniqueCFRef<CTFontDescriptorRef> resolvedDesc(
428             CTFontDescriptorCreateMatchingFontDescriptor(reqDesc.get(), name_required().get()));
429         if (!resolvedDesc) {
430             return nullptr;
431         }
432         return create_from_desc(resolvedDesc.get());
433     }
434 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const435     sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[],
436                                                   const SkFontStyle& style,
437                                                   const char* bcp47[], int bcp47Count,
438                                                   SkUnichar character) const override {
439         SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
440         SkUniqueCFRef<CTFontRef> familyFont(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
441 
442         // kCFStringEncodingUTF32 is BE unless there is a BOM.
443         // Since there is no machine endian option, explicitly state machine endian.
444 #ifdef SK_CPU_LENDIAN
445         constexpr CFStringEncoding encoding = kCFStringEncodingUTF32LE;
446 #else
447         constexpr CFStringEncoding encoding = kCFStringEncodingUTF32BE;
448 #endif
449         SkUniqueCFRef<CFStringRef> string(CFStringCreateWithBytes(
450                 kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(&character), sizeof(character),
451                 encoding, false));
452         // If 0xD800 <= codepoint <= 0xDFFF || 0x10FFFF < codepoint 'string' may be nullptr.
453         // No font should be covering such codepoints (even the magic fallback font).
454         if (!string) {
455             return nullptr;
456         }
457         CFRange range = CFRangeMake(0, CFStringGetLength(string.get()));  // in UniChar units.
458         SkUniqueCFRef<CTFontRef> fallbackFont(
459                 CTFontCreateForString(familyFont.get(), string.get(), range));
460         return SkTypeface_Mac::Make(std::move(fallbackFont), OpszVariation(), nullptr);
461     }
462 
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const463     sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
464         return this->makeFromStream(
465                 std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data))), ttcIndex);
466     }
467 
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const468     sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
469                                             int ttcIndex) const override {
470         return this->makeFromStream(std::move(stream),
471                                     SkFontArguments().setCollectionIndex(ttcIndex));
472     }
473 
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const474     sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
475                                            const SkFontArguments& args) const override {
476         return SkTypeface_Mac::MakeFromStream(std::move(stream), args);
477     }
478 
onMakeFromFile(const char path[],int ttcIndex) const479     sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
480         sk_sp<SkData> data = SkData::MakeFromFileName(path);
481         if (!data) {
482             return nullptr;
483         }
484 
485         return this->onMakeFromData(std::move(data), ttcIndex);
486     }
487 
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const488     sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
489         if (familyName) {
490             familyName = map_css_names(familyName);
491         }
492 
493         sk_sp<SkTypeface> face = create_from_name(familyName, style);
494         if (face) {
495             return face;
496         }
497 
498         static SkTypeface* gDefaultFace;
499         static SkOnce lookupDefault;
500         static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
501         lookupDefault([]{
502             gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle()).release();
503         });
504         return sk_ref_sp(gDefaultFace);
505     }
506 };
507 
SkFontMgr_New_CoreText(CTFontCollectionRef fontCollection)508 sk_sp<SkFontMgr> SkFontMgr_New_CoreText(CTFontCollectionRef fontCollection) {
509     return sk_make_sp<SkFontMgr_Mac>(fontCollection);
510 }
511 
512 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
513