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