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