• 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 #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                 // CTFontCopyCharacterSet and CTFontGetGlyphsForCharacters seem to add 'support'
425                 // for characters 0x9, 0xA, and 0xD mapping them to the glyph for character 0x20?
426                 // Prefer mappings to codepoints at or above 0x20.
427                 if (glyphs[0] < glyphCount && glyphToUnicode[glyphs[0]] < 0x20) {
428                     glyphToUnicode[glyphs[0]] = codepoint;
429                 }
430             }
431         }
432     }
433 }
434 // Construct Glyph to Unicode table.
populate_glyph_to_unicode(CTFontRef ctFont,CFIndex glyphCount,SkUnichar * glyphToUnicode)435 static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
436                                       SkUnichar* glyphToUnicode) {
437     sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount);
438     SkUniqueCFRef<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
439     if (!charSet) {
440         populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
441         return;
442     }
443 
444     SkUniqueCFRef<CFDataRef> bitmap(
445             CFCharacterSetCreateBitmapRepresentation(nullptr, charSet.get()));
446     if (!bitmap) {
447         return;
448     }
449     CFIndex dataLength = CFDataGetLength(bitmap.get());
450     if (!dataLength) {
451         return;
452     }
453     SkASSERT(dataLength >= kPlaneSize);
454     const UInt8* bits = CFDataGetBytePtr(bitmap.get());
455 
456     get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, 0);
457     /*
458     A CFData object that specifies the bitmap representation of the Unicode
459     character points the for the new character set. The bitmap representation could
460     contain all the Unicode character range starting from BMP to Plane 16. The
461     first 8KiB (8192 bytes) of the data represent the BMP range. The BMP range 8KiB
462     can be followed by zero to sixteen 8KiB bitmaps, each prepended with the plane
463     index byte. For example, the bitmap representing the BMP and Plane 2 has the
464     size of 16385 bytes (8KiB for BMP, 1 byte index, and a 8KiB bitmap for Plane
465     2). The plane index byte, in this case, contains the integer value two.
466     */
467 
468     if (dataLength <= kPlaneSize) {
469         return;
470     }
471     int extraPlaneCount = (dataLength - kPlaneSize) / (1 + kPlaneSize);
472     SkASSERT(dataLength == kPlaneSize + extraPlaneCount * (1 + kPlaneSize));
473     while (extraPlaneCount-- > 0) {
474         bits += kPlaneSize;
475         uint8_t planeIndex = *bits++;
476         SkASSERT(planeIndex >= 1);
477         SkASSERT(planeIndex <= 16);
478         get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, planeIndex);
479     }
480 }
481 
getGlyphToUnicodeMap(SkUnichar * dstArray) const482 void SkTypeface_Mac::getGlyphToUnicodeMap(SkUnichar* dstArray) const {
483     SkUniqueCFRef<CTFontRef> ctFont =
484             SkCTFontCreateExactCopy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()),
485                                     fOpszVariation);
486     CFIndex glyphCount = CTFontGetGlyphCount(ctFont.get());
487     populate_glyph_to_unicode(ctFont.get(), glyphCount, dstArray);
488 }
489 
onGetAdvancedMetrics() const490 std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_Mac::onGetAdvancedMetrics() const {
491 
492     SkUniqueCFRef<CTFontRef> ctFont =
493             SkCTFontCreateExactCopy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()),
494                                     fOpszVariation);
495 
496     std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics);
497 
498     {
499         SkUniqueCFRef<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont.get()));
500         if (fontName.get()) {
501             SkStringFromCFString(fontName.get(), &info->fPostScriptName);
502         }
503     }
504 
505     CFArrayRef ctAxes = this->getVariationAxes();
506     if (ctAxes && CFArrayGetCount(ctAxes) > 0) {
507         info->fFlags |= SkAdvancedTypefaceMetrics::kVariable_FontFlag;
508     }
509 
510     SkOTTableOS2_V4::Type fsType;
511     if (sizeof(fsType) == this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG),
512                                              offsetof(SkOTTableOS2_V4, fsType),
513                                              sizeof(fsType),
514                                              &fsType)) {
515         SkOTUtils::SetAdvancedTypefaceFlags(fsType, info.get());
516     }
517 
518     // If it's not an OpenType font, mark it as 'other'. Assume that OpenType
519     // fonts always have both glyf and loca tables or a CFF table.
520     // At the least, this is what is needed to subset the font.
521     // CTFontCopyAttribute() does not always succeed in determining this directly.
522     constexpr SkFontTableTag glyf = SkSetFourByteTag('g','l','y','f');
523     constexpr SkFontTableTag loca = SkSetFourByteTag('l','o','c','a');
524     constexpr SkFontTableTag CFF  = SkSetFourByteTag('C','F','F',' ');
525     if (this->getTableSize(glyf) && this->getTableSize(loca)) {
526         info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
527     } else if (this->getTableSize(CFF)) {
528         info->fType = SkAdvancedTypefaceMetrics::kCFF_Font;
529     } else {
530         return info;
531     }
532 
533     CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get());
534     if (symbolicTraits & kCTFontMonoSpaceTrait) {
535         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
536     }
537     if (symbolicTraits & kCTFontItalicTrait) {
538         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
539     }
540     CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
541     if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
542         info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
543     } else if (stylisticClass & kCTFontScriptsClass) {
544         info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
545     }
546     info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont.get());
547     info->fAscent = (int16_t) CTFontGetAscent(ctFont.get());
548     info->fDescent = (int16_t) CTFontGetDescent(ctFont.get());
549     info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont.get());
550     CGRect bbox = CTFontGetBoundingBox(ctFont.get());
551 
552     SkRect r;
553     r.setLTRB(SkScalarFromCGFloat(SkCGRectGetMinX(bbox)),   // Left
554               SkScalarFromCGFloat(SkCGRectGetMaxY(bbox)),   // Top
555               SkScalarFromCGFloat(SkCGRectGetMaxX(bbox)),   // Right
556               SkScalarFromCGFloat(SkCGRectGetMinY(bbox)));  // Bottom
557 
558     r.roundOut(&(info->fBBox));
559 
560     // Figure out a good guess for StemV - Min width of i, I, !, 1.
561     // This probably isn't very good with an italic font.
562     int16_t min_width = SHRT_MAX;
563     info->fStemV = 0;
564     static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
565     const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
566     CGGlyph glyphs[count];
567     CGRect boundingRects[count];
568     if (CTFontGetGlyphsForCharacters(ctFont.get(), stem_chars, glyphs, count)) {
569         CTFontGetBoundingRectsForGlyphs(ctFont.get(), kCTFontOrientationHorizontal,
570                                         glyphs, boundingRects, count);
571         for (size_t i = 0; i < count; i++) {
572             int16_t width = (int16_t) boundingRects[i].size.width;
573             if (width > 0 && width < min_width) {
574                 min_width = width;
575                 info->fStemV = min_width;
576             }
577         }
578     }
579     return info;
580 }
581 
get_font_type_tag(CTFontRef ctFont)582 static SK_SFNT_ULONG get_font_type_tag(CTFontRef ctFont) {
583     SkUniqueCFRef<CFNumberRef> fontFormatRef(
584             static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
585     if (!fontFormatRef) {
586         return 0;
587     }
588 
589     SInt32 fontFormatValue;
590     if (!CFNumberGetValue(fontFormatRef.get(), kCFNumberSInt32Type, &fontFormatValue)) {
591         return 0;
592     }
593 
594     switch (fontFormatValue) {
595         case kCTFontFormatOpenTypePostScript:
596             return SkSFNTHeader::fontType_OpenTypeCFF::TAG;
597         case kCTFontFormatOpenTypeTrueType:
598             return SkSFNTHeader::fontType_WindowsTrueType::TAG;
599         case kCTFontFormatTrueType:
600             return SkSFNTHeader::fontType_MacTrueType::TAG;
601         case kCTFontFormatPostScript:
602             return SkSFNTHeader::fontType_PostScript::TAG;
603         case kCTFontFormatBitmap:
604             return SkSFNTHeader::fontType_MacTrueType::TAG;
605         case kCTFontFormatUnrecognized:
606         default:
607             return 0;
608     }
609 }
610 
onOpenStream(int * ttcIndex) const611 std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
612     *ttcIndex = 0;
613 
614     fInitStream([this]{
615     if (fStream) {
616         return;
617     }
618 
619     SK_SFNT_ULONG fontType = get_font_type_tag(fFontRef.get());
620 
621     // get table tags
622     int numTables = this->countTables();
623     SkTDArray<SkFontTableTag> tableTags;
624     tableTags.resize(numTables);
625     this->getTableTags(tableTags.begin());
626 
627     // CT seems to be unreliable in being able to obtain the type,
628     // even if all we want is the first four bytes of the font resource.
629     // Just the presence of the FontForge 'FFTM' table seems to throw it off.
630     if (fontType == 0) {
631         fontType = SkSFNTHeader::fontType_WindowsTrueType::TAG;
632 
633         // see https://skbug.com/7630#c7
634         bool couldBeCFF = false;
635         constexpr SkFontTableTag CFFTag = SkSetFourByteTag('C', 'F', 'F', ' ');
636         constexpr SkFontTableTag CFF2Tag = SkSetFourByteTag('C', 'F', 'F', '2');
637         for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
638             if (CFFTag == tableTags[tableIndex] || CFF2Tag == tableTags[tableIndex]) {
639                 couldBeCFF = true;
640             }
641         }
642         if (couldBeCFF) {
643             fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG;
644         }
645     }
646 
647     // Sometimes CoreGraphics incorrectly thinks a font is kCTFontFormatPostScript.
648     // It is exceedingly unlikely that this is the case, so double check
649     // (see https://crbug.com/809763 ).
650     if (fontType == SkSFNTHeader::fontType_PostScript::TAG) {
651         // see if there are any required 'typ1' tables (see Adobe Technical Note #5180)
652         bool couldBeTyp1 = false;
653         constexpr SkFontTableTag TYPE1Tag = SkSetFourByteTag('T', 'Y', 'P', '1');
654         constexpr SkFontTableTag CIDTag = SkSetFourByteTag('C', 'I', 'D', ' ');
655         for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
656             if (TYPE1Tag == tableTags[tableIndex] || CIDTag == tableTags[tableIndex]) {
657                 couldBeTyp1 = true;
658             }
659         }
660         if (!couldBeTyp1) {
661             fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG;
662         }
663     }
664 
665     // get the table sizes and accumulate the total size of the font
666     SkTDArray<size_t> tableSizes;
667     size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
668     for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
669         size_t tableSize = this->getTableSize(tableTags[tableIndex]);
670         totalSize += (tableSize + 3) & ~3;
671         *tableSizes.append() = tableSize;
672     }
673 
674     // reserve memory for stream, and zero it (tables must be zero padded)
675     sk_sp<SkData> streamData = SkData::MakeZeroInitialized(totalSize);
676     char* dataStart = (char*)streamData->writable_data();
677     char* dataPtr = dataStart;
678 
679     // compute font header entries
680     uint16_t entrySelector = 0;
681     uint16_t searchRange = 1;
682     while (searchRange < numTables >> 1) {
683         entrySelector++;
684         searchRange <<= 1;
685     }
686     searchRange <<= 4;
687     uint16_t rangeShift = (numTables << 4) - searchRange;
688 
689     // write font header
690     SkSFNTHeader* header = (SkSFNTHeader*)dataPtr;
691     header->fontType = fontType;
692     header->numTables = SkEndian_SwapBE16(numTables);
693     header->searchRange = SkEndian_SwapBE16(searchRange);
694     header->entrySelector = SkEndian_SwapBE16(entrySelector);
695     header->rangeShift = SkEndian_SwapBE16(rangeShift);
696     dataPtr += sizeof(SkSFNTHeader);
697 
698     // write tables
699     SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr;
700     dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
701     for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
702         size_t tableSize = tableSizes[tableIndex];
703         this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
704         entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]);
705         entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr,
706                                                                          tableSize));
707         entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart));
708         entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize));
709 
710         dataPtr += (tableSize + 3) & ~3;
711         ++entry;
712     }
713     fStream = std::make_unique<SkMemoryStream>(std::move(streamData));
714     });
715     return fStream->duplicate();
716 }
717 
onOpenExistingStream(int * ttcIndex) const718 std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenExistingStream(int* ttcIndex) const {
719     *ttcIndex = 0;
720     return fStream ? fStream->duplicate() : nullptr;
721 }
722 
onGlyphMaskNeedsCurrentColor() const723 bool SkTypeface_Mac::onGlyphMaskNeedsCurrentColor() const {
724     // `CPAL` (`COLR` and `SVG`) fonts may need the current color.
725     // However, even `sbix` fonts can have glyphs which need the current color.
726     // These may be glyphs with paths but no `sbix` entries, which are impossible to distinguish.
727     return this->fHasColorGlyphs;
728 }
729 
getVariationAxes() const730 CFArrayRef SkTypeface_Mac::getVariationAxes() const {
731     fInitVariationAxes([this]{
732         // Prefer kCTFontVariationAxesAttribute, faster since it doesn't localize axis names.
733         SkUniqueCFRef<CTFontDescriptorRef> desc(CTFontCopyFontDescriptor(fFontRef.get()));
734         SkUniqueCFRef<CFTypeRef> cf(
735                 CTFontDescriptorCopyAttribute(desc.get(), kCTFontVariationAxesAttribute));
736         CFArrayRef array;
737         if (cf && SkCFDynamicCast(cf.get(), &array, "Axes")) {
738             fVariationAxes.reset(array);
739             cf.release();
740             return;
741         }
742         fVariationAxes.reset(CTFontCopyVariationAxes(fFontRef.get()));
743     });
744     return fVariationAxes.get();
745 }
746 
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount) const747 int SkTypeface_Mac::onGetVariationDesignPosition(
748         SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
749 {
750     CFArrayRef ctAxes = this->getVariationAxes();
751     if (!ctAxes) {
752         return -1;
753     }
754     CFIndex axisCount = CFArrayGetCount(ctAxes);
755     if (!coordinates || coordinateCount < axisCount) {
756         return axisCount;
757     }
758 
759     // On 10.12 and later, this only returns non-default variations.
760     SkUniqueCFRef<CFDictionaryRef> ctVariation(CTFontCopyVariation(fFontRef.get()));
761     if (!ctVariation) {
762         return -1;
763     }
764 
765     for (int i = 0; i < axisCount; ++i) {
766         CFDictionaryRef axisInfoDict;
767         if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict, "Axis")) {
768             return -1;
769         }
770 
771         int64_t tagLong;
772         CFNumberRef tagNumber;
773         CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
774         if (!SkCFNumberDynamicCast(tag, &tagLong, &tagNumber, "Axis tag")) {
775             return -1;
776         }
777         coordinates[i].axis = tagLong;
778 
779         CGFloat valueCGFloat;
780         CFTypeRef value = CFDictionaryGetValue(ctVariation.get(), tagNumber);
781         if (value) {
782             if (!SkCFNumberDynamicCast(value, &valueCGFloat, nullptr, "Variation value")) {
783                 return -1;
784             }
785         } else {
786             CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
787             if (!SkCFNumberDynamicCast(def, &valueCGFloat, nullptr, "Axis default value")) {
788                 return -1;
789             }
790         }
791         coordinates[i].value = SkScalarFromCGFloat(valueCGFloat);
792     }
793     return axisCount;
794 }
795 
onGetUPEM() const796 int SkTypeface_Mac::onGetUPEM() const {
797     SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr));
798     return CGFontGetUnitsPerEm(cgFont.get());
799 }
800 
onCreateFamilyNameIterator() const801 SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const {
802     sk_sp<SkTypeface::LocalizedStrings> nameIter =
803             SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this);
804     if (!nameIter) {
805         CFStringRef cfLanguageRaw;
806         SkUniqueCFRef<CFStringRef> cfFamilyName(
807                 CTFontCopyLocalizedName(fFontRef.get(), kCTFontFamilyNameKey, &cfLanguageRaw));
808         SkUniqueCFRef<CFStringRef> cfLanguage(cfLanguageRaw);
809 
810         SkString skLanguage;
811         SkString skFamilyName;
812         if (cfLanguage) {
813             SkStringFromCFString(cfLanguage.get(), &skLanguage);
814         } else {
815             skLanguage = "und"; //undetermined
816         }
817         if (cfFamilyName) {
818             SkStringFromCFString(cfFamilyName.get(), &skFamilyName);
819         }
820 
821         nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(skFamilyName, skLanguage);
822     }
823     return nameIter.release();
824 }
825 
onGetTableTags(SkFontTableTag tags[]) const826 int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
827     SkUniqueCFRef<CFArrayRef> cfArray(
828             CTFontCopyAvailableTables(fFontRef.get(), kCTFontTableOptionNoOptions));
829     if (!cfArray) {
830         return 0;
831     }
832     CFIndex count = CFArrayGetCount(cfArray.get());
833     if (tags) {
834         for (CFIndex i = 0; i < count; ++i) {
835             uintptr_t fontTag = reinterpret_cast<uintptr_t>(
836                 CFArrayGetValueAtIndex(cfArray.get(), i));
837             tags[i] = static_cast<SkFontTableTag>(fontTag);
838         }
839     }
840     return count;
841 }
842 
843 // If, as is the case with web fonts, the CTFont data isn't available,
844 // the CGFont data may work. While the CGFont may always provide the
845 // right result, leave the CTFont code path to minimize disruption.
copy_table_from_font(CTFontRef ctFont,SkFontTableTag tag)846 static SkUniqueCFRef<CFDataRef> copy_table_from_font(CTFontRef ctFont, SkFontTableTag tag) {
847     SkUniqueCFRef<CFDataRef> data(CTFontCopyTable(ctFont, (CTFontTableTag) tag,
848                                                   kCTFontTableOptionNoOptions));
849     if (!data) {
850         SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr));
851         data.reset(CGFontCopyTableForTag(cgFont.get(), tag));
852     }
853     return data;
854 }
855 
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * dstData) const856 size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset,
857                                       size_t length, void* dstData) const {
858     SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
859     if (!srcData) {
860         return 0;
861     }
862 
863     size_t srcSize = CFDataGetLength(srcData.get());
864     if (offset >= srcSize) {
865         return 0;
866     }
867     if (length > srcSize - offset) {
868         length = srcSize - offset;
869     }
870     if (dstData) {
871         memcpy(dstData, CFDataGetBytePtr(srcData.get()) + offset, length);
872     }
873     return length;
874 }
875 
onCopyTableData(SkFontTableTag tag) const876 sk_sp<SkData> SkTypeface_Mac::onCopyTableData(SkFontTableTag tag) const {
877     SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
878     if (!srcData) {
879         return nullptr;
880     }
881     const UInt8* data = CFDataGetBytePtr(srcData.get());
882     CFIndex length = CFDataGetLength(srcData.get());
883     return SkData::MakeWithProc(data, length,
884                                 [](const void*, void* ctx) {
885                                     CFRelease((CFDataRef)ctx);
886                                 }, (void*)srcData.release());
887 }
888 
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const889 std::unique_ptr<SkScalerContext> SkTypeface_Mac::onCreateScalerContext(
890     const SkScalerContextEffects& effects, const SkDescriptor* desc) const
891 {
892     return std::make_unique<SkScalerContext_Mac>(*const_cast<SkTypeface_Mac*>(this), effects, desc);
893 }
894 
onFilterRec(SkScalerContextRec * rec) const895 void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
896     rec->useStrokeForFakeBold();
897 
898     if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
899         rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
900     {
901         rec->fMaskFormat = SkMask::kA8_Format;
902         // Render the glyphs as close as possible to what was requested.
903         // The above turns off subpixel rendering, but the user requested it.
904         // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks.
905         // See comments below for more details.
906         rec->setHinting(SkFontHinting::kNormal);
907     }
908 
909     unsigned flagsWeDontSupport = SkScalerContext::kForceAutohinting_Flag  |
910                                   SkScalerContext::kLCD_BGROrder_Flag |
911                                   SkScalerContext::kLCD_Vertical_Flag;
912 
913     rec->fFlags &= ~flagsWeDontSupport;
914 
915     const SkCTFontSmoothBehavior smoothBehavior = SkCTFontGetSmoothBehavior();
916 
917     // Only two levels of hinting are supported.
918     // kNo_Hinting means avoid CoreGraphics outline dilation (smoothing).
919     // kNormal_Hinting means CoreGraphics outline dilation (smoothing) is allowed.
920     if (rec->getHinting() != SkFontHinting::kNone) {
921         rec->setHinting(SkFontHinting::kNormal);
922     }
923     // If smoothing has no effect, don't request it.
924     if (smoothBehavior == SkCTFontSmoothBehavior::none) {
925         rec->setHinting(SkFontHinting::kNone);
926     }
927 
928     // FIXME: lcd smoothed un-hinted rasterization unsupported.
929     // Tracked by http://code.google.com/p/skia/issues/detail?id=915 .
930     // There is no current means to honor a request for unhinted lcd,
931     // so arbitrarilly ignore the hinting request and honor lcd.
932 
933     // Hinting and smoothing should be orthogonal, but currently they are not.
934     // CoreGraphics has no API to influence hinting. However, its lcd smoothed
935     // output is drawn from auto-dilated outlines (the amount of which is
936     // determined by AppleFontSmoothing). Its regular anti-aliased output is
937     // drawn from un-dilated outlines.
938 
939     // The behavior of Skia is as follows:
940     // [AA][no-hint]: generate AA using CoreGraphic's AA output.
941     // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single
942     // channel. This matches [LCD][yes-hint] in weight.
943     // [LCD][no-hint]: currently unable to honor, and must pick which to respect.
944     // Currently side with LCD, effectively ignoring the hinting setting.
945     // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output.
946     if (rec->fMaskFormat == SkMask::kLCD16_Format) {
947         if (smoothBehavior == SkCTFontSmoothBehavior::subpixel) {
948             //CoreGraphics creates 555 masks for smoothed text anyway.
949             rec->fMaskFormat = SkMask::kLCD16_Format;
950             rec->setHinting(SkFontHinting::kNormal);
951         } else {
952             rec->fMaskFormat = SkMask::kA8_Format;
953             if (smoothBehavior != SkCTFontSmoothBehavior::none) {
954                 rec->setHinting(SkFontHinting::kNormal);
955             }
956         }
957     }
958 
959     // CoreText provides no information as to whether a glyph will be color or not.
960     // Fonts may mix outlines and bitmaps, so information is needed on a glyph by glyph basis.
961     // If a font contains an 'sbix' table, consider it to be a color font, and disable lcd.
962     if (fHasColorGlyphs) {
963         rec->fMaskFormat = SkMask::kARGB32_Format;
964     }
965 
966     // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
967     // All other masks can use regular gamma.
968     if (SkMask::kA8_Format == rec->fMaskFormat && SkFontHinting::kNone == rec->getHinting()) {
969 #ifndef SK_GAMMA_APPLY_TO_A8
970         // SRGBTODO: Is this correct? Do we want contrast boost?
971         rec->ignorePreBlend();
972 #endif
973     } else {
974         SkColor color = rec->getLuminanceColor();
975         if (smoothBehavior == SkCTFontSmoothBehavior::some) {
976             // CoreGraphics smoothed text without subpixel coverage blitting goes from a gamma of
977             // 2.0 for black foreground to a gamma of 1.0 for white foreground. Emulate this
978             // through the mask gamma by reducing the color values to 1/2.
979             color = SkColorSetRGB(SkColorGetR(color) * 1/2,
980                                   SkColorGetG(color) * 1/2,
981                                   SkColorGetB(color) * 1/2);
982         } else if (smoothBehavior == SkCTFontSmoothBehavior::subpixel) {
983             // CoreGraphics smoothed text with subpixel coverage blitting goes from a gamma of
984             // 2.0 for black foreground to a gamma of ~1.4? for white foreground. Emulate this
985             // through the mask gamma by reducing the color values to 3/4.
986             color = SkColorSetRGB(SkColorGetR(color) * 3/4,
987                                   SkColorGetG(color) * 3/4,
988                                   SkColorGetB(color) * 3/4);
989         }
990         rec->setLuminanceColor(color);
991 
992         // CoreGraphics dialates smoothed text to provide contrast.
993         rec->setContrast(0);
994     }
995 }
996 
997 /** Takes ownership of the CFStringRef. */
get_str(CFStringRef ref,SkString * str)998 static const char* get_str(CFStringRef ref, SkString* str) {
999     if (nullptr == ref) {
1000         return nullptr;
1001     }
1002     SkStringFromCFString(ref, str);
1003     CFRelease(ref);
1004     return str->c_str();
1005 }
1006 
onGetFamilyName(SkString * familyName) const1007 void SkTypeface_Mac::onGetFamilyName(SkString* familyName) const {
1008     get_str(CTFontCopyFamilyName(fFontRef.get()), familyName);
1009 }
1010 
onGetPostScriptName(SkString * skPostScriptName) const1011 bool SkTypeface_Mac::onGetPostScriptName(SkString* skPostScriptName) const {
1012     SkUniqueCFRef<CFStringRef> ctPostScriptName(CTFontCopyPostScriptName(fFontRef.get()));
1013     if (!ctPostScriptName) {
1014         return false;
1015     }
1016     if (skPostScriptName) {
1017         SkStringFromCFString(ctPostScriptName.get(), skPostScriptName);
1018     }
1019     return true;
1020 }
1021 
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocalStream) const1022 void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc,
1023                                          bool* isLocalStream) const {
1024     SkString tmpStr;
1025 
1026     desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef.get()), &tmpStr));
1027     desc->setFullName(get_str(CTFontCopyFullName(fFontRef.get()), &tmpStr));
1028     desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef.get()), &tmpStr));
1029     desc->setStyle(this->fontStyle());
1030     desc->setFactoryId(FactoryId);
1031     *isLocalStream = fIsFromStream;
1032 }
1033 
onCharsToGlyphs(const SkUnichar uni[],int count,SkGlyphID glyphs[]) const1034 void SkTypeface_Mac::onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const {
1035     // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
1036     // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
1037     // It is documented that if a mapping is unavailable, the glyph will be set to 0.
1038 
1039     AutoSTMalloc<1024, UniChar> charStorage;
1040     const UniChar* src; // UniChar is a UTF-16 16-bit code unit.
1041     int srcCount;
1042     const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(uni);
1043     UniChar* utf16 = charStorage.reset(2 * count);
1044     src = utf16;
1045     for (int i = 0; i < count; ++i) {
1046         utf16 += SkUTF::ToUTF16(utf32[i], utf16);
1047     }
1048     srcCount = SkToInt(utf16 - src);
1049 
1050     // If there are any non-bmp code points, the provided 'glyphs' storage will be inadequate.
1051     AutoSTMalloc<1024, uint16_t> glyphStorage;
1052     uint16_t* macGlyphs = glyphs;
1053     if (srcCount > count) {
1054         macGlyphs = glyphStorage.reset(srcCount);
1055     }
1056 
1057     CTFontGetGlyphsForCharacters(fFontRef.get(), src, macGlyphs, srcCount);
1058 
1059     // If there were any non-bmp, then copy and compact.
1060     // If all are bmp, 'glyphs' already contains the compact glyphs.
1061     // If some are non-bmp, copy and compact into 'glyphs'.
1062     if (srcCount > count) {
1063         SkASSERT(glyphs != macGlyphs);
1064         int extra = 0;
1065         for (int i = 0; i < count; ++i) {
1066             glyphs[i] = macGlyphs[i + extra];
1067             if (SkUTF::IsLeadingSurrogateUTF16(src[i + extra])) {
1068                 ++extra;
1069             }
1070         }
1071     } else {
1072         SkASSERT(glyphs == macGlyphs);
1073     }
1074 }
1075 
onCountGlyphs() const1076 int SkTypeface_Mac::onCountGlyphs() const {
1077     return SkToInt(CTFontGetGlyphCount(fFontRef.get()));
1078 }
1079 
1080 /** Creates a dictionary suitable for setting the axes on a CTFont. */
ctvariation_from_SkFontArguments(CTFontRef ct,CFArrayRef ctAxes,const SkFontArguments & args)1081 static CTFontVariation ctvariation_from_SkFontArguments(CTFontRef ct, CFArrayRef ctAxes,
1082                                                         const SkFontArguments& args) {
1083     OpszVariation opsz;
1084     constexpr const SkFourByteTag opszTag = SkSetFourByteTag('o','p','s','z');
1085 
1086     if (!ctAxes) {
1087         return CTFontVariation();
1088     }
1089     CFIndex axisCount = CFArrayGetCount(ctAxes);
1090 
1091     // On 10.12 and later, this only returns non-default variations.
1092     SkUniqueCFRef<CFDictionaryRef> oldCtVariation(CTFontCopyVariation(ct));
1093 
1094     const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
1095 
1096     SkUniqueCFRef<CFMutableDictionaryRef> newCtVariation(
1097             CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
1098                                       &kCFTypeDictionaryKeyCallBacks,
1099                                       &kCFTypeDictionaryValueCallBacks));
1100     SkUniqueCFRef<CFMutableDictionaryRef> wrongOpszVariation;
1101 
1102     for (int i = 0; i < axisCount; ++i) {
1103         CFDictionaryRef axisInfoDict;
1104         if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict, "Axis")) {
1105             return CTFontVariation();
1106         }
1107 
1108         int64_t tagLong;
1109         CFNumberRef tagNumber;
1110         CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
1111         if (!SkCFNumberDynamicCast(tag, &tagLong, &tagNumber, "Axis tag")) {
1112             return CTFontVariation();
1113         }
1114 
1115         // The variation axes can be set to any value, but cg will effectively pin them.
1116         // Pin them here to normalize.
1117         double minDouble;
1118         double maxDouble;
1119         double defDouble;
1120         CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
1121         CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
1122         CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
1123         if (!SkCFNumberDynamicCast(min, &minDouble, nullptr, "Axis min") ||
1124             !SkCFNumberDynamicCast(max, &maxDouble, nullptr, "Axis max") ||
1125             !SkCFNumberDynamicCast(def, &defDouble, nullptr, "Axis def"))
1126         {
1127             return CTFontVariation();
1128         }
1129 
1130         // Start with the default value.
1131         double value = defDouble;
1132 
1133         // Then the current value.
1134         bool haveCurrentDouble = false;
1135         double currentDouble = 0;
1136         if (oldCtVariation) {
1137             CFTypeRef currentNumber = CFDictionaryGetValue(oldCtVariation.get(), tagNumber);
1138             if (currentNumber) {
1139                 if (!SkCFNumberDynamicCast(currentNumber, &value, nullptr, "Variation value")) {
1140                     return CTFontVariation();
1141                 }
1142                 currentDouble = value;
1143                 haveCurrentDouble = true;
1144             }
1145         }
1146 
1147         // Then the requested value.
1148         // The position may be over specified. If there are multiple values for a given axis,
1149         // use the last one since that's what css-fonts-4 requires.
1150         for (int j = position.coordinateCount; j --> 0;) {
1151             if (position.coordinates[j].axis == tagLong) {
1152                 value = SkTPin<double>(position.coordinates[j].value, minDouble, maxDouble);
1153                 if (tagLong == opszTag) {
1154                     opsz.isSet = true;
1155                 }
1156                 break;
1157             }
1158         }
1159         if (tagLong == opszTag) {
1160             opsz.value = value;
1161             if (haveCurrentDouble && value == currentDouble) {
1162                 // Calculate a value strictly in range but different from currentValue.
1163                 double wrongOpszDouble = ((maxDouble - minDouble) / 2.0) + minDouble;
1164                 if (wrongOpszDouble == currentDouble) {
1165                     wrongOpszDouble = ((maxDouble - minDouble) / 4.0) + minDouble;
1166                 }
1167                 wrongOpszVariation.reset(
1168                     CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1169                                               &kCFTypeDictionaryKeyCallBacks,
1170                                               &kCFTypeDictionaryValueCallBacks));
1171                 SkUniqueCFRef<CFNumberRef> wrongOpszNumber(
1172                     CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &wrongOpszDouble));
1173                 CFDictionarySetValue(wrongOpszVariation.get(), tagNumber, wrongOpszNumber.get());
1174             }
1175         }
1176         SkUniqueCFRef<CFNumberRef> valueNumber(
1177             CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
1178         CFDictionaryAddValue(newCtVariation.get(), tagNumber, valueNumber.get());
1179     }
1180     return { SkUniqueCFRef<CFDictionaryRef>(std::move(newCtVariation)),
1181              SkUniqueCFRef<CFDictionaryRef>(std::move(wrongOpszVariation)),
1182              opsz };
1183 }
1184 
onMakeClone(const SkFontArguments & args) const1185 sk_sp<SkTypeface> SkTypeface_Mac::onMakeClone(const SkFontArguments& args) const {
1186     CTFontVariation ctVariation = ctvariation_from_SkFontArguments(fFontRef.get(),
1187                                                                    this->getVariationAxes(),
1188                                                                    args);
1189 
1190     SkUniqueCFRef<CTFontRef> ctVariant;
1191     if (ctVariation.variation) {
1192         SkUniqueCFRef<CFMutableDictionaryRef> attributes(
1193                 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1194                                           &kCFTypeDictionaryKeyCallBacks,
1195                                           &kCFTypeDictionaryValueCallBacks));
1196 
1197         CTFontRef ctFont = fFontRef.get();
1198         SkUniqueCFRef<CTFontRef> wrongOpszFont;
1199         if (ctVariation.wrongOpszVariation) {
1200             // On macOS 11 cloning a system font with an opsz axis and not changing the
1201             // value of the opsz axis (either by setting it to the same value or not
1202             // specifying it at all) when setting a variation causes the variation to
1203             // be set but the cloned font will still compare CFEqual to the original
1204             // font. Work around this by setting the opsz to something which isn't the
1205             // desired value before setting the entire desired variation.
1206             //
1207             // A similar issue occurs with fonts from data on macOS 10.15 and the same
1208             // work around seems to apply. This is less noticeable though since CFEqual
1209             // isn't used on these fonts.
1210             CFDictionarySetValue(attributes.get(),
1211                                  kCTFontVariationAttribute, ctVariation.wrongOpszVariation.get());
1212             SkUniqueCFRef<CTFontDescriptorRef> varDesc(
1213                 CTFontDescriptorCreateWithAttributes(attributes.get()));
1214             wrongOpszFont.reset(CTFontCreateCopyWithAttributes(ctFont, 0, nullptr, varDesc.get()));
1215             ctFont = wrongOpszFont.get();
1216         }
1217 
1218         CFDictionarySetValue(attributes.get(),
1219                              kCTFontVariationAttribute, ctVariation.variation.get());
1220         SkUniqueCFRef<CTFontDescriptorRef> varDesc(
1221                 CTFontDescriptorCreateWithAttributes(attributes.get()));
1222         ctVariant.reset(CTFontCreateCopyWithAttributes(ctFont, 0, nullptr, varDesc.get()));
1223     } else {
1224         ctVariant.reset((CTFontRef)CFRetain(fFontRef.get()));
1225     }
1226     if (!ctVariant) {
1227         return nullptr;
1228     }
1229 
1230     return SkTypeface_Mac::Make(std::move(ctVariant), ctVariation.opsz,
1231                                 fStream ? fStream->duplicate() : nullptr);
1232 }
1233 
skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream)1234 static sk_sp<SkData> skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream) {
1235     size_t size = stream->getLength();
1236     if (const void* base = stream->getMemoryBase()) {
1237         return SkData::MakeWithProc(base, size,
1238                                     [](const void*, void* ctx) -> void {
1239                                         delete (SkStreamAsset*)ctx;
1240                                     }, stream.release());
1241     }
1242     return SkData::MakeFromStream(stream.get(), size);
1243 }
1244 
cfdata_from_skdata(sk_sp<SkData> data)1245 static SkUniqueCFRef<CFDataRef> cfdata_from_skdata(sk_sp<SkData> data) {
1246     void const * const addr = data->data();
1247     size_t const size = data->size();
1248 
1249     CFAllocatorContext ctx = {
1250         0, // CFIndex version
1251         data.release(), // void* info
1252         nullptr, // const void *(*retain)(const void *info);
1253         nullptr, // void (*release)(const void *info);
1254         nullptr, // CFStringRef (*copyDescription)(const void *info);
1255         nullptr, // void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info);
1256         nullptr, // void*(*reallocate)(void* ptr,CFIndex newsize,CFOptionFlags hint,void* info);
1257         [](void*,void* info) -> void { // void (*deallocate)(void *ptr, void *info);
1258             SkASSERT(info);
1259             ((SkData*)info)->unref();
1260         },
1261         nullptr, // CFIndex (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info);
1262     };
1263     SkUniqueCFRef<CFAllocatorRef> alloc(CFAllocatorCreate(kCFAllocatorDefault, &ctx));
1264     return SkUniqueCFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(
1265             kCFAllocatorDefault, (const UInt8 *)addr, size, alloc.get()));
1266 }
1267 
ctfont_from_skdata(sk_sp<SkData> data,int ttcIndex)1268 static SkUniqueCFRef<CTFontRef> ctfont_from_skdata(sk_sp<SkData> data, int ttcIndex) {
1269     // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available.
1270     if (ttcIndex != 0) {
1271         return nullptr;
1272     }
1273 
1274     SkUniqueCFRef<CFDataRef> cfData(cfdata_from_skdata(std::move(data)));
1275 
1276     SkUniqueCFRef<CTFontDescriptorRef> desc(
1277             CTFontManagerCreateFontDescriptorFromData(cfData.get()));
1278     if (!desc) {
1279         return nullptr;
1280     }
1281     return SkUniqueCFRef<CTFontRef>(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
1282 }
1283 
MakeFromStream(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args)1284 sk_sp<SkTypeface> SkTypeface_Mac::MakeFromStream(std::unique_ptr<SkStreamAsset> stream,
1285                                                  const SkFontArguments& args)
1286 {
1287     // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available.
1288     int ttcIndex = args.getCollectionIndex();
1289     if (ttcIndex != 0) {
1290         return nullptr;
1291     }
1292 
1293     sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate());
1294     if (!data) {
1295         return nullptr;
1296     }
1297     SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex);
1298     if (!ct) {
1299         return nullptr;
1300     }
1301 
1302     SkUniqueCFRef<CTFontRef> ctVariant;
1303     CTFontVariation ctVariation;
1304     if (args.getVariationDesignPosition().coordinateCount == 0) {
1305         ctVariant = std::move(ct);
1306     } else {
1307         SkUniqueCFRef<CFArrayRef> axes(CTFontCopyVariationAxes(ct.get()));
1308         ctVariation = ctvariation_from_SkFontArguments(ct.get(), axes.get(), args);
1309 
1310         if (ctVariation.variation) {
1311             SkUniqueCFRef<CFMutableDictionaryRef> attributes(
1312                      CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1313                                                &kCFTypeDictionaryKeyCallBacks,
1314                                                &kCFTypeDictionaryValueCallBacks));
1315             CFDictionaryAddValue(attributes.get(),
1316                                  kCTFontVariationAttribute, ctVariation.variation.get());
1317             SkUniqueCFRef<CTFontDescriptorRef> varDesc(
1318                     CTFontDescriptorCreateWithAttributes(attributes.get()));
1319             ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get()));
1320         } else {
1321             ctVariant = std::move(ct);
1322         }
1323     }
1324     if (!ctVariant) {
1325         return nullptr;
1326     }
1327 
1328     return SkTypeface_Mac::Make(std::move(ctVariant), ctVariation.opsz, std::move(stream));
1329 }
1330 
onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],int parameterCount) const1331 int SkTypeface_Mac::onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
1332                                                    int parameterCount) const
1333 {
1334     CFArrayRef ctAxes = this->getVariationAxes();
1335     if (!ctAxes) {
1336         return -1;
1337     }
1338     CFIndex axisCount = CFArrayGetCount(ctAxes);
1339 
1340     if (!parameters || parameterCount < axisCount) {
1341         return axisCount;
1342     }
1343 
1344     // Added in 10.13
1345     static CFStringRef* kCTFontVariationAxisHiddenKeyPtr =
1346             static_cast<CFStringRef*>(dlsym(RTLD_DEFAULT, "kCTFontVariationAxisHiddenKey"));
1347 
1348     for (int i = 0; i < axisCount; ++i) {
1349         CFDictionaryRef axisInfoDict;
1350         if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict, "Axis")) {
1351             return -1;
1352         }
1353 
1354         int64_t tagLong;
1355         CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
1356         if (!SkCFNumberDynamicCast(tag, &tagLong, nullptr, "Axis tag")) {
1357             return -1;
1358         }
1359 
1360         double minDouble;
1361         double maxDouble;
1362         double defDouble;
1363         CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
1364         CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
1365         CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
1366         if (!SkCFNumberDynamicCast(min, &minDouble, nullptr, "Axis min") ||
1367             !SkCFNumberDynamicCast(max, &maxDouble, nullptr, "Axis max") ||
1368             !SkCFNumberDynamicCast(def, &defDouble, nullptr, "Axis def"))
1369         {
1370             return -1;
1371         }
1372 
1373         SkFontParameters::Variation::Axis& skAxis = parameters[i];
1374         skAxis.tag = tagLong;
1375         skAxis.min = minDouble;
1376         skAxis.max = maxDouble;
1377         skAxis.def = defDouble;
1378         skAxis.setHidden(false);
1379         if (kCTFontVariationAxisHiddenKeyPtr) {
1380             CFTypeRef hidden = CFDictionaryGetValue(axisInfoDict,*kCTFontVariationAxisHiddenKeyPtr);
1381             if (hidden) {
1382                 // At least macOS 11 Big Sur Beta 4 uses CFNumberRef instead of CFBooleanRef.
1383                 // https://crbug.com/1113444
1384                 CFBooleanRef hiddenBoolean;
1385                 int hiddenInt;
1386                 if (SkCFDynamicCast(hidden, &hiddenBoolean, nullptr)) {
1387                     skAxis.setHidden(CFBooleanGetValue(hiddenBoolean));
1388                 } else if (SkCFNumberDynamicCast(hidden, &hiddenInt, nullptr, "Axis hidden")) {
1389                     skAxis.setHidden(hiddenInt);
1390                 } else {
1391                     return -1;
1392                 }
1393             }
1394         }
1395     }
1396     return axisCount;
1397 }
1398 
1399 #endif
1400