• 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/base/SkFixed.h"
32 #include "include/private/base/SkOnce.h"
33 #include "include/private/base/SkTPin.h"
34 #include "include/private/base/SkTemplates.h"
35 #include "include/private/base/SkTo.h"
36 #include "src/base/SkUTF.h"
37 #include "src/core/SkFontDescriptor.h"
38 #include "src/ports/SkTypeface_mac_ct.h"
39 
40 #include <string.h>
41 #include <memory>
42 
43 using namespace skia_private;
44 
make_CFString(const char s[])45 static SkUniqueCFRef<CFStringRef> make_CFString(const char s[]) {
46     return SkUniqueCFRef<CFStringRef>(CFStringCreateWithCString(nullptr, s, kCFStringEncodingUTF8));
47 }
48 
49 /** Creates a typeface from a descriptor, searching the cache. */
create_from_desc(CTFontDescriptorRef desc)50 static sk_sp<SkTypeface> create_from_desc(CTFontDescriptorRef desc) {
51     SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr));
52     if (!ctFont) {
53         return nullptr;
54     }
55 
56     return SkTypeface_Mac::Make(std::move(ctFont), OpszVariation(), nullptr);
57 }
58 
create_descriptor(const char familyName[],const SkFontStyle & style)59 static SkUniqueCFRef<CTFontDescriptorRef> create_descriptor(const char familyName[],
60                                                             const SkFontStyle& style) {
61     SkUniqueCFRef<CFMutableDictionaryRef> cfAttributes(
62             CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
63                                       &kCFTypeDictionaryKeyCallBacks,
64                                       &kCFTypeDictionaryValueCallBacks));
65 
66     SkUniqueCFRef<CFMutableDictionaryRef> cfTraits(
67             CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
68                                       &kCFTypeDictionaryKeyCallBacks,
69                                       &kCFTypeDictionaryValueCallBacks));
70 
71     if (!cfAttributes || !cfTraits) {
72         return nullptr;
73     }
74 
75     // Setting both kCTFontSymbolicTrait and the specific WWS traits may lead to strange outcomes.
76 
77     // CTFontTraits (weight)
78     CGFloat ctWeight = SkCTFontCTWeightForCSSWeight(style.weight());
79     SkUniqueCFRef<CFNumberRef> cfFontWeight(
80             CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWeight));
81     if (cfFontWeight) {
82         CFDictionaryAddValue(cfTraits.get(), kCTFontWeightTrait, cfFontWeight.get());
83     }
84     // CTFontTraits (width)
85     CGFloat ctWidth = SkCTFontCTWidthForCSSWidth(style.width());
86     SkUniqueCFRef<CFNumberRef> cfFontWidth(
87             CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWidth));
88     if (cfFontWidth) {
89         CFDictionaryAddValue(cfTraits.get(), kCTFontWidthTrait, cfFontWidth.get());
90     }
91     // CTFontTraits (slant)
92     // Slope value set to 0.07 based on WebKit's implementation for better font matching
93     static const CGFloat kSystemFontItalicSlope = 0.07;
94     CGFloat ctSlant = style.slant() == SkFontStyle::kUpright_Slant ? 0 : kSystemFontItalicSlope;
95     SkUniqueCFRef<CFNumberRef> cfFontSlant(
96             CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctSlant));
97     if (cfFontSlant) {
98         CFDictionaryAddValue(cfTraits.get(), kCTFontSlantTrait, cfFontSlant.get());
99     }
100     // CTFontTraits
101     CFDictionaryAddValue(cfAttributes.get(), kCTFontTraitsAttribute, cfTraits.get());
102 
103     // CTFontFamilyName
104     if (familyName) {
105         SkUniqueCFRef<CFStringRef> cfFontName = make_CFString(familyName);
106         if (cfFontName) {
107             CFDictionaryAddValue(cfAttributes.get(), kCTFontFamilyNameAttribute, cfFontName.get());
108         }
109     }
110 
111     return SkUniqueCFRef<CTFontDescriptorRef>(
112             CTFontDescriptorCreateWithAttributes(cfAttributes.get()));
113 }
114 
115 // Same as the above function except style is included so we can
116 // compare whether the created font conforms to the style. If not, we need
117 // to recreate the font with symbolic traits. This is needed due to MacOS 10.11
118 // font creation problem https://bugs.chromium.org/p/skia/issues/detail?id=8447.
create_from_desc_and_style(CTFontDescriptorRef desc,const SkFontStyle & style)119 static sk_sp<SkTypeface> create_from_desc_and_style(CTFontDescriptorRef desc,
120                                                     const SkFontStyle& style) {
121     SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr));
122     if (!ctFont) {
123         return nullptr;
124     }
125 
126     const CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctFont.get());
127     CTFontSymbolicTraits expected_traits = traits;
128     if (style.slant() != SkFontStyle::kUpright_Slant) {
129         expected_traits |= kCTFontItalicTrait;
130     }
131     if (style.weight() >= SkFontStyle::kBold_Weight) {
132         expected_traits |= kCTFontBoldTrait;
133     }
134 
135     if (expected_traits != traits) {
136         SkUniqueCFRef<CTFontRef> ctNewFont(CTFontCreateCopyWithSymbolicTraits(
137                     ctFont.get(), 0, nullptr, expected_traits, expected_traits));
138         if (ctNewFont) {
139             ctFont = std::move(ctNewFont);
140         }
141     }
142 
143     return SkTypeface_Mac::Make(std::move(ctFont), OpszVariation(), nullptr);
144 }
145 
146 /** Creates a typeface from a name, searching the cache. */
create_from_name(const char familyName[],const SkFontStyle & style)147 static sk_sp<SkTypeface> create_from_name(const char familyName[], const SkFontStyle& style) {
148     SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
149     if (!desc) {
150         return nullptr;
151     }
152     return create_from_desc_and_style(desc.get(), style);
153 }
154 
map_css_names(const char * name)155 static const char* map_css_names(const char* name) {
156     static const struct {
157         const char* fFrom;  // name the caller specified
158         const char* fTo;    // "canonical" name we map to
159     } gPairs[] = {
160         { "sans-serif", "Helvetica" },
161         { "serif",      "Times"     },
162         { "monospace",  "Courier"   }
163     };
164 
165     for (size_t i = 0; i < std::size(gPairs); i++) {
166         if (strcmp(name, gPairs[i].fFrom) == 0) {
167             return gPairs[i].fTo;
168         }
169     }
170     return name;    // no change
171 }
172 
173 namespace {
174 
find_desc_str(CTFontDescriptorRef desc,CFStringRef name,SkString * value)175 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
176     SkUniqueCFRef<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
177     if (!ref) {
178         return false;
179     }
180     SkStringFromCFString(ref.get(), value);
181     return true;
182 }
183 
sqr(int value)184 static inline int sqr(int value) {
185     SkASSERT(SkAbs32(value) < 0x7FFF);  // check for overflow
186     return value * value;
187 }
188 
189 // We normalize each axis (weight, width, italic) to be base-900
compute_metric(const SkFontStyle & a,const SkFontStyle & b)190 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
191     return sqr(a.weight() - b.weight()) +
192            sqr((a.width() - b.width()) * 100) +
193            sqr((a.slant() != b.slant()) * 900);
194 }
195 
name_required()196 static SkUniqueCFRef<CFSetRef> name_required() {
197     CFStringRef set_values[] = {kCTFontFamilyNameAttribute};
198     return SkUniqueCFRef<CFSetRef>(CFSetCreate(kCFAllocatorDefault,
199         reinterpret_cast<const void**>(set_values), std::size(set_values),
200         &kCFTypeSetCallBacks));
201 }
202 
203 class SkFontStyleSet_Mac : public SkFontStyleSet {
204 public:
SkFontStyleSet_Mac(CTFontDescriptorRef desc)205     SkFontStyleSet_Mac(CTFontDescriptorRef desc)
206         : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, name_required().get()))
207         , fCount(0)
208     {
209         if (!fArray) {
210             fArray.reset(CFArrayCreate(nullptr, nullptr, 0, nullptr));
211         }
212         fCount = SkToInt(CFArrayGetCount(fArray.get()));
213     }
214 
count()215     int count() override {
216         return fCount;
217     }
218 
getStyle(int index,SkFontStyle * style,SkString * name)219     void getStyle(int index, SkFontStyle* style, SkString* name) override {
220         SkASSERT((unsigned)index < (unsigned)fCount);
221         CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
222         if (style) {
223             *style = SkCTFontDescriptorGetSkFontStyle(desc, false);
224         }
225         if (name) {
226             if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
227                 name->reset();
228             }
229         }
230     }
231 
createTypeface(int index)232     sk_sp<SkTypeface> createTypeface(int index) override {
233         SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray.get()));
234         CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
235 
236         return create_from_desc(desc);
237     }
238 
matchStyle(const SkFontStyle & pattern)239     sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override {
240         if (0 == fCount) {
241             return nullptr;
242         }
243         return create_from_desc(findMatchingDesc(pattern));
244     }
245 
246 private:
247     SkUniqueCFRef<CFArrayRef> fArray;
248     int fCount;
249 
findMatchingDesc(const SkFontStyle & pattern) const250     CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
251         int bestMetric = SK_MaxS32;
252         CTFontDescriptorRef bestDesc = nullptr;
253 
254         for (int i = 0; i < fCount; ++i) {
255             CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), i);
256             int metric = compute_metric(pattern, SkCTFontDescriptorGetSkFontStyle(desc, false));
257             if (0 == metric) {
258                 return desc;
259             }
260             if (metric < bestMetric) {
261                 bestMetric = metric;
262                 bestDesc = desc;
263             }
264         }
265         SkASSERT(bestDesc);
266         return bestDesc;
267     }
268 };
269 
SkCopyAvailableFontFamilyNames(CTFontCollectionRef collection)270 SkUniqueCFRef<CFArrayRef> SkCopyAvailableFontFamilyNames(CTFontCollectionRef collection) {
271     // Create a CFArray of all available font descriptors.
272     SkUniqueCFRef<CFArrayRef> descriptors(
273         CTFontCollectionCreateMatchingFontDescriptors(collection));
274 
275     // Copy the font family names of the font descriptors into a CFSet.
276     auto addDescriptorFamilyNameToSet = [](const void* value, void* context) -> void {
277         CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(value);
278         CFMutableSetRef familyNameSet = static_cast<CFMutableSetRef>(context);
279         SkUniqueCFRef<CFTypeRef> familyName(
280             CTFontDescriptorCopyAttribute(descriptor, kCTFontFamilyNameAttribute));
281         if (familyName) {
282             CFSetAddValue(familyNameSet, familyName.get());
283         }
284     };
285     SkUniqueCFRef<CFMutableSetRef> familyNameSet(
286         CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks));
287     CFArrayApplyFunction(descriptors.get(), CFRangeMake(0, CFArrayGetCount(descriptors.get())),
288                          addDescriptorFamilyNameToSet, familyNameSet.get());
289 
290     // Get the set of family names into an array; this does not retain.
291     CFIndex count = CFSetGetCount(familyNameSet.get());
292     std::unique_ptr<const void*[]> familyNames(new const void*[count]);
293     CFSetGetValues(familyNameSet.get(), familyNames.get());
294 
295     // Sort the array of family names (to match CTFontManagerCopyAvailableFontFamilyNames).
296     std::sort(familyNames.get(), familyNames.get() + count, [](const void* a, const void* b){
297         return CFStringCompare((CFStringRef)a, (CFStringRef)b, 0) == kCFCompareLessThan;
298     });
299 
300     // Copy family names into a CFArray; this does retain.
301     return SkUniqueCFRef<CFArrayRef>(
302         CFArrayCreate(kCFAllocatorDefault, familyNames.get(), count, &kCFTypeArrayCallBacks));
303 }
304 
305 /** Use CTFontManagerCopyAvailableFontFamilyNames if available, simulate if not. */
SkCTFontManagerCopyAvailableFontFamilyNames()306 SkUniqueCFRef<CFArrayRef> SkCTFontManagerCopyAvailableFontFamilyNames() {
307 #ifdef SK_BUILD_FOR_IOS
308     using CTFontManagerCopyAvailableFontFamilyNamesProc = CFArrayRef (*)(void);
309     CTFontManagerCopyAvailableFontFamilyNamesProc ctFontManagerCopyAvailableFontFamilyNames;
310     *(void**)(&ctFontManagerCopyAvailableFontFamilyNames) =
311         dlsym(RTLD_DEFAULT, "CTFontManagerCopyAvailableFontFamilyNames");
312     if (ctFontManagerCopyAvailableFontFamilyNames) {
313         return SkUniqueCFRef<CFArrayRef>(ctFontManagerCopyAvailableFontFamilyNames());
314     }
315     SkUniqueCFRef<CTFontCollectionRef> collection(
316         CTFontCollectionCreateFromAvailableFonts(nullptr));
317     return SkUniqueCFRef<CFArrayRef>(SkCopyAvailableFontFamilyNames(collection.get()));
318 #else
319     return SkUniqueCFRef<CFArrayRef>(CTFontManagerCopyAvailableFontFamilyNames());
320 #endif
321 }
322 
323 } // namespace
324 
325 class SkFontMgr_Mac : public SkFontMgr {
326     SkUniqueCFRef<CFArrayRef> fNames;
327     int fCount;
328 
getFamilyNameAt(int index) const329     CFStringRef getFamilyNameAt(int index) const {
330         SkASSERT((unsigned)index < (unsigned)fCount);
331         return (CFStringRef)CFArrayGetValueAtIndex(fNames.get(), index);
332     }
333 
CreateSet(CFStringRef cfFamilyName)334     static sk_sp<SkFontStyleSet> CreateSet(CFStringRef cfFamilyName) {
335         SkUniqueCFRef<CFMutableDictionaryRef> cfAttr(
336                  CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
337                                            &kCFTypeDictionaryKeyCallBacks,
338                                            &kCFTypeDictionaryValueCallBacks));
339 
340         CFDictionaryAddValue(cfAttr.get(), kCTFontFamilyNameAttribute, cfFamilyName);
341 
342         SkUniqueCFRef<CTFontDescriptorRef> desc(
343                 CTFontDescriptorCreateWithAttributes(cfAttr.get()));
344         return sk_sp<SkFontStyleSet>(new SkFontStyleSet_Mac(desc.get()));
345     }
346 
347 public:
348     SkUniqueCFRef<CTFontCollectionRef> fFontCollection;
SkFontMgr_Mac(CTFontCollectionRef fontCollection)349     SkFontMgr_Mac(CTFontCollectionRef fontCollection)
350         : fNames(fontCollection ? SkCopyAvailableFontFamilyNames(fontCollection)
351                                 : SkCTFontManagerCopyAvailableFontFamilyNames())
352         , fCount(fNames ? SkToInt(CFArrayGetCount(fNames.get())) : 0)
353         , fFontCollection(fontCollection ? (CTFontCollectionRef)CFRetain(fontCollection)
354                                          : CTFontCollectionCreateFromAvailableFonts(nullptr))
355     {}
356 
357 protected:
onCountFamilies() const358     int onCountFamilies() const override {
359         return fCount;
360     }
361 
onGetFamilyName(int index,SkString * familyName) const362     void onGetFamilyName(int index, SkString* familyName) const override {
363         if ((unsigned)index < (unsigned)fCount) {
364             SkStringFromCFString(this->getFamilyNameAt(index), familyName);
365         } else {
366             familyName->reset();
367         }
368     }
369 
onCreateStyleSet(int index) const370     sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
371         if ((unsigned)index >= (unsigned)fCount) {
372             return nullptr;
373         }
374         return CreateSet(this->getFamilyNameAt(index));
375     }
376 
onMatchFamily(const char familyName[]) const377     sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override {
378         if (!familyName) {
379             return nullptr;
380         }
381         SkUniqueCFRef<CFStringRef> cfName = make_CFString(familyName);
382         return CreateSet(cfName.get());
383     }
384 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const385     sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
386                                    const SkFontStyle& style) const override {
387         SkUniqueCFRef<CTFontDescriptorRef> reqDesc = create_descriptor(familyName, style);
388         if (!familyName) {
389             return create_from_desc(reqDesc.get());
390         }
391         SkUniqueCFRef<CTFontDescriptorRef> resolvedDesc(
392             CTFontDescriptorCreateMatchingFontDescriptor(reqDesc.get(), name_required().get()));
393         if (!resolvedDesc) {
394             return nullptr;
395         }
396         return create_from_desc(resolvedDesc.get());
397     }
398 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const399     sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[],
400                                                   const SkFontStyle& style,
401                                                   const char* bcp47[], int bcp47Count,
402                                                   SkUnichar character) const override {
403         SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
404         SkUniqueCFRef<CTFontRef> familyFont(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
405 
406         // kCFStringEncodingUTF32 is BE unless there is a BOM.
407         // Since there is no machine endian option, explicitly state machine endian.
408 #ifdef SK_CPU_LENDIAN
409         constexpr CFStringEncoding encoding = kCFStringEncodingUTF32LE;
410 #else
411         constexpr CFStringEncoding encoding = kCFStringEncodingUTF32BE;
412 #endif
413         SkUniqueCFRef<CFStringRef> string(CFStringCreateWithBytes(
414                 kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(&character), sizeof(character),
415                 encoding, false));
416         // If 0xD800 <= codepoint <= 0xDFFF || 0x10FFFF < codepoint 'string' may be nullptr.
417         // No font should be covering such codepoints (even the magic fallback font).
418         if (!string) {
419             return nullptr;
420         }
421         CFRange range = CFRangeMake(0, CFStringGetLength(string.get()));  // in UniChar units.
422         SkUniqueCFRef<CTFontRef> fallbackFont(
423                 CTFontCreateForString(familyFont.get(), string.get(), range));
424         return SkTypeface_Mac::Make(std::move(fallbackFont), OpszVariation(), nullptr);
425     }
426 
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const427     sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
428         return this->makeFromStream(
429                 std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data))), ttcIndex);
430     }
431 
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const432     sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
433                                             int ttcIndex) const override {
434         return this->makeFromStream(std::move(stream),
435                                     SkFontArguments().setCollectionIndex(ttcIndex));
436     }
437 
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const438     sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
439                                            const SkFontArguments& args) const override {
440         return SkTypeface_Mac::MakeFromStream(std::move(stream), args);
441     }
442 
onMakeFromFile(const char path[],int ttcIndex) const443     sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
444         sk_sp<SkData> data = SkData::MakeFromFileName(path);
445         if (!data) {
446             return nullptr;
447         }
448 
449         return this->onMakeFromData(std::move(data), ttcIndex);
450     }
451 
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const452     sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
453         if (familyName) {
454             familyName = map_css_names(familyName);
455         }
456 
457         sk_sp<SkTypeface> face = create_from_name(familyName, style);
458         if (face) {
459             return face;
460         }
461 
462         static SkTypeface* gDefaultFace;
463         static SkOnce lookupDefault;
464         static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
465         lookupDefault([]{
466             gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle()).release();
467         });
468         return sk_ref_sp(gDefaultFace);
469     }
470 };
471 
SkFontMgr_New_CoreText(CTFontCollectionRef fontCollection)472 sk_sp<SkFontMgr> SkFontMgr_New_CoreText(CTFontCollectionRef fontCollection) {
473     return sk_make_sp<SkFontMgr_Mac>(fontCollection);
474 }
475 
476 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
477