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