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