• 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 #if defined(CROSS_PLATFORM)
38 #include "src/ports/skia_ohos/HmSymbolConfig_ohos.h"
39 #endif
40 #include "src/ports/SkTypeface_mac_ct.h"
41 #include "src/utils/SkUTF.h"
42 
43 #include <string.h>
44 #include <memory>
45 
46 #if (defined(SK_BUILD_FOR_IOS) && defined(__IPHONE_14_0) &&  \
47       __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_14_0) ||  \
48     (defined(SK_BUILD_FOR_MAC) && defined(__MAC_11_0) &&     \
49       __MAC_OS_VERSION_MIN_REQUIRED >= __MAC_11_0)
50 
SkGetCoreTextVersion()51 static uint32_t SkGetCoreTextVersion() {
52     // If compiling for iOS 14.0+ or macOS 11.0+, the CoreText version number
53     // must be derived from the OS version number.
54     static const uint32_t kCoreTextVersionNEWER = 0x000D0000;
55     return kCoreTextVersionNEWER;
56 }
57 
58 #else
59 
SkGetCoreTextVersion()60 static uint32_t SkGetCoreTextVersion() {
61     // Check for CoreText availability before calling CTGetCoreTextVersion().
62     if (&CTGetCoreTextVersion) {
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 < SK_ARRAY_COUNT(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 
skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream)231 static sk_sp<SkData> skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream) {
232     size_t size = stream->getLength();
233     if (const void* base = stream->getMemoryBase()) {
234         return SkData::MakeWithProc(base, size,
235                                     [](const void*, void* ctx) -> void {
236                                         delete (SkStreamAsset*)ctx;
237                                     }, stream.release());
238     }
239     return SkData::MakeFromStream(stream.get(), size);
240 }
241 
cfdata_from_skdata(sk_sp<SkData> data)242 static SkUniqueCFRef<CFDataRef> cfdata_from_skdata(sk_sp<SkData> data) {
243     void const * const addr = data->data();
244     size_t const size = data->size();
245 
246     CFAllocatorContext ctx = {
247         0, // CFIndex version
248         data.release(), // void* info
249         nullptr, // const void *(*retain)(const void *info);
250         nullptr, // void (*release)(const void *info);
251         nullptr, // CFStringRef (*copyDescription)(const void *info);
252         nullptr, // void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info);
253         nullptr, // void*(*reallocate)(void* ptr,CFIndex newsize,CFOptionFlags hint,void* info);
254         [](void*,void* info) -> void { // void (*deallocate)(void *ptr, void *info);
255             SkASSERT(info);
256             ((SkData*)info)->unref();
257         },
258         nullptr, // CFIndex (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info);
259     };
260     SkUniqueCFRef<CFAllocatorRef> alloc(CFAllocatorCreate(kCFAllocatorDefault, &ctx));
261     return SkUniqueCFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(
262             kCFAllocatorDefault, (const UInt8 *)addr, size, alloc.get()));
263 }
264 
ctfont_from_skdata(sk_sp<SkData> data,int ttcIndex)265 static SkUniqueCFRef<CTFontRef> ctfont_from_skdata(sk_sp<SkData> data, int ttcIndex) {
266     // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available.
267     if (ttcIndex != 0) {
268         return nullptr;
269     }
270 
271     SkUniqueCFRef<CFDataRef> cfData(cfdata_from_skdata(std::move(data)));
272 
273     SkUniqueCFRef<CTFontDescriptorRef> desc(
274             CTFontManagerCreateFontDescriptorFromData(cfData.get()));
275     if (!desc) {
276         return nullptr;
277     }
278     return SkUniqueCFRef<CTFontRef>(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
279 }
280 
find_desc_str(CTFontDescriptorRef desc,CFStringRef name,SkString * value)281 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
282     SkUniqueCFRef<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
283     if (!ref) {
284         return false;
285     }
286     SkStringFromCFString(ref.get(), value);
287     return true;
288 }
289 
sqr(int value)290 static inline int sqr(int value) {
291     SkASSERT(SkAbs32(value) < 0x7FFF);  // check for overflow
292     return value * value;
293 }
294 
295 // We normalize each axis (weight, width, italic) to be base-900
compute_metric(const SkFontStyle & a,const SkFontStyle & b)296 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
297     return sqr(a.weight() - b.weight()) +
298            sqr((a.width() - b.width()) * 100) +
299            sqr((a.slant() != b.slant()) * 900);
300 }
301 
302 class SkFontStyleSet_Mac : public SkFontStyleSet {
303 public:
SkFontStyleSet_Mac(CTFontDescriptorRef desc)304     SkFontStyleSet_Mac(CTFontDescriptorRef desc)
305         : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, nullptr))
306         , fCount(0)
307     {
308         if (!fArray) {
309             fArray.reset(CFArrayCreate(nullptr, nullptr, 0, nullptr));
310         }
311         fCount = SkToInt(CFArrayGetCount(fArray.get()));
312     }
313 
count()314     int count() override {
315         return fCount;
316     }
317 
getStyle(int index,SkFontStyle * style,SkString * name)318     void getStyle(int index, SkFontStyle* style, SkString* name) override {
319         SkASSERT((unsigned)index < (unsigned)fCount);
320         CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
321         if (style) {
322             *style = SkCTFontDescriptorGetSkFontStyle(desc, false);
323         }
324         if (name) {
325             if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
326                 name->reset();
327             }
328         }
329     }
330 
createTypeface(int index)331     SkTypeface* createTypeface(int index) override {
332         SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray.get()));
333         CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
334 
335         return create_from_desc(desc).release();
336     }
337 
matchStyle(const SkFontStyle & pattern)338     SkTypeface* matchStyle(const SkFontStyle& pattern) override {
339         if (0 == fCount) {
340             return nullptr;
341         }
342         return create_from_desc(findMatchingDesc(pattern)).release();
343     }
344 
345 private:
346     SkUniqueCFRef<CFArrayRef> fArray;
347     int fCount;
348 
findMatchingDesc(const SkFontStyle & pattern) const349     CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
350         int bestMetric = SK_MaxS32;
351         CTFontDescriptorRef bestDesc = nullptr;
352 
353         for (int i = 0; i < fCount; ++i) {
354             CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), i);
355             int metric = compute_metric(pattern, SkCTFontDescriptorGetSkFontStyle(desc, false));
356             if (0 == metric) {
357                 return desc;
358             }
359             if (metric < bestMetric) {
360                 bestMetric = metric;
361                 bestDesc = desc;
362             }
363         }
364         SkASSERT(bestDesc);
365         return bestDesc;
366     }
367 };
368 
SkCopyAvailableFontFamilyNames(CTFontCollectionRef collection)369 SkUniqueCFRef<CFArrayRef> SkCopyAvailableFontFamilyNames(CTFontCollectionRef collection) {
370     // Create a CFArray of all available font descriptors.
371     SkUniqueCFRef<CFArrayRef> descriptors(
372         CTFontCollectionCreateMatchingFontDescriptors(collection));
373 
374     // Copy the font family names of the font descriptors into a CFSet.
375     auto addDescriptorFamilyNameToSet = [](const void* value, void* context) -> void {
376         CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(value);
377         CFMutableSetRef familyNameSet = static_cast<CFMutableSetRef>(context);
378         SkUniqueCFRef<CFTypeRef> familyName(
379             CTFontDescriptorCopyAttribute(descriptor, kCTFontFamilyNameAttribute));
380         if (familyName) {
381             CFSetAddValue(familyNameSet, familyName.get());
382         }
383     };
384     SkUniqueCFRef<CFMutableSetRef> familyNameSet(
385         CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks));
386     CFArrayApplyFunction(descriptors.get(), CFRangeMake(0, CFArrayGetCount(descriptors.get())),
387                          addDescriptorFamilyNameToSet, familyNameSet.get());
388 
389     // Get the set of family names into an array; this does not retain.
390     CFIndex count = CFSetGetCount(familyNameSet.get());
391     std::unique_ptr<const void*[]> familyNames(new const void*[count]);
392     CFSetGetValues(familyNameSet.get(), familyNames.get());
393 
394     // Sort the array of family names (to match CTFontManagerCopyAvailableFontFamilyNames).
395     std::sort(familyNames.get(), familyNames.get() + count, [](const void* a, const void* b){
396         return CFStringCompare((CFStringRef)a, (CFStringRef)b, 0) == kCFCompareLessThan;
397     });
398 
399     // Copy family names into a CFArray; this does retain.
400     return SkUniqueCFRef<CFArrayRef>(
401         CFArrayCreate(kCFAllocatorDefault, familyNames.get(), count, &kCFTypeArrayCallBacks));
402 }
403 
404 /** Use CTFontManagerCopyAvailableFontFamilyNames if available, simulate if not. */
SkCTFontManagerCopyAvailableFontFamilyNames()405 SkUniqueCFRef<CFArrayRef> SkCTFontManagerCopyAvailableFontFamilyNames() {
406 #ifdef SK_BUILD_FOR_IOS
407     using CTFontManagerCopyAvailableFontFamilyNamesProc = CFArrayRef (*)(void);
408     CTFontManagerCopyAvailableFontFamilyNamesProc ctFontManagerCopyAvailableFontFamilyNames;
409     *(void**)(&ctFontManagerCopyAvailableFontFamilyNames) =
410         dlsym(RTLD_DEFAULT, "CTFontManagerCopyAvailableFontFamilyNames");
411     if (ctFontManagerCopyAvailableFontFamilyNames) {
412         return SkUniqueCFRef<CFArrayRef>(ctFontManagerCopyAvailableFontFamilyNames());
413     }
414     SkUniqueCFRef<CTFontCollectionRef> collection(
415         CTFontCollectionCreateFromAvailableFonts(nullptr));
416     return SkUniqueCFRef<CFArrayRef>(SkCopyAvailableFontFamilyNames(collection.get()));
417 #else
418     return SkUniqueCFRef<CFArrayRef>(CTFontManagerCopyAvailableFontFamilyNames());
419 #endif
420 }
421 
422 } // namespace
423 
424 class SkFontMgr_Mac : public SkFontMgr {
425     SkUniqueCFRef<CFArrayRef> fNames;
426     int fCount;
427 
getFamilyNameAt(int index) const428     CFStringRef getFamilyNameAt(int index) const {
429         SkASSERT((unsigned)index < (unsigned)fCount);
430         return (CFStringRef)CFArrayGetValueAtIndex(fNames.get(), index);
431     }
432 
CreateSet(CFStringRef cfFamilyName)433     static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) {
434         SkUniqueCFRef<CFMutableDictionaryRef> cfAttr(
435                  CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
436                                            &kCFTypeDictionaryKeyCallBacks,
437                                            &kCFTypeDictionaryValueCallBacks));
438 
439         CFDictionaryAddValue(cfAttr.get(), kCTFontFamilyNameAttribute, cfFamilyName);
440 
441         SkUniqueCFRef<CTFontDescriptorRef> desc(
442                 CTFontDescriptorCreateWithAttributes(cfAttr.get()));
443         return new SkFontStyleSet_Mac(desc.get());
444     }
445 
446 public:
447     SkUniqueCFRef<CTFontCollectionRef> fFontCollection;
SkFontMgr_Mac(CTFontCollectionRef fontCollection)448     SkFontMgr_Mac(CTFontCollectionRef fontCollection)
449         : fNames(fontCollection ? SkCopyAvailableFontFamilyNames(fontCollection)
450                                 : SkCTFontManagerCopyAvailableFontFamilyNames())
451         , fCount(fNames ? SkToInt(CFArrayGetCount(fNames.get())) : 0)
452         , fFontCollection(fontCollection ? (CTFontCollectionRef)CFRetain(fontCollection)
453                                          : CTFontCollectionCreateFromAvailableFonts(nullptr))
454     {
455 #if defined(CROSS_PLATFORM)
456         std::string path(SkFontMgr::containerFontPath);
457         if (path.empty()) {
458             return;
459         }
460         SkString fontDir(path.c_str());
461         path += "/HMSymbolVF.ttf";
462         sk_sp<SkTypeface> typeface = onMakeFromFile(path.c_str(), 0);
463         if (!typeface) {
464             return;
465         }
466         sk_sp<SkData> fontData = SkData::MakeFromFileName(path.c_str());
467         if (!fontData) {
468             return;
469         }
470         skia::text::HmSymbolConfig_OHOS::LoadSymbolConfig("hm_symbol_config_next.json", fontDir);
471         SkUniqueCFRef<CFDataRef> cfData =
472             SkUniqueCFRef<CFDataRef>(CFDataCreate(kCFAllocatorDefault, fontData->bytes(), fontData->size()));
473         if (!cfData) {
474             return;
475         }
476         SkUniqueCFRef<CGDataProviderRef> dataProvider =
477             SkUniqueCFRef<CGDataProviderRef>(CGDataProviderCreateWithCFData(cfData.get()));
478         if (!dataProvider) {
479             return;
480         }
481         SkUniqueCFRef<CGFontRef> cgFont = SkUniqueCFRef<CGFontRef>(CGFontCreateWithDataProvider(dataProvider.get()));
482         if (!cgFont) {
483             return;
484         }
485         CTFontManagerRegisterGraphicsFont(cgFont.get(), nullptr);
486 #endif
487     }
488 
489 protected:
onCountFamilies() const490     int onCountFamilies() const override {
491         return fCount;
492     }
493 
onGetFamilyName(int index,SkString * familyName) const494     void onGetFamilyName(int index, SkString* familyName) const override {
495         if ((unsigned)index < (unsigned)fCount) {
496             SkStringFromCFString(this->getFamilyNameAt(index), familyName);
497         } else {
498             familyName->reset();
499         }
500     }
501 
onCreateStyleSet(int index) const502     SkFontStyleSet* onCreateStyleSet(int index) const override {
503         if ((unsigned)index >= (unsigned)fCount) {
504             return nullptr;
505         }
506         return CreateSet(this->getFamilyNameAt(index));
507     }
508 
onMatchFamily(const char familyName[]) const509     SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
510         if (!familyName) {
511             return nullptr;
512         }
513         SkUniqueCFRef<CFStringRef> cfName = make_CFString(familyName);
514         return CreateSet(cfName.get());
515     }
516 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const517     SkTypeface* onMatchFamilyStyle(const char familyName[],
518                                    const SkFontStyle& style) const override {
519         SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
520         return create_from_desc(desc.get()).release();
521     }
522 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const523     SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
524                                             const SkFontStyle& style,
525                                             const char* bcp47[], int bcp47Count,
526                                             SkUnichar character) const override {
527         SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
528         SkUniqueCFRef<CTFontRef> familyFont(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
529 
530         // kCFStringEncodingUTF32 is BE unless there is a BOM.
531         // Since there is no machine endian option, explicitly state machine endian.
532 #ifdef SK_CPU_LENDIAN
533         constexpr CFStringEncoding encoding = kCFStringEncodingUTF32LE;
534 #else
535         constexpr CFStringEncoding encoding = kCFStringEncodingUTF32BE;
536 #endif
537         SkUniqueCFRef<CFStringRef> string(CFStringCreateWithBytes(
538                 kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(&character), sizeof(character),
539                 encoding, false));
540         // If 0xD800 <= codepoint <= 0xDFFF || 0x10FFFF < codepoint 'string' may be nullptr.
541         // No font should be covering such codepoints (even the magic fallback font).
542         if (!string) {
543             return nullptr;
544         }
545         CFRange range = CFRangeMake(0, CFStringGetLength(string.get()));  // in UniChar units.
546         SkUniqueCFRef<CTFontRef> fallbackFont(
547                 CTFontCreateForString(familyFont.get(), string.get(), range));
548         return SkTypeface_Mac::Make(std::move(fallbackFont), OpszVariation(), nullptr).release();
549     }
550 
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const551     sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
552         if (ttcIndex != 0) {
553             return nullptr;
554         }
555 
556         SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(data, ttcIndex);
557         if (!ct) {
558             return nullptr;
559         }
560 
561         return SkTypeface_Mac::Make(std::move(ct), OpszVariation(),
562                                     SkMemoryStream::Make(std::move(data)));
563     }
564 
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const565     sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
566                                             int ttcIndex) const override {
567         if (ttcIndex != 0) {
568             return nullptr;
569         }
570 
571         sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate());
572         if (!data) {
573             return nullptr;
574         }
575         SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex);
576         if (!ct) {
577             return nullptr;
578         }
579 
580         return SkTypeface_Mac::Make(std::move(ct), OpszVariation(), std::move(stream));
581     }
582 
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const583     sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
584                                            const SkFontArguments& args) const override
585     {
586         // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available.
587         int ttcIndex = args.getCollectionIndex();
588         if (ttcIndex != 0) {
589             return nullptr;
590         }
591 
592         sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate());
593         if (!data) {
594             return nullptr;
595         }
596         SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex);
597         if (!ct) {
598             return nullptr;
599         }
600 
601         CTFontVariation ctVariation = SkCTVariationFromSkFontArguments(ct.get(), args);
602 
603         SkUniqueCFRef<CTFontRef> ctVariant;
604         if (ctVariation.variation) {
605             SkUniqueCFRef<CFMutableDictionaryRef> attributes(
606                     CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
607                                               &kCFTypeDictionaryKeyCallBacks,
608                                               &kCFTypeDictionaryValueCallBacks));
609             CFDictionaryAddValue(attributes.get(),
610                                  kCTFontVariationAttribute, ctVariation.variation.get());
611             SkUniqueCFRef<CTFontDescriptorRef> varDesc(
612                     CTFontDescriptorCreateWithAttributes(attributes.get()));
613             ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get()));
614         } else {
615             ctVariant.reset(ct.release());
616         }
617         if (!ctVariant) {
618             return nullptr;
619         }
620 
621         return SkTypeface_Mac::Make(std::move(ctVariant), ctVariation.opsz, std::move(stream));
622     }
623 
onMakeFromFile(const char path[],int ttcIndex) const624     sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
625         if (ttcIndex != 0) {
626             return nullptr;
627         }
628 
629         sk_sp<SkData> data = SkData::MakeFromFileName(path);
630         if (!data) {
631             return nullptr;
632         }
633 
634         return this->onMakeFromData(std::move(data), ttcIndex);
635     }
636 
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const637     sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
638         if (familyName) {
639             familyName = map_css_names(familyName);
640         }
641 
642         sk_sp<SkTypeface> face = create_from_name(familyName, style);
643         if (face) {
644             return face;
645         }
646 
647         static SkTypeface* gDefaultFace;
648         static SkOnce lookupDefault;
649         static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
650         lookupDefault([]{
651             gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle()).release();
652         });
653         return sk_ref_sp(gDefaultFace);
654     }
655 };
656 
SkFontMgr_New_CoreText(CTFontCollectionRef fontCollection)657 sk_sp<SkFontMgr> SkFontMgr_New_CoreText(CTFontCollectionRef fontCollection) {
658     return sk_make_sp<SkFontMgr_Mac>(fontCollection);
659 }
660 
661 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
662