xref: /aosp_15_r20/external/skia/src/ports/SkTypeface_mac_ct.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 #endif
21 
22 #include "include/core/SkColor.h"
23 #include "include/core/SkData.h"
24 #include "include/core/SkFontArguments.h"
25 #include "include/core/SkFontParameters.h"
26 #include "include/core/SkFontStyle.h"
27 #include "include/core/SkFontTypes.h"
28 #include "include/core/SkRect.h"
29 #include "include/core/SkRefCnt.h"
30 #include "include/core/SkScalar.h"
31 #include "include/core/SkStream.h"
32 #include "include/core/SkString.h"
33 #include "include/core/SkTypeface.h"
34 #include "include/ports/SkTypeface_mac.h"
35 #include "include/private/base/SkFixed.h"
36 #include "include/private/base/SkMalloc.h"
37 #include "include/private/base/SkMutex.h"
38 #include "include/private/base/SkOnce.h"
39 #include "include/private/base/SkTDArray.h"
40 #include "include/private/base/SkTPin.h"
41 #include "include/private/base/SkTemplates.h"
42 #include "include/private/base/SkTo.h"
43 #include "src/base/SkEndian.h"
44 #include "src/base/SkUTF.h"
45 #include "src/core/SkAdvancedTypefaceMetrics.h"
46 #include "src/core/SkFontDescriptor.h"
47 #include "src/core/SkMask.h"
48 #include "src/core/SkScalerContext.h"
49 #include "src/core/SkTypefaceCache.h"
50 #include "src/ports/SkScalerContext_mac_ct.h"
51 #include "src/ports/SkTypeface_mac_ct.h"
52 #include "src/sfnt/SkOTTableTypes.h"
53 #include "src/sfnt/SkOTTable_OS_2.h"
54 #include "src/sfnt/SkOTTable_OS_2_V4.h"
55 #include "src/sfnt/SkOTUtils.h"
56 #include "src/sfnt/SkSFNTHeader.h"
57 #include "src/utils/mac/SkCGBase.h"
58 #include "src/utils/mac/SkCGGeometry.h"
59 #include "src/utils/mac/SkCTFont.h"
60 #include "src/utils/mac/SkCTFontCreateExactCopy.h"
61 #include "src/utils/mac/SkUniqueCFRef.h"
62 
63 #include <dlfcn.h>
64 #include <limits.h>
65 #include <string.h>
66 #include <memory>
67 
68 using namespace skia_private;
69 
70 /** Assumes src and dst are not nullptr. */
SkStringFromCFString(CFStringRef src,SkString * dst)71 void SkStringFromCFString(CFStringRef src, SkString* dst) {
72     // Reserve enough room for the worst-case string,
73     // plus 1 byte for the trailing null.
74     CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src),
75                                                        kCFStringEncodingUTF8) + 1;
76     dst->resize(length);
77     CFStringGetCString(src, dst->data(), length, kCFStringEncodingUTF8);
78     // Resize to the actual UTF-8 length used, stripping the null character.
79     dst->resize(strlen(dst->c_str()));
80 }
81 
SkCFTypeIDDescription(CFTypeID id)82 SkString SkCFTypeIDDescription(CFTypeID id) {
83     SkUniqueCFRef<CFStringRef> typeDescription(CFCopyTypeIDDescription(id));
84     SkString skTypeDescription;
85     SkStringFromCFString(typeDescription.get(), &skTypeDescription);
86     return skTypeDescription;
87 }
88 
89 template<typename CF> CFTypeID SkCFGetTypeID();
90 #define SK_GETCFTYPEID(cf) \
91 template<> CFTypeID SkCFGetTypeID<cf##Ref>() { return cf##GetTypeID(); }
92 SK_GETCFTYPEID(CFArray);
93 SK_GETCFTYPEID(CFBoolean);
94 SK_GETCFTYPEID(CFDictionary);
95 SK_GETCFTYPEID(CFNumber);
96 
97 /* Checked dynamic downcast of CFTypeRef.
98  *
99  * @param cf the ref to downcast.
100  * @param cfAsCF if cf can be cast to the type CF, receives the downcast ref.
101  * @param name if non-nullptr the cast is expected to succeed and failures will be logged.
102  * @return true if the cast succeeds, false otherwise.
103  */
104 template <typename CF>
SkCFDynamicCast(CFTypeRef cf,CF * cfAsCF,char const * name)105 static bool SkCFDynamicCast(CFTypeRef cf, CF* cfAsCF, char const* name) {
106     //SkDEBUGF("SkCFDynamicCast '%s' of type %s to type %s\n", name ? name : "<annon>",
107     //         SkCFTypeIDDescription(  CFGetTypeID(cf)  ).c_str()
108     //         SkCFTypeIDDescription(SkCFGetTypeID<CF>()).c_str());
109     if (!cf) {
110         if (name) {
111             SkDEBUGF("%s not present\n", name);
112         }
113         return false;
114     }
115     if (CFGetTypeID(cf) != SkCFGetTypeID<CF>()) {
116         if (name) {
117             SkDEBUGF("%s is a %s but expected a %s\n", name,
118                      SkCFTypeIDDescription(  CFGetTypeID(cf)  ).c_str(),
119                      SkCFTypeIDDescription(SkCFGetTypeID<CF>()).c_str());
120         }
121         return false;
122     }
123     *cfAsCF = static_cast<CF>(cf);
124     return true;
125 }
126 
127 template<typename T> struct SkCFNumberTypeFor {};
128 #define SK_CFNUMBERTYPE_FOR(c, cf) \
129 template<> struct SkCFNumberTypeFor<c> : std::integral_constant<CFNumberType, cf> {};
130 SK_CFNUMBERTYPE_FOR(char     , kCFNumberCharType    );
131 SK_CFNUMBERTYPE_FOR(short    , kCFNumberShortType   );
132 SK_CFNUMBERTYPE_FOR(int      , kCFNumberIntType     );
133 SK_CFNUMBERTYPE_FOR(long     , kCFNumberLongType    );
134 SK_CFNUMBERTYPE_FOR(long long, kCFNumberLongLongType);
135 SK_CFNUMBERTYPE_FOR(float    , kCFNumberFloatType   );
136 SK_CFNUMBERTYPE_FOR(double   , kCFNumberDoubleType  );
137 
138 template <typename T>
SkCFNumberDynamicCast(CFTypeRef cf,T * number,CFNumberRef * cfNumber,char const * name)139 static bool SkCFNumberDynamicCast(CFTypeRef cf, T* number, CFNumberRef* cfNumber, char const* name){
140     CFNumberRef cfAsCFNumber;
141     if (!SkCFDynamicCast(cf, &cfAsCFNumber, name)) {
142         return false;
143     }
144     if (!CFNumberGetValue(cfAsCFNumber, SkCFNumberTypeFor<T>::value, number)) {
145         if (name) {
146             SkDEBUGF("%s CFNumber not extractable\n", name);
147         }
148         return false;
149     }
150     if (cfNumber) {
151         *cfNumber = cfAsCFNumber;
152     }
153     return true;
154 }
155 
SkTypeface_GetCTFontRef(const SkTypeface * face)156 CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) {
157     return face ? (CTFontRef)face->internal_private_getCTFontRef() : nullptr;
158 }
159 
find_by_CTFontRef(SkTypeface * cached,void * context)160 static bool find_by_CTFontRef(SkTypeface* cached, void* context) {
161     CTFontRef self = (CTFontRef)context;
162     CTFontRef other = (CTFontRef)cached->internal_private_getCTFontRef();
163 
164     return CFEqual(self, other);
165 }
166 
167 /** Creates a typeface, searching the cache if providedData is nullptr. */
Make(SkUniqueCFRef<CTFontRef> font,OpszVariation opszVariation,std::unique_ptr<SkStreamAsset> providedData)168 sk_sp<SkTypeface> SkTypeface_Mac::Make(SkUniqueCFRef<CTFontRef> font,
169                                        OpszVariation opszVariation,
170                                        std::unique_ptr<SkStreamAsset> providedData) {
171     static SkMutex gTFCacheMutex;
172     static SkTypefaceCache gTFCache;
173 
174     SkASSERT(font);
175     const bool isFromStream(providedData);
176 
177     auto makeTypeface = [&]() {
178         SkUniqueCFRef<CTFontDescriptorRef> desc(CTFontCopyFontDescriptor(font.get()));
179         SkFontStyle style = SkCTFontDescriptorGetSkFontStyle(desc.get(), isFromStream);
180         CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font.get());
181         bool isFixedPitch = SkToBool(traits & kCTFontMonoSpaceTrait);
182 
183         return sk_sp<SkTypeface>(new SkTypeface_Mac(std::move(font), style, isFixedPitch,
184                                                     opszVariation, std::move(providedData)));
185     };
186 
187     if (isFromStream) {
188         return makeTypeface();
189     }
190 
191     SkAutoMutexExclusive ama(gTFCacheMutex);
192     sk_sp<SkTypeface> face = gTFCache.findByProcAndRef(find_by_CTFontRef, (void*)font.get());
193     if (!face) {
194         face = makeTypeface();
195         if (face) {
196             gTFCache.add(face);
197         }
198     }
199     return face;
200 }
201 
202 /*  This function is visible on the outside. It first searches the cache, and if
203  *  not found, returns a new entry (after adding it to the cache).
204  */
SkMakeTypefaceFromCTFont(CTFontRef font)205 sk_sp<SkTypeface> SkMakeTypefaceFromCTFont(CTFontRef font) {
206     CFRetain(font);
207     return SkTypeface_Mac::Make(SkUniqueCFRef<CTFontRef>(font),
208                                 OpszVariation(),
209                                 nullptr);
210 }
211 
find_dict_CGFloat(CFDictionaryRef dict,CFStringRef name,CGFloat * value)212 static bool find_dict_CGFloat(CFDictionaryRef dict, CFStringRef name, CGFloat* value) {
213     CFNumberRef num;
214     return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num)
215         && CFNumberIsFloatType(num)
216         && CFNumberGetValue(num, kCFNumberCGFloatType, value);
217 }
218 
219 template <typename S, typename D, typename C> struct LinearInterpolater {
220     struct Mapping {
221         S src_val;
222         D dst_val;
223     };
LinearInterpolaterLinearInterpolater224     constexpr LinearInterpolater(Mapping const mapping[], int mappingCount)
225         : fMapping(mapping), fMappingCount(mappingCount) {}
226 
mapLinearInterpolater227     static D map(S value, S src_min, S src_max, D dst_min, D dst_max) {
228         SkASSERT(src_min < src_max);
229         SkASSERT(dst_min <= dst_max);
230         return C()(dst_min + (((value - src_min) * (dst_max - dst_min)) / (src_max - src_min)));
231     }
232 
mapLinearInterpolater233     D map(S val) const {
234         // -Inf to [0]
235         if (val < fMapping[0].src_val) {
236             return fMapping[0].dst_val;
237         }
238 
239         // Linear from [i] to [i+1]
240         for (int i = 0; i < fMappingCount - 1; ++i) {
241             if (val < fMapping[i+1].src_val) {
242                 return map(val, fMapping[i].src_val, fMapping[i+1].src_val,
243                                 fMapping[i].dst_val, fMapping[i+1].dst_val);
244             }
245         }
246 
247         // From [n] to +Inf
248         // if (fcweight < Inf)
249         return fMapping[fMappingCount - 1].dst_val;
250     }
251 
252     Mapping const * fMapping;
253     int fMappingCount;
254 };
255 
256 struct RoundCGFloatToInt {
operator ()RoundCGFloatToInt257     int operator()(CGFloat s) { return s + 0.5; }
258 };
259 struct CGFloatIdentity {
operator ()CGFloatIdentity260     CGFloat operator()(CGFloat s) { return s; }
261 };
262 
263 /** Convert the [0, 1000] CSS weight to [-1, 1] CTFontDescriptor weight (for system fonts).
264  *
265  *  The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the
266  *  CTFont is native or created from a CGDataProvider.
267  */
SkCTFontCTWeightForCSSWeight(int fontstyleWeight)268 CGFloat SkCTFontCTWeightForCSSWeight(int fontstyleWeight) {
269     using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>;
270 
271     // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100.
272     // However, on this end we can't tell, so this is ignored.
273 
274     static Interpolator::Mapping nativeWeightMappings[11];
275     static SkOnce once;
276     once([&] {
277         const CGFloat(&nsFontWeights)[11] = SkCTFontGetNSFontWeightMapping();
278         for (int i = 0; i < 11; ++i) {
279             nativeWeightMappings[i].src_val = i * 100;
280             nativeWeightMappings[i].dst_val = nsFontWeights[i];
281         }
282     });
283     static constexpr Interpolator nativeInterpolator(
284             nativeWeightMappings, std::size(nativeWeightMappings));
285 
286     return nativeInterpolator.map(fontstyleWeight);
287 }
288 
289 /** Convert the [-1, 1] CTFontDescriptor weight to [0, 1000] CSS weight.
290  *
291  *  The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the
292  *  CTFont is native or created from a CGDataProvider.
293  */
ct_weight_to_fontstyle(CGFloat cgWeight,bool fromDataProvider)294 static int ct_weight_to_fontstyle(CGFloat cgWeight, bool fromDataProvider) {
295     using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>;
296 
297     // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100.
298     // However, on this end we can't tell, so this is ignored.
299 
300     static Interpolator::Mapping nativeWeightMappings[11];
301     static Interpolator::Mapping dataProviderWeightMappings[11];
302     static SkOnce once;
303     once([&] {
304         const CGFloat(&nsFontWeights)[11] = SkCTFontGetNSFontWeightMapping();
305         const CGFloat(&userFontWeights)[11] = SkCTFontGetDataFontWeightMapping();
306         for (int i = 0; i < 11; ++i) {
307             nativeWeightMappings[i].src_val = nsFontWeights[i];
308             nativeWeightMappings[i].dst_val = i * 100;
309 
310             dataProviderWeightMappings[i].src_val = userFontWeights[i];
311             dataProviderWeightMappings[i].dst_val = i * 100;
312         }
313     });
314     static constexpr Interpolator nativeInterpolator(
315             nativeWeightMappings, std::size(nativeWeightMappings));
316     static constexpr Interpolator dataProviderInterpolator(
317             dataProviderWeightMappings, std::size(dataProviderWeightMappings));
318 
319     return fromDataProvider ? dataProviderInterpolator.map(cgWeight)
320                             : nativeInterpolator.map(cgWeight);
321 }
322 
323 /** Convert the [0, 10] CSS weight to [-1, 1] CTFontDescriptor width. */
SkCTFontCTWidthForCSSWidth(int fontstyleWidth)324 CGFloat SkCTFontCTWidthForCSSWidth(int fontstyleWidth) {
325     using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>;
326 
327     // Values determined by creating font data with every width, creating a CTFont,
328     // and asking the CTFont for its width. See TypefaceStyle test for basics.
329     static constexpr Interpolator::Mapping widthMappings[] = {
330         {  0, -0.5 },
331         { 10,  0.5 },
332     };
333     static constexpr Interpolator interpolator(widthMappings, std::size(widthMappings));
334     return interpolator.map(fontstyleWidth);
335 }
336 
337 /** Convert the [-1, 1] CTFontDescriptor width to [0, 10] CSS weight. */
ct_width_to_fontstyle(CGFloat cgWidth)338 static int ct_width_to_fontstyle(CGFloat cgWidth) {
339     using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>;
340 
341     // Values determined by creating font data with every width, creating a CTFont,
342     // and asking the CTFont for its width. See TypefaceStyle test for basics.
343     static constexpr Interpolator::Mapping widthMappings[] = {
344         { -0.5,  0 },
345         {  0.5, 10 },
346     };
347     static constexpr Interpolator interpolator(widthMappings, std::size(widthMappings));
348     return interpolator.map(cgWidth);
349 }
350 
SkCTFontDescriptorGetSkFontStyle(CTFontDescriptorRef desc,bool fromDataProvider)351 SkFontStyle SkCTFontDescriptorGetSkFontStyle(CTFontDescriptorRef desc, bool fromDataProvider) {
352     SkUniqueCFRef<CFTypeRef> traits(CTFontDescriptorCopyAttribute(desc, kCTFontTraitsAttribute));
353     CFDictionaryRef fontTraitsDict;
354     if (!SkCFDynamicCast(traits.get(), &fontTraitsDict, "Font traits")) {
355         return SkFontStyle();
356     }
357 
358     CGFloat weight, width, slant;
359     if (!find_dict_CGFloat(fontTraitsDict, kCTFontWeightTrait, &weight)) {
360         weight = 0;
361     }
362     if (!find_dict_CGFloat(fontTraitsDict, kCTFontWidthTrait, &width)) {
363         width = 0;
364     }
365     if (!find_dict_CGFloat(fontTraitsDict, kCTFontSlantTrait, &slant)) {
366         slant = 0;
367     }
368 
369     return SkFontStyle(ct_weight_to_fontstyle(weight, fromDataProvider),
370                        ct_width_to_fontstyle(width),
371                        slant ? SkFontStyle::kItalic_Slant
372                              : SkFontStyle::kUpright_Slant);
373 }
374 
375 
376 // Web fonts added to the CTFont registry do not return their character set.
377 // Iterate through the font in this case. The existing caller caches the result,
378 // so the performance impact isn't too bad.
populate_glyph_to_unicode_slow(CTFontRef ctFont,CFIndex glyphCount,SkUnichar * out)379 static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
380                                            SkUnichar* out) {
381     sk_bzero(out, glyphCount * sizeof(SkUnichar));
382     UniChar unichar = 0;
383     while (glyphCount > 0) {
384         CGGlyph glyph;
385         if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
386             if (out[glyph] == 0) {
387                 out[glyph] = unichar;
388                 --glyphCount;
389             }
390         }
391         if (++unichar == 0) {
392             break;
393         }
394     }
395 }
396 
397 static constexpr uint16_t kPlaneSize = 1 << 13;
398 
get_plane_glyph_map(const uint8_t * bits,CTFontRef ctFont,CFIndex glyphCount,SkUnichar * glyphToUnicode,uint8_t planeIndex)399 static void get_plane_glyph_map(const uint8_t* bits,
400                                 CTFontRef ctFont,
401                                 CFIndex glyphCount,
402                                 SkUnichar* glyphToUnicode,
403                                 uint8_t planeIndex) {
404     SkUnichar planeOrigin = (SkUnichar)planeIndex << 16; // top half of codepoint.
405     for (uint16_t i = 0; i < kPlaneSize; i++) {
406         uint8_t mask = bits[i];
407         if (!mask) {
408             continue;
409         }
410         for (uint8_t j = 0; j < 8; j++) {
411             if (0 == (mask & ((uint8_t)1 << j))) {
412                 continue;
413             }
414             uint16_t planeOffset = (i << 3) | j;
415             SkUnichar codepoint = planeOrigin | (SkUnichar)planeOffset;
416             uint16_t utf16[2] = {planeOffset, 0};
417             size_t count = 1;
418             if (planeOrigin != 0) {
419                 count = SkUTF::ToUTF16(codepoint, utf16);
420             }
421             CGGlyph glyphs[2] = {0, 0};
422             if (CTFontGetGlyphsForCharacters(ctFont, utf16, glyphs, count)) {
423                 SkASSERT(glyphs[1] == 0);
424                 SkASSERT(glyphs[0] < glyphCount);
425                 // CTFontCopyCharacterSet and CTFontGetGlyphsForCharacters seem to add 'support'
426                 // for characters 0x9, 0xA, and 0xD mapping them to the glyph for character 0x20?
427                 // Prefer mappings to codepoints at or above 0x20.
428                 if (glyphToUnicode[glyphs[0]] < 0x20) {
429                     glyphToUnicode[glyphs[0]] = codepoint;
430                 }
431             }
432         }
433     }
434 }
435 // Construct Glyph to Unicode table.
populate_glyph_to_unicode(CTFontRef ctFont,CFIndex glyphCount,SkUnichar * glyphToUnicode)436 static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
437                                       SkUnichar* glyphToUnicode) {
438     sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount);
439     SkUniqueCFRef<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
440     if (!charSet) {
441         populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
442         return;
443     }
444 
445     SkUniqueCFRef<CFDataRef> bitmap(
446             CFCharacterSetCreateBitmapRepresentation(nullptr, charSet.get()));
447     if (!bitmap) {
448         return;
449     }
450     CFIndex dataLength = CFDataGetLength(bitmap.get());
451     if (!dataLength) {
452         return;
453     }
454     SkASSERT(dataLength >= kPlaneSize);
455     const UInt8* bits = CFDataGetBytePtr(bitmap.get());
456 
457     get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, 0);
458     /*
459     A CFData object that specifies the bitmap representation of the Unicode
460     character points the for the new character set. The bitmap representation could
461     contain all the Unicode character range starting from BMP to Plane 16. The
462     first 8KiB (8192 bytes) of the data represent the BMP range. The BMP range 8KiB
463     can be followed by zero to sixteen 8KiB bitmaps, each prepended with the plane
464     index byte. For example, the bitmap representing the BMP and Plane 2 has the
465     size of 16385 bytes (8KiB for BMP, 1 byte index, and a 8KiB bitmap for Plane
466     2). The plane index byte, in this case, contains the integer value two.
467     */
468 
469     if (dataLength <= kPlaneSize) {
470         return;
471     }
472     int extraPlaneCount = (dataLength - kPlaneSize) / (1 + kPlaneSize);
473     SkASSERT(dataLength == kPlaneSize + extraPlaneCount * (1 + kPlaneSize));
474     while (extraPlaneCount-- > 0) {
475         bits += kPlaneSize;
476         uint8_t planeIndex = *bits++;
477         SkASSERT(planeIndex >= 1);
478         SkASSERT(planeIndex <= 16);
479         get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, planeIndex);
480     }
481 }
482 
getGlyphToUnicodeMap(SkUnichar * dstArray) const483 void SkTypeface_Mac::getGlyphToUnicodeMap(SkUnichar* dstArray) const {
484     SkUniqueCFRef<CTFontRef> ctFont =
485             SkCTFontCreateExactCopy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()),
486                                     fOpszVariation);
487     CFIndex glyphCount = CTFontGetGlyphCount(ctFont.get());
488     populate_glyph_to_unicode(ctFont.get(), glyphCount, dstArray);
489 }
490 
onGetAdvancedMetrics() const491 std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_Mac::onGetAdvancedMetrics() const {
492 
493     SkUniqueCFRef<CTFontRef> ctFont =
494             SkCTFontCreateExactCopy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()),
495                                     fOpszVariation);
496 
497     std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics);
498 
499     {
500         SkUniqueCFRef<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont.get()));
501         if (fontName.get()) {
502             SkStringFromCFString(fontName.get(), &info->fPostScriptName);
503         }
504     }
505 
506     CFArrayRef ctAxes = this->getVariationAxes();
507     if (ctAxes && CFArrayGetCount(ctAxes) > 0) {
508         info->fFlags |= SkAdvancedTypefaceMetrics::kVariable_FontFlag;
509     }
510 
511     SkOTTableOS2_V4::Type fsType;
512     if (sizeof(fsType) == this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG),
513                                              offsetof(SkOTTableOS2_V4, fsType),
514                                              sizeof(fsType),
515                                              &fsType)) {
516         SkOTUtils::SetAdvancedTypefaceFlags(fsType, info.get());
517     }
518 
519     // If it's not an OpenType font, mark it as 'other'. Assume that OpenType
520     // fonts always have both glyf and loca tables or a CFF table.
521     // At the least, this is what is needed to subset the font.
522     // CTFontCopyAttribute() does not always succeed in determining this directly.
523     constexpr SkFontTableTag glyf = SkSetFourByteTag('g','l','y','f');
524     constexpr SkFontTableTag loca = SkSetFourByteTag('l','o','c','a');
525     constexpr SkFontTableTag CFF  = SkSetFourByteTag('C','F','F',' ');
526     if (this->getTableSize(glyf) && this->getTableSize(loca)) {
527         info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
528     } else if (this->getTableSize(CFF)) {
529         info->fType = SkAdvancedTypefaceMetrics::kCFF_Font;
530     } else {
531         return info;
532     }
533 
534     CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get());
535     if (symbolicTraits & kCTFontMonoSpaceTrait) {
536         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
537     }
538     if (symbolicTraits & kCTFontItalicTrait) {
539         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
540     }
541     CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
542     if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
543         info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
544     } else if (stylisticClass & kCTFontScriptsClass) {
545         info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
546     }
547     info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont.get());
548     info->fAscent = (int16_t) CTFontGetAscent(ctFont.get());
549     info->fDescent = (int16_t) CTFontGetDescent(ctFont.get());
550     info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont.get());
551     CGRect bbox = CTFontGetBoundingBox(ctFont.get());
552 
553     SkRect r;
554     r.setLTRB(SkScalarFromCGFloat(SkCGRectGetMinX(bbox)),   // Left
555               SkScalarFromCGFloat(SkCGRectGetMaxY(bbox)),   // Top
556               SkScalarFromCGFloat(SkCGRectGetMaxX(bbox)),   // Right
557               SkScalarFromCGFloat(SkCGRectGetMinY(bbox)));  // Bottom
558 
559     r.roundOut(&(info->fBBox));
560 
561     // Figure out a good guess for StemV - Min width of i, I, !, 1.
562     // This probably isn't very good with an italic font.
563     int16_t min_width = SHRT_MAX;
564     info->fStemV = 0;
565     static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
566     const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
567     CGGlyph glyphs[count];
568     CGRect boundingRects[count];
569     if (CTFontGetGlyphsForCharacters(ctFont.get(), stem_chars, glyphs, count)) {
570         CTFontGetBoundingRectsForGlyphs(ctFont.get(), kCTFontOrientationHorizontal,
571                                         glyphs, boundingRects, count);
572         for (size_t i = 0; i < count; i++) {
573             int16_t width = (int16_t) boundingRects[i].size.width;
574             if (width > 0 && width < min_width) {
575                 min_width = width;
576                 info->fStemV = min_width;
577             }
578         }
579     }
580     return info;
581 }
582 
get_font_type_tag(CTFontRef ctFont)583 static SK_SFNT_ULONG get_font_type_tag(CTFontRef ctFont) {
584     SkUniqueCFRef<CFNumberRef> fontFormatRef(
585             static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
586     if (!fontFormatRef) {
587         return 0;
588     }
589 
590     SInt32 fontFormatValue;
591     if (!CFNumberGetValue(fontFormatRef.get(), kCFNumberSInt32Type, &fontFormatValue)) {
592         return 0;
593     }
594 
595     switch (fontFormatValue) {
596         case kCTFontFormatOpenTypePostScript:
597             return SkSFNTHeader::fontType_OpenTypeCFF::TAG;
598         case kCTFontFormatOpenTypeTrueType:
599             return SkSFNTHeader::fontType_WindowsTrueType::TAG;
600         case kCTFontFormatTrueType:
601             return SkSFNTHeader::fontType_MacTrueType::TAG;
602         case kCTFontFormatPostScript:
603             return SkSFNTHeader::fontType_PostScript::TAG;
604         case kCTFontFormatBitmap:
605             return SkSFNTHeader::fontType_MacTrueType::TAG;
606         case kCTFontFormatUnrecognized:
607         default:
608             return 0;
609     }
610 }
611 
onOpenStream(int * ttcIndex) const612 std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
613     *ttcIndex = 0;
614 
615     fInitStream([this]{
616     if (fStream) {
617         return;
618     }
619 
620     SK_SFNT_ULONG fontType = get_font_type_tag(fFontRef.get());
621 
622     // get table tags
623     int numTables = this->countTables();
624     SkTDArray<SkFontTableTag> tableTags;
625     tableTags.resize(numTables);
626     this->getTableTags(tableTags.begin());
627 
628     // CT seems to be unreliable in being able to obtain the type,
629     // even if all we want is the first four bytes of the font resource.
630     // Just the presence of the FontForge 'FFTM' table seems to throw it off.
631     if (fontType == 0) {
632         fontType = SkSFNTHeader::fontType_WindowsTrueType::TAG;
633 
634         // see https://skbug.com/7630#c7
635         bool couldBeCFF = false;
636         constexpr SkFontTableTag CFFTag = SkSetFourByteTag('C', 'F', 'F', ' ');
637         constexpr SkFontTableTag CFF2Tag = SkSetFourByteTag('C', 'F', 'F', '2');
638         for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
639             if (CFFTag == tableTags[tableIndex] || CFF2Tag == tableTags[tableIndex]) {
640                 couldBeCFF = true;
641             }
642         }
643         if (couldBeCFF) {
644             fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG;
645         }
646     }
647 
648     // Sometimes CoreGraphics incorrectly thinks a font is kCTFontFormatPostScript.
649     // It is exceedingly unlikely that this is the case, so double check
650     // (see https://crbug.com/809763 ).
651     if (fontType == SkSFNTHeader::fontType_PostScript::TAG) {
652         // see if there are any required 'typ1' tables (see Adobe Technical Note #5180)
653         bool couldBeTyp1 = false;
654         constexpr SkFontTableTag TYPE1Tag = SkSetFourByteTag('T', 'Y', 'P', '1');
655         constexpr SkFontTableTag CIDTag = SkSetFourByteTag('C', 'I', 'D', ' ');
656         for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
657             if (TYPE1Tag == tableTags[tableIndex] || CIDTag == tableTags[tableIndex]) {
658                 couldBeTyp1 = true;
659             }
660         }
661         if (!couldBeTyp1) {
662             fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG;
663         }
664     }
665 
666     // get the table sizes and accumulate the total size of the font
667     SkTDArray<size_t> tableSizes;
668     size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
669     for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
670         size_t tableSize = this->getTableSize(tableTags[tableIndex]);
671         totalSize += (tableSize + 3) & ~3;
672         *tableSizes.append() = tableSize;
673     }
674 
675     // reserve memory for stream, and zero it (tables must be zero padded)
676     sk_sp<SkData> streamData = SkData::MakeZeroInitialized(totalSize);
677     char* dataStart = (char*)streamData->writable_data();
678     char* dataPtr = dataStart;
679 
680     // compute font header entries
681     uint16_t entrySelector = 0;
682     uint16_t searchRange = 1;
683     while (searchRange < numTables >> 1) {
684         entrySelector++;
685         searchRange <<= 1;
686     }
687     searchRange <<= 4;
688     uint16_t rangeShift = (numTables << 4) - searchRange;
689 
690     // write font header
691     SkSFNTHeader* header = (SkSFNTHeader*)dataPtr;
692     header->fontType = fontType;
693     header->numTables = SkEndian_SwapBE16(numTables);
694     header->searchRange = SkEndian_SwapBE16(searchRange);
695     header->entrySelector = SkEndian_SwapBE16(entrySelector);
696     header->rangeShift = SkEndian_SwapBE16(rangeShift);
697     dataPtr += sizeof(SkSFNTHeader);
698 
699     // write tables
700     SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr;
701     dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
702     for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
703         size_t tableSize = tableSizes[tableIndex];
704         this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
705         entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]);
706         entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr,
707                                                                          tableSize));
708         entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart));
709         entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize));
710 
711         dataPtr += (tableSize + 3) & ~3;
712         ++entry;
713     }
714     fStream = std::make_unique<SkMemoryStream>(std::move(streamData));
715     });
716     return fStream->duplicate();
717 }
718 
onOpenExistingStream(int * ttcIndex) const719 std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenExistingStream(int* ttcIndex) const {
720     *ttcIndex = 0;
721     return fStream ? fStream->duplicate() : nullptr;
722 }
723 
onGlyphMaskNeedsCurrentColor() const724 bool SkTypeface_Mac::onGlyphMaskNeedsCurrentColor() const {
725     // `CPAL` (`COLR` and `SVG`) fonts may need the current color.
726     // However, even `sbix` fonts can have glyphs which need the current color.
727     // These may be glyphs with paths but no `sbix` entries, which are impossible to distinguish.
728     return this->fHasColorGlyphs;
729 }
730 
getVariationAxes() const731 CFArrayRef SkTypeface_Mac::getVariationAxes() const {
732     fInitVariationAxes([this]{
733         // Prefer kCTFontVariationAxesAttribute, faster since it doesn't localize axis names.
734         SkUniqueCFRef<CTFontDescriptorRef> desc(CTFontCopyFontDescriptor(fFontRef.get()));
735         SkUniqueCFRef<CFTypeRef> cf(
736                 CTFontDescriptorCopyAttribute(desc.get(), kCTFontVariationAxesAttribute));
737         CFArrayRef array;
738         if (cf && SkCFDynamicCast(cf.get(), &array, "Axes")) {
739             fVariationAxes.reset(array);
740             cf.release();
741             return;
742         }
743         fVariationAxes.reset(CTFontCopyVariationAxes(fFontRef.get()));
744     });
745     return fVariationAxes.get();
746 }
747 
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount) const748 int SkTypeface_Mac::onGetVariationDesignPosition(
749         SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
750 {
751     CFArrayRef ctAxes = this->getVariationAxes();
752     if (!ctAxes) {
753         return -1;
754     }
755     CFIndex axisCount = CFArrayGetCount(ctAxes);
756     if (!coordinates || coordinateCount < axisCount) {
757         return axisCount;
758     }
759 
760     // On 10.12 and later, this only returns non-default variations.
761     SkUniqueCFRef<CFDictionaryRef> ctVariation(CTFontCopyVariation(fFontRef.get()));
762     if (!ctVariation) {
763         return -1;
764     }
765 
766     for (int i = 0; i < axisCount; ++i) {
767         CFDictionaryRef axisInfoDict;
768         if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict, "Axis")) {
769             return -1;
770         }
771 
772         int64_t tagLong;
773         CFNumberRef tagNumber;
774         CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
775         if (!SkCFNumberDynamicCast(tag, &tagLong, &tagNumber, "Axis tag")) {
776             return -1;
777         }
778         coordinates[i].axis = tagLong;
779 
780         CGFloat valueCGFloat;
781         CFTypeRef value = CFDictionaryGetValue(ctVariation.get(), tagNumber);
782         if (value) {
783             if (!SkCFNumberDynamicCast(value, &valueCGFloat, nullptr, "Variation value")) {
784                 return -1;
785             }
786         } else {
787             CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
788             if (!SkCFNumberDynamicCast(def, &valueCGFloat, nullptr, "Axis default value")) {
789                 return -1;
790             }
791         }
792         coordinates[i].value = SkScalarFromCGFloat(valueCGFloat);
793     }
794     return axisCount;
795 }
796 
onGetUPEM() const797 int SkTypeface_Mac::onGetUPEM() const {
798     SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr));
799     return CGFontGetUnitsPerEm(cgFont.get());
800 }
801 
onCreateFamilyNameIterator() const802 SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const {
803     sk_sp<SkTypeface::LocalizedStrings> nameIter =
804             SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this);
805     if (!nameIter) {
806         CFStringRef cfLanguageRaw;
807         SkUniqueCFRef<CFStringRef> cfFamilyName(
808                 CTFontCopyLocalizedName(fFontRef.get(), kCTFontFamilyNameKey, &cfLanguageRaw));
809         SkUniqueCFRef<CFStringRef> cfLanguage(cfLanguageRaw);
810 
811         SkString skLanguage;
812         SkString skFamilyName;
813         if (cfLanguage) {
814             SkStringFromCFString(cfLanguage.get(), &skLanguage);
815         } else {
816             skLanguage = "und"; //undetermined
817         }
818         if (cfFamilyName) {
819             SkStringFromCFString(cfFamilyName.get(), &skFamilyName);
820         }
821 
822         nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(skFamilyName, skLanguage);
823     }
824     return nameIter.release();
825 }
826 
onGetTableTags(SkFontTableTag tags[]) const827 int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
828     SkUniqueCFRef<CFArrayRef> cfArray(
829             CTFontCopyAvailableTables(fFontRef.get(), kCTFontTableOptionNoOptions));
830     if (!cfArray) {
831         return 0;
832     }
833     CFIndex count = CFArrayGetCount(cfArray.get());
834     if (tags) {
835         for (CFIndex i = 0; i < count; ++i) {
836             uintptr_t fontTag = reinterpret_cast<uintptr_t>(
837                 CFArrayGetValueAtIndex(cfArray.get(), i));
838             tags[i] = static_cast<SkFontTableTag>(fontTag);
839         }
840     }
841     return count;
842 }
843 
844 // If, as is the case with web fonts, the CTFont data isn't available,
845 // the CGFont data may work. While the CGFont may always provide the
846 // right result, leave the CTFont code path to minimize disruption.
copy_table_from_font(CTFontRef ctFont,SkFontTableTag tag)847 static SkUniqueCFRef<CFDataRef> copy_table_from_font(CTFontRef ctFont, SkFontTableTag tag) {
848     SkUniqueCFRef<CFDataRef> data(CTFontCopyTable(ctFont, (CTFontTableTag) tag,
849                                                   kCTFontTableOptionNoOptions));
850     if (!data) {
851         SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr));
852         data.reset(CGFontCopyTableForTag(cgFont.get(), tag));
853     }
854     return data;
855 }
856 
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * dstData) const857 size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset,
858                                       size_t length, void* dstData) const {
859     SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
860     if (!srcData) {
861         return 0;
862     }
863 
864     size_t srcSize = CFDataGetLength(srcData.get());
865     if (offset >= srcSize) {
866         return 0;
867     }
868     if (length > srcSize - offset) {
869         length = srcSize - offset;
870     }
871     if (dstData) {
872         memcpy(dstData, CFDataGetBytePtr(srcData.get()) + offset, length);
873     }
874     return length;
875 }
876 
onCopyTableData(SkFontTableTag tag) const877 sk_sp<SkData> SkTypeface_Mac::onCopyTableData(SkFontTableTag tag) const {
878     SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
879     if (!srcData) {
880         return nullptr;
881     }
882     const UInt8* data = CFDataGetBytePtr(srcData.get());
883     CFIndex length = CFDataGetLength(srcData.get());
884     return SkData::MakeWithProc(data, length,
885                                 [](const void*, void* ctx) {
886                                     CFRelease((CFDataRef)ctx);
887                                 }, (void*)srcData.release());
888 }
889 
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const890 std::unique_ptr<SkScalerContext> SkTypeface_Mac::onCreateScalerContext(
891     const SkScalerContextEffects& effects, const SkDescriptor* desc) const
892 {
893     return std::make_unique<SkScalerContext_Mac>(
894             sk_ref_sp(const_cast<SkTypeface_Mac*>(this)), effects, desc);
895 }
896 
onFilterRec(SkScalerContextRec * rec) const897 void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
898     rec->useStrokeForFakeBold();
899 
900     if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
901         rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
902     {
903         rec->fMaskFormat = SkMask::kA8_Format;
904         // Render the glyphs as close as possible to what was requested.
905         // The above turns off subpixel rendering, but the user requested it.
906         // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks.
907         // See comments below for more details.
908         rec->setHinting(SkFontHinting::kNormal);
909     }
910 
911     unsigned flagsWeDontSupport = SkScalerContext::kForceAutohinting_Flag  |
912                                   SkScalerContext::kLCD_BGROrder_Flag |
913                                   SkScalerContext::kLCD_Vertical_Flag;
914 
915     rec->fFlags &= ~flagsWeDontSupport;
916 
917     const SkCTFontSmoothBehavior smoothBehavior = SkCTFontGetSmoothBehavior();
918 
919     // Only two levels of hinting are supported.
920     // kNo_Hinting means avoid CoreGraphics outline dilation (smoothing).
921     // kNormal_Hinting means CoreGraphics outline dilation (smoothing) is allowed.
922     if (rec->getHinting() != SkFontHinting::kNone) {
923         rec->setHinting(SkFontHinting::kNormal);
924     }
925     // If smoothing has no effect, don't request it.
926     if (smoothBehavior == SkCTFontSmoothBehavior::none) {
927         rec->setHinting(SkFontHinting::kNone);
928     }
929 
930     // FIXME: lcd smoothed un-hinted rasterization unsupported.
931     // Tracked by http://code.google.com/p/skia/issues/detail?id=915 .
932     // There is no current means to honor a request for unhinted lcd,
933     // so arbitrarilly ignore the hinting request and honor lcd.
934 
935     // Hinting and smoothing should be orthogonal, but currently they are not.
936     // CoreGraphics has no API to influence hinting. However, its lcd smoothed
937     // output is drawn from auto-dilated outlines (the amount of which is
938     // determined by AppleFontSmoothing). Its regular anti-aliased output is
939     // drawn from un-dilated outlines.
940 
941     // The behavior of Skia is as follows:
942     // [AA][no-hint]: generate AA using CoreGraphic's AA output.
943     // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single
944     // channel. This matches [LCD][yes-hint] in weight.
945     // [LCD][no-hint]: currently unable to honor, and must pick which to respect.
946     // Currently side with LCD, effectively ignoring the hinting setting.
947     // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output.
948     if (rec->fMaskFormat == SkMask::kLCD16_Format) {
949         if (smoothBehavior == SkCTFontSmoothBehavior::subpixel) {
950             //CoreGraphics creates 555 masks for smoothed text anyway.
951             rec->fMaskFormat = SkMask::kLCD16_Format;
952             rec->setHinting(SkFontHinting::kNormal);
953         } else {
954             rec->fMaskFormat = SkMask::kA8_Format;
955             if (smoothBehavior != SkCTFontSmoothBehavior::none) {
956                 rec->setHinting(SkFontHinting::kNormal);
957             }
958         }
959     }
960 
961     // CoreText provides no information as to whether a glyph will be color or not.
962     // Fonts may mix outlines and bitmaps, so information is needed on a glyph by glyph basis.
963     // If a font contains an 'sbix' table, consider it to be a color font, and disable lcd.
964     if (fHasColorGlyphs) {
965         rec->fMaskFormat = SkMask::kARGB32_Format;
966     }
967 
968     // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
969     // All other masks can use regular gamma.
970     if (SkMask::kA8_Format == rec->fMaskFormat && SkFontHinting::kNone == rec->getHinting()) {
971 #ifndef SK_GAMMA_APPLY_TO_A8
972         // SRGBTODO: Is this correct? Do we want contrast boost?
973         rec->ignorePreBlend();
974 #endif
975     } else {
976         SkColor color = rec->getLuminanceColor();
977         if (smoothBehavior == SkCTFontSmoothBehavior::some) {
978             // CoreGraphics smoothed text without subpixel coverage blitting goes from a gamma of
979             // 2.0 for black foreground to a gamma of 1.0 for white foreground. Emulate this
980             // through the mask gamma by reducing the color values to 1/2.
981             color = SkColorSetRGB(SkColorGetR(color) * 1/2,
982                                   SkColorGetG(color) * 1/2,
983                                   SkColorGetB(color) * 1/2);
984         } else if (smoothBehavior == SkCTFontSmoothBehavior::subpixel) {
985             // CoreGraphics smoothed text with subpixel coverage blitting goes from a gamma of
986             // 2.0 for black foreground to a gamma of ~1.4? for white foreground. Emulate this
987             // through the mask gamma by reducing the color values to 3/4.
988             color = SkColorSetRGB(SkColorGetR(color) * 3/4,
989                                   SkColorGetG(color) * 3/4,
990                                   SkColorGetB(color) * 3/4);
991         }
992         rec->setLuminanceColor(color);
993 
994         // CoreGraphics dialates smoothed text to provide contrast.
995         rec->setContrast(0);
996     }
997 }
998 
999 /** Takes ownership of the CFStringRef. */
get_str(CFStringRef ref,SkString * str)1000 static const char* get_str(CFStringRef ref, SkString* str) {
1001     if (nullptr == ref) {
1002         return nullptr;
1003     }
1004     SkStringFromCFString(ref, str);
1005     CFRelease(ref);
1006     return str->c_str();
1007 }
1008 
onGetFamilyName(SkString * familyName) const1009 void SkTypeface_Mac::onGetFamilyName(SkString* familyName) const {
1010     get_str(CTFontCopyFamilyName(fFontRef.get()), familyName);
1011 }
1012 
onGetPostScriptName(SkString * skPostScriptName) const1013 bool SkTypeface_Mac::onGetPostScriptName(SkString* skPostScriptName) const {
1014     SkUniqueCFRef<CFStringRef> ctPostScriptName(CTFontCopyPostScriptName(fFontRef.get()));
1015     if (!ctPostScriptName) {
1016         return false;
1017     }
1018     if (skPostScriptName) {
1019         SkStringFromCFString(ctPostScriptName.get(), skPostScriptName);
1020     }
1021     return true;
1022 }
1023 
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocalStream) const1024 void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc,
1025                                          bool* isLocalStream) const {
1026     SkString tmpStr;
1027 
1028     desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef.get()), &tmpStr));
1029     desc->setFullName(get_str(CTFontCopyFullName(fFontRef.get()), &tmpStr));
1030     desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef.get()), &tmpStr));
1031     desc->setStyle(this->fontStyle());
1032     desc->setFactoryId(FactoryId);
1033     *isLocalStream = fIsFromStream;
1034 }
1035 
onCharsToGlyphs(const SkUnichar uni[],int count,SkGlyphID glyphs[]) const1036 void SkTypeface_Mac::onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const {
1037     // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
1038     // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
1039     // It is documented that if a mapping is unavailable, the glyph will be set to 0.
1040 
1041     AutoSTMalloc<1024, UniChar> charStorage;
1042     const UniChar* src; // UniChar is a UTF-16 16-bit code unit.
1043     int srcCount;
1044     const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(uni);
1045     UniChar* utf16 = charStorage.reset(2 * count);
1046     src = utf16;
1047     for (int i = 0; i < count; ++i) {
1048         utf16 += SkUTF::ToUTF16(utf32[i], utf16);
1049     }
1050     srcCount = SkToInt(utf16 - src);
1051 
1052     // If there are any non-bmp code points, the provided 'glyphs' storage will be inadequate.
1053     AutoSTMalloc<1024, uint16_t> glyphStorage;
1054     uint16_t* macGlyphs = glyphs;
1055     if (srcCount > count) {
1056         macGlyphs = glyphStorage.reset(srcCount);
1057     }
1058 
1059     CTFontGetGlyphsForCharacters(fFontRef.get(), src, macGlyphs, srcCount);
1060 
1061     // If there were any non-bmp, then copy and compact.
1062     // If all are bmp, 'glyphs' already contains the compact glyphs.
1063     // If some are non-bmp, copy and compact into 'glyphs'.
1064     if (srcCount > count) {
1065         SkASSERT(glyphs != macGlyphs);
1066         int extra = 0;
1067         for (int i = 0; i < count; ++i) {
1068             glyphs[i] = macGlyphs[i + extra];
1069             if (SkUTF::IsLeadingSurrogateUTF16(src[i + extra])) {
1070                 ++extra;
1071             }
1072         }
1073     } else {
1074         SkASSERT(glyphs == macGlyphs);
1075     }
1076 }
1077 
onCountGlyphs() const1078 int SkTypeface_Mac::onCountGlyphs() const {
1079     return SkToInt(CTFontGetGlyphCount(fFontRef.get()));
1080 }
1081 
1082 /** Creates a dictionary suitable for setting the axes on a CTFont. */
ctvariation_from_SkFontArguments(CTFontRef ct,CFArrayRef ctAxes,const SkFontArguments & args)1083 static CTFontVariation ctvariation_from_SkFontArguments(CTFontRef ct, CFArrayRef ctAxes,
1084                                                         const SkFontArguments& args) {
1085     OpszVariation opsz;
1086     constexpr const SkFourByteTag opszTag = SkSetFourByteTag('o','p','s','z');
1087 
1088     if (!ctAxes) {
1089         return CTFontVariation();
1090     }
1091     CFIndex axisCount = CFArrayGetCount(ctAxes);
1092 
1093     // On 10.12 and later, this only returns non-default variations.
1094     SkUniqueCFRef<CFDictionaryRef> oldCtVariation(CTFontCopyVariation(ct));
1095 
1096     const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
1097 
1098     SkUniqueCFRef<CFMutableDictionaryRef> newCtVariation(
1099             CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
1100                                       &kCFTypeDictionaryKeyCallBacks,
1101                                       &kCFTypeDictionaryValueCallBacks));
1102     SkUniqueCFRef<CFMutableDictionaryRef> wrongOpszVariation;
1103 
1104     for (int i = 0; i < axisCount; ++i) {
1105         CFDictionaryRef axisInfoDict;
1106         if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict, "Axis")) {
1107             return CTFontVariation();
1108         }
1109 
1110         int64_t tagLong;
1111         CFNumberRef tagNumber;
1112         CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
1113         if (!SkCFNumberDynamicCast(tag, &tagLong, &tagNumber, "Axis tag")) {
1114             return CTFontVariation();
1115         }
1116 
1117         // The variation axes can be set to any value, but cg will effectively pin them.
1118         // Pin them here to normalize.
1119         double minDouble;
1120         double maxDouble;
1121         double defDouble;
1122         CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
1123         CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
1124         CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
1125         if (!SkCFNumberDynamicCast(min, &minDouble, nullptr, "Axis min") ||
1126             !SkCFNumberDynamicCast(max, &maxDouble, nullptr, "Axis max") ||
1127             !SkCFNumberDynamicCast(def, &defDouble, nullptr, "Axis def"))
1128         {
1129             return CTFontVariation();
1130         }
1131 
1132         // Start with the default value.
1133         double value = defDouble;
1134 
1135         // Then the current value.
1136         bool haveCurrentDouble = false;
1137         double currentDouble = 0;
1138         if (oldCtVariation) {
1139             CFTypeRef currentNumber = CFDictionaryGetValue(oldCtVariation.get(), tagNumber);
1140             if (currentNumber) {
1141                 if (!SkCFNumberDynamicCast(currentNumber, &value, nullptr, "Variation value")) {
1142                     return CTFontVariation();
1143                 }
1144                 currentDouble = value;
1145                 haveCurrentDouble = true;
1146             }
1147         }
1148 
1149         // Then the requested value.
1150         // The position may be over specified. If there are multiple values for a given axis,
1151         // use the last one since that's what css-fonts-4 requires.
1152         for (int j = position.coordinateCount; j --> 0;) {
1153             if (position.coordinates[j].axis == tagLong) {
1154                 value = SkTPin<double>(position.coordinates[j].value, minDouble, maxDouble);
1155                 if (tagLong == opszTag) {
1156                     opsz.isSet = true;
1157                 }
1158                 break;
1159             }
1160         }
1161         if (tagLong == opszTag) {
1162             opsz.value = value;
1163             if (haveCurrentDouble && value == currentDouble) {
1164                 // Calculate a value strictly in range but different from currentValue.
1165                 double wrongOpszDouble = ((maxDouble - minDouble) / 2.0) + minDouble;
1166                 if (wrongOpszDouble == currentDouble) {
1167                     wrongOpszDouble = ((maxDouble - minDouble) / 4.0) + minDouble;
1168                 }
1169                 wrongOpszVariation.reset(
1170                     CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1171                                               &kCFTypeDictionaryKeyCallBacks,
1172                                               &kCFTypeDictionaryValueCallBacks));
1173                 SkUniqueCFRef<CFNumberRef> wrongOpszNumber(
1174                     CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &wrongOpszDouble));
1175                 CFDictionarySetValue(wrongOpszVariation.get(), tagNumber, wrongOpszNumber.get());
1176             }
1177         }
1178         SkUniqueCFRef<CFNumberRef> valueNumber(
1179             CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
1180         CFDictionaryAddValue(newCtVariation.get(), tagNumber, valueNumber.get());
1181     }
1182     return { SkUniqueCFRef<CFDictionaryRef>(std::move(newCtVariation)),
1183              SkUniqueCFRef<CFDictionaryRef>(std::move(wrongOpszVariation)),
1184              opsz };
1185 }
1186 
onMakeClone(const SkFontArguments & args) const1187 sk_sp<SkTypeface> SkTypeface_Mac::onMakeClone(const SkFontArguments& args) const {
1188     CTFontVariation ctVariation = ctvariation_from_SkFontArguments(fFontRef.get(),
1189                                                                    this->getVariationAxes(),
1190                                                                    args);
1191 
1192     SkUniqueCFRef<CTFontRef> ctVariant;
1193     if (ctVariation.variation) {
1194         SkUniqueCFRef<CFMutableDictionaryRef> attributes(
1195                 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1196                                           &kCFTypeDictionaryKeyCallBacks,
1197                                           &kCFTypeDictionaryValueCallBacks));
1198 
1199         CTFontRef ctFont = fFontRef.get();
1200         SkUniqueCFRef<CTFontRef> wrongOpszFont;
1201         if (ctVariation.wrongOpszVariation) {
1202             // On macOS 11 cloning a system font with an opsz axis and not changing the
1203             // value of the opsz axis (either by setting it to the same value or not
1204             // specifying it at all) when setting a variation causes the variation to
1205             // be set but the cloned font will still compare CFEqual to the original
1206             // font. Work around this by setting the opsz to something which isn't the
1207             // desired value before setting the entire desired variation.
1208             //
1209             // A similar issue occurs with fonts from data on macOS 10.15 and the same
1210             // work around seems to apply. This is less noticeable though since CFEqual
1211             // isn't used on these fonts.
1212             CFDictionarySetValue(attributes.get(),
1213                                  kCTFontVariationAttribute, ctVariation.wrongOpszVariation.get());
1214             SkUniqueCFRef<CTFontDescriptorRef> varDesc(
1215                 CTFontDescriptorCreateWithAttributes(attributes.get()));
1216             wrongOpszFont.reset(CTFontCreateCopyWithAttributes(ctFont, 0, nullptr, varDesc.get()));
1217             ctFont = wrongOpszFont.get();
1218         }
1219 
1220         CFDictionarySetValue(attributes.get(),
1221                              kCTFontVariationAttribute, ctVariation.variation.get());
1222         SkUniqueCFRef<CTFontDescriptorRef> varDesc(
1223                 CTFontDescriptorCreateWithAttributes(attributes.get()));
1224         ctVariant.reset(CTFontCreateCopyWithAttributes(ctFont, 0, nullptr, varDesc.get()));
1225     } else {
1226         ctVariant.reset((CTFontRef)CFRetain(fFontRef.get()));
1227     }
1228     if (!ctVariant) {
1229         return nullptr;
1230     }
1231 
1232     return SkTypeface_Mac::Make(std::move(ctVariant), ctVariation.opsz,
1233                                 fStream ? fStream->duplicate() : nullptr);
1234 }
1235 
skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream)1236 static sk_sp<SkData> skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream) {
1237     size_t size = stream->getLength();
1238     if (const void* base = stream->getMemoryBase()) {
1239         return SkData::MakeWithProc(base, size,
1240                                     [](const void*, void* ctx) -> void {
1241                                         delete (SkStreamAsset*)ctx;
1242                                     }, stream.release());
1243     }
1244     return SkData::MakeFromStream(stream.get(), size);
1245 }
1246 
cfdata_from_skdata(sk_sp<SkData> data)1247 static SkUniqueCFRef<CFDataRef> cfdata_from_skdata(sk_sp<SkData> data) {
1248     void const * const addr = data->data();
1249     size_t const size = data->size();
1250 
1251     CFAllocatorContext ctx = {
1252         0, // CFIndex version
1253         data.release(), // void* info
1254         nullptr, // const void *(*retain)(const void *info);
1255         nullptr, // void (*release)(const void *info);
1256         nullptr, // CFStringRef (*copyDescription)(const void *info);
1257         nullptr, // void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info);
1258         nullptr, // void*(*reallocate)(void* ptr,CFIndex newsize,CFOptionFlags hint,void* info);
1259         [](void*,void* info) -> void { // void (*deallocate)(void *ptr, void *info);
1260             SkASSERT(info);
1261             ((SkData*)info)->unref();
1262         },
1263         nullptr, // CFIndex (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info);
1264     };
1265     SkUniqueCFRef<CFAllocatorRef> alloc(CFAllocatorCreate(kCFAllocatorDefault, &ctx));
1266     return SkUniqueCFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(
1267             kCFAllocatorDefault, (const UInt8 *)addr, size, alloc.get()));
1268 }
1269 
ctfont_from_skdata(sk_sp<SkData> data,int ttcIndex)1270 static SkUniqueCFRef<CTFontRef> ctfont_from_skdata(sk_sp<SkData> data, int ttcIndex) {
1271     // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available.
1272     if (ttcIndex != 0) {
1273         return nullptr;
1274     }
1275 
1276     SkUniqueCFRef<CFDataRef> cfData(cfdata_from_skdata(std::move(data)));
1277 
1278     SkUniqueCFRef<CTFontDescriptorRef> desc(
1279             CTFontManagerCreateFontDescriptorFromData(cfData.get()));
1280     if (!desc) {
1281         return nullptr;
1282     }
1283     return SkUniqueCFRef<CTFontRef>(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
1284 }
1285 
MakeFromStream(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args)1286 sk_sp<SkTypeface> SkTypeface_Mac::MakeFromStream(std::unique_ptr<SkStreamAsset> stream,
1287                                                  const SkFontArguments& args)
1288 {
1289     // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available.
1290     int ttcIndex = args.getCollectionIndex();
1291     if (ttcIndex != 0) {
1292         return nullptr;
1293     }
1294 
1295     sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate());
1296     if (!data) {
1297         return nullptr;
1298     }
1299     SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex);
1300     if (!ct) {
1301         return nullptr;
1302     }
1303 
1304     SkUniqueCFRef<CTFontRef> ctVariant;
1305     CTFontVariation ctVariation;
1306     if (args.getVariationDesignPosition().coordinateCount == 0) {
1307         ctVariant = std::move(ct);
1308     } else {
1309         SkUniqueCFRef<CFArrayRef> axes(CTFontCopyVariationAxes(ct.get()));
1310         ctVariation = ctvariation_from_SkFontArguments(ct.get(), axes.get(), args);
1311 
1312         if (ctVariation.variation) {
1313             SkUniqueCFRef<CFMutableDictionaryRef> attributes(
1314                      CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1315                                                &kCFTypeDictionaryKeyCallBacks,
1316                                                &kCFTypeDictionaryValueCallBacks));
1317             CFDictionaryAddValue(attributes.get(),
1318                                  kCTFontVariationAttribute, ctVariation.variation.get());
1319             SkUniqueCFRef<CTFontDescriptorRef> varDesc(
1320                     CTFontDescriptorCreateWithAttributes(attributes.get()));
1321             ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get()));
1322         } else {
1323             ctVariant = std::move(ct);
1324         }
1325     }
1326     if (!ctVariant) {
1327         return nullptr;
1328     }
1329 
1330     return SkTypeface_Mac::Make(std::move(ctVariant), ctVariation.opsz, std::move(stream));
1331 }
1332 
onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],int parameterCount) const1333 int SkTypeface_Mac::onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
1334                                                    int parameterCount) const
1335 {
1336     CFArrayRef ctAxes = this->getVariationAxes();
1337     if (!ctAxes) {
1338         return -1;
1339     }
1340     CFIndex axisCount = CFArrayGetCount(ctAxes);
1341 
1342     if (!parameters || parameterCount < axisCount) {
1343         return axisCount;
1344     }
1345 
1346     // Added in 10.13
1347     static CFStringRef* kCTFontVariationAxisHiddenKeyPtr =
1348             static_cast<CFStringRef*>(dlsym(RTLD_DEFAULT, "kCTFontVariationAxisHiddenKey"));
1349 
1350     for (int i = 0; i < axisCount; ++i) {
1351         CFDictionaryRef axisInfoDict;
1352         if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict, "Axis")) {
1353             return -1;
1354         }
1355 
1356         int64_t tagLong;
1357         CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
1358         if (!SkCFNumberDynamicCast(tag, &tagLong, nullptr, "Axis tag")) {
1359             return -1;
1360         }
1361 
1362         double minDouble;
1363         double maxDouble;
1364         double defDouble;
1365         CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
1366         CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
1367         CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
1368         if (!SkCFNumberDynamicCast(min, &minDouble, nullptr, "Axis min") ||
1369             !SkCFNumberDynamicCast(max, &maxDouble, nullptr, "Axis max") ||
1370             !SkCFNumberDynamicCast(def, &defDouble, nullptr, "Axis def"))
1371         {
1372             return -1;
1373         }
1374 
1375         SkFontParameters::Variation::Axis& skAxis = parameters[i];
1376         skAxis.tag = tagLong;
1377         skAxis.min = minDouble;
1378         skAxis.max = maxDouble;
1379         skAxis.def = defDouble;
1380         skAxis.setHidden(false);
1381         if (kCTFontVariationAxisHiddenKeyPtr) {
1382             CFTypeRef hidden = CFDictionaryGetValue(axisInfoDict,*kCTFontVariationAxisHiddenKeyPtr);
1383             if (hidden) {
1384                 // At least macOS 11 Big Sur Beta 4 uses CFNumberRef instead of CFBooleanRef.
1385                 // https://crbug.com/1113444
1386                 CFBooleanRef hiddenBoolean;
1387                 int hiddenInt;
1388                 if (SkCFDynamicCast(hidden, &hiddenBoolean, nullptr)) {
1389                     skAxis.setHidden(CFBooleanGetValue(hiddenBoolean));
1390                 } else if (SkCFNumberDynamicCast(hidden, &hiddenInt, nullptr, "Axis hidden")) {
1391                     skAxis.setHidden(hiddenInt);
1392                 } else {
1393                     return -1;
1394                 }
1395             }
1396         }
1397     }
1398     return axisCount;
1399 }
1400 
1401 #endif
1402