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