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