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