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