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 "SkTypes.h" // Keep this before any #ifdef ...
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 "SkAdvancedTypefaceMetrics.h"
23 #include "SkAutoMalloc.h"
24 #include "SkCGUtils.h"
25 #include "SkColorPriv.h"
26 #include "SkDescriptor.h"
27 #include "SkEndian.h"
28 #include "SkFloatingPoint.h"
29 #include "SkFontDescriptor.h"
30 #include "SkFontMgr.h"
31 #include "SkGlyph.h"
32 #include "SkMakeUnique.h"
33 #include "SkMaskGamma.h"
34 #include "SkMathPriv.h"
35 #include "SkMutex.h"
36 #include "SkOTTable_OS_2.h"
37 #include "SkOTUtils.h"
38 #include "SkOnce.h"
39 #include "SkPaint.h"
40 #include "SkPath.h"
41 #include "SkSFNTHeader.h"
42 #include "SkStream.h"
43 #include "SkString.h"
44 #include "SkTemplates.h"
45 #include "SkTypefaceCache.h"
46 #include "SkTypeface_mac.h"
47 #include "SkUtils.h"
48
49 // Experimental code to use a global lock whenever we access CG, to see if this reduces
50 // crashes in Chrome
51 #define USE_GLOBAL_MUTEX_FOR_CG_ACCESS
52
53 #ifdef USE_GLOBAL_MUTEX_FOR_CG_ACCESS
54 SK_DECLARE_STATIC_MUTEX(gCGMutex);
55 #define AUTO_CG_LOCK() SkAutoMutexAcquire amc(gCGMutex)
56 #else
57 #define AUTO_CG_LOCK()
58 #endif
59
60 // Set to make glyph bounding boxes visible.
61 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
62
63 class SkScalerContext_Mac;
64
65 struct CFSafeRelease {
operator ()CFSafeRelease66 void operator()(CFTypeRef cfTypeRef) {
67 if (cfTypeRef) {
68 CFRelease(cfTypeRef);
69 }
70 }
71 };
72 template <typename CFRef> using UniqueCFRef =
73 std::unique_ptr<skstd::remove_pointer_t<CFRef>, CFSafeRelease>;
74
make_CFString(const char str[])75 static UniqueCFRef<CFStringRef> make_CFString(const char str[]) {
76 return UniqueCFRef<CFStringRef>(CFStringCreateWithCString(nullptr, str, kCFStringEncodingUTF8));
77 }
78
79 // inline versions of these rect helpers
80
CGRectIsEmpty_inline(const CGRect & rect)81 static bool CGRectIsEmpty_inline(const CGRect& rect) {
82 return rect.size.width <= 0 || rect.size.height <= 0;
83 }
84
CGRectGetMinX_inline(const CGRect & rect)85 static CGFloat CGRectGetMinX_inline(const CGRect& rect) {
86 return rect.origin.x;
87 }
88
CGRectGetMaxX_inline(const CGRect & rect)89 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) {
90 return rect.origin.x + rect.size.width;
91 }
92
CGRectGetMinY_inline(const CGRect & rect)93 static CGFloat CGRectGetMinY_inline(const CGRect& rect) {
94 return rect.origin.y;
95 }
96
CGRectGetMaxY_inline(const CGRect & rect)97 static CGFloat CGRectGetMaxY_inline(const CGRect& rect) {
98 return rect.origin.y + rect.size.height;
99 }
100
CGRectGetWidth_inline(const CGRect & rect)101 static CGFloat CGRectGetWidth_inline(const CGRect& rect) {
102 return rect.size.width;
103 }
104
105 ///////////////////////////////////////////////////////////////////////////////
106
sk_memset_rect32(uint32_t * ptr,uint32_t value,int width,int height,size_t rowBytes)107 static void sk_memset_rect32(uint32_t* ptr, uint32_t value,
108 int width, int height, size_t rowBytes) {
109 SkASSERT(width);
110 SkASSERT(width * sizeof(uint32_t) <= rowBytes);
111
112 if (width >= 32) {
113 while (height) {
114 sk_memset32(ptr, value, width);
115 ptr = (uint32_t*)((char*)ptr + rowBytes);
116 height -= 1;
117 }
118 return;
119 }
120
121 rowBytes -= width * sizeof(uint32_t);
122
123 if (width >= 8) {
124 while (height) {
125 int w = width;
126 do {
127 *ptr++ = value; *ptr++ = value;
128 *ptr++ = value; *ptr++ = value;
129 *ptr++ = value; *ptr++ = value;
130 *ptr++ = value; *ptr++ = value;
131 w -= 8;
132 } while (w >= 8);
133 while (--w >= 0) {
134 *ptr++ = value;
135 }
136 ptr = (uint32_t*)((char*)ptr + rowBytes);
137 height -= 1;
138 }
139 } else {
140 while (height) {
141 int w = width;
142 do {
143 *ptr++ = value;
144 } while (--w > 0);
145 ptr = (uint32_t*)((char*)ptr + rowBytes);
146 height -= 1;
147 }
148 }
149 }
150
151 typedef uint32_t CGRGBPixel;
152
CGRGBPixel_getAlpha(CGRGBPixel pixel)153 static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) {
154 return pixel & 0xFF;
155 }
156
ScalarToCG(SkScalar scalar)157 static CGFloat ScalarToCG(SkScalar scalar) {
158 if (sizeof(CGFloat) == sizeof(float)) {
159 return SkScalarToFloat(scalar);
160 } else {
161 SkASSERT(sizeof(CGFloat) == sizeof(double));
162 return (CGFloat) SkScalarToDouble(scalar);
163 }
164 }
165
CGToScalar(CGFloat cgFloat)166 static SkScalar CGToScalar(CGFloat cgFloat) {
167 if (sizeof(CGFloat) == sizeof(float)) {
168 return SkFloatToScalar(cgFloat);
169 } else {
170 SkASSERT(sizeof(CGFloat) == sizeof(double));
171 return SkDoubleToScalar(cgFloat);
172 }
173 }
174
CGToFloat(CGFloat cgFloat)175 static float CGToFloat(CGFloat cgFloat) {
176 if (sizeof(CGFloat) == sizeof(float)) {
177 return cgFloat;
178 } else {
179 SkASSERT(sizeof(CGFloat) == sizeof(double));
180 return static_cast<float>(cgFloat);
181 }
182 }
183
MatrixToCGAffineTransform(const SkMatrix & matrix)184 static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix) {
185 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX]),
186 -ScalarToCG(matrix[SkMatrix::kMSkewY] ),
187 -ScalarToCG(matrix[SkMatrix::kMSkewX] ),
188 ScalarToCG(matrix[SkMatrix::kMScaleY]),
189 ScalarToCG(matrix[SkMatrix::kMTransX]),
190 ScalarToCG(matrix[SkMatrix::kMTransY]));
191 }
192
193 ///////////////////////////////////////////////////////////////////////////////
194
195 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
196
197 /**
198 * There does not appear to be a publicly accessable API for determining if lcd
199 * font smoothing will be applied if we request it. The main issue is that if
200 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0.
201 */
supports_LCD()202 static bool supports_LCD() {
203 static int gSupportsLCD = -1;
204 if (gSupportsLCD >= 0) {
205 return (bool) gSupportsLCD;
206 }
207 uint32_t rgb = 0;
208 UniqueCFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
209 UniqueCFRef<CGContextRef> cgContext(
210 CGBitmapContextCreate(&rgb, 1, 1, 8, 4, colorspace.get(), BITMAP_INFO_RGB));
211 UniqueCFRef<CTFontRef> ctFont(CTFontCreateWithName(CFSTR("Helvetica"), 16, nullptr));
212 CGContextSetShouldSmoothFonts(cgContext.get(), true);
213 CGContextSetShouldAntialias(cgContext.get(), true);
214 CGContextSetTextDrawingMode(cgContext.get(), kCGTextFill);
215 CGContextSetGrayFillColor(cgContext.get(), 1, 1);
216 CGPoint point = CGPointMake(-1, 0);
217 static const UniChar pipeChar = '|';
218 CGGlyph pipeGlyph;
219 CTFontGetGlyphsForCharacters(ctFont.get(), &pipeChar, &pipeGlyph, 1);
220 CTFontDrawGlyphs(ctFont.get(), &pipeGlyph, &point, 1, cgContext.get());
221
222 uint32_t r = (rgb >> 16) & 0xFF;
223 uint32_t g = (rgb >> 8) & 0xFF;
224 uint32_t b = (rgb >> 0) & 0xFF;
225 gSupportsLCD = (r != g || r != b);
226 return (bool) gSupportsLCD;
227 }
228
229 class Offscreen {
230 public:
Offscreen()231 Offscreen()
232 : fRGBSpace(nullptr)
233 , fCG(nullptr)
234 , fDoAA(false)
235 , fDoLCD(false)
236 {
237 fSize.set(0, 0);
238 }
239
240 CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
241 CGGlyph glyphID, size_t* rowBytesPtr, bool generateA8FromLCD);
242
243 private:
244 enum {
245 kSize = 32 * 32 * sizeof(CGRGBPixel)
246 };
247 SkAutoSMalloc<kSize> fImageStorage;
248 UniqueCFRef<CGColorSpaceRef> fRGBSpace;
249
250 // cached state
251 UniqueCFRef<CGContextRef> fCG;
252 SkISize fSize;
253 bool fDoAA;
254 bool fDoLCD;
255
RoundSize(int dimension)256 static int RoundSize(int dimension) {
257 return SkNextPow2(dimension);
258 }
259 };
260
261 ///////////////////////////////////////////////////////////////////////////////
262
find_dict_CGFloat(CFDictionaryRef dict,CFStringRef name,CGFloat * value)263 static bool find_dict_CGFloat(CFDictionaryRef dict, CFStringRef name, CGFloat* value) {
264 CFNumberRef num;
265 return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num)
266 && CFNumberIsFloatType(num)
267 && CFNumberGetValue(num, kCFNumberCGFloatType, value);
268 }
269
270 template <typename S, typename D, typename C> struct LinearInterpolater {
271 struct Mapping {
272 S src_val;
273 D dst_val;
274 };
LinearInterpolaterLinearInterpolater275 constexpr LinearInterpolater(Mapping const mapping[], int mappingCount)
276 : fMapping(mapping), fMappingCount(mappingCount) {}
277
mapLinearInterpolater278 static D map(S value, S src_min, S src_max, D dst_min, D dst_max) {
279 SkASSERT(src_min < src_max);
280 SkASSERT(dst_min <= dst_max);
281 return C()(dst_min + (((value - src_min) * (dst_max - dst_min)) / (src_max - src_min)));
282 }
283
mapLinearInterpolater284 D map(S val) const {
285 // -Inf to [0]
286 if (val < fMapping[0].src_val) {
287 return fMapping[0].dst_val;
288 }
289
290 // Linear from [i] to [i+1]
291 for (int i = 0; i < fMappingCount - 1; ++i) {
292 if (val < fMapping[i+1].src_val) {
293 return map(val, fMapping[i].src_val, fMapping[i+1].src_val,
294 fMapping[i].dst_val, fMapping[i+1].dst_val);
295 }
296 }
297
298 // From [n] to +Inf
299 // if (fcweight < Inf)
300 return fMapping[fMappingCount - 1].dst_val;
301 }
302
303 Mapping const * fMapping;
304 int fMappingCount;
305 };
306
307 struct RoundCGFloatToInt {
operator ()RoundCGFloatToInt308 int operator()(CGFloat s) { return s + 0.5; }
309 };
310 struct CGFloatIdentity {
operator ()CGFloatIdentity311 CGFloat operator()(CGFloat s) { return s; }
312 };
313
314 /** Convert the [0, 1000] CSS weight to [-1, 1] CTFontDescriptor weight (for system fonts).
315 *
316 * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the
317 * CTFont is native or created from a CGDataProvider.
318 */
fontstyle_to_ct_weight(int fontstyleWeight)319 static CGFloat fontstyle_to_ct_weight(int fontstyleWeight) {
320 using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>;
321
322 // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100.
323 // However, on this end we can't tell, so this is ignored.
324
325 /** This mapping for native fonts is determined by running the following in an .mm file
326 * #include <AppKit/AppKit>
327 * printf("{ 100, % #.2f },\n", NSFontWeightUltraLight);
328 * printf("{ 200, % #.2f },\n", NSFontWeightThin);
329 * printf("{ 300, % #.2f },\n", NSFontWeightLight);
330 * printf("{ 400, % #.2f },\n", NSFontWeightRegular);
331 * printf("{ 500, % #.2f },\n", NSFontWeightMedium);
332 * printf("{ 600, % #.2f },\n", NSFontWeightSemibold);
333 * printf("{ 700, % #.2f },\n", NSFontWeightBold);
334 * printf("{ 800, % #.2f },\n", NSFontWeightHeavy);
335 * printf("{ 900, % #.2f },\n", NSFontWeightBlack);
336 */
337 static constexpr Interpolator::Mapping nativeWeightMappings[] = {
338 { 0, -1.00 },
339 { 100, -0.80 },
340 { 200, -0.60 },
341 { 300, -0.40 },
342 { 400, 0.00 },
343 { 500, 0.23 },
344 { 600, 0.30 },
345 { 700, 0.40 },
346 { 800, 0.56 },
347 { 900, 0.62 },
348 { 1000, 1.00 },
349 };
350 static constexpr Interpolator nativeInterpolator(
351 nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings));
352
353 return nativeInterpolator.map(fontstyleWeight);
354 }
355
356
357 /** Convert the [-1, 1] CTFontDescriptor weight to [0, 1000] CSS weight.
358 *
359 * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the
360 * CTFont is native or created from a CGDataProvider.
361 */
ct_weight_to_fontstyle(CGFloat cgWeight,bool fromDataProvider)362 static int ct_weight_to_fontstyle(CGFloat cgWeight, bool fromDataProvider) {
363 using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>;
364
365 // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100.
366 // However, on this end we can't tell, so this is ignored.
367
368 /** This mapping for CGDataProvider created fonts is determined by creating font data with every
369 * weight, creating a CTFont, and asking the CTFont for its weight. See the TypefaceStyle test
370 * in tests/TypefaceTest.cpp for the code used to determine these values.
371 */
372 static constexpr Interpolator::Mapping dataProviderWeightMappings[] = {
373 { -1.00, 0 },
374 { -0.70, 100 },
375 { -0.50, 200 },
376 { -0.23, 300 },
377 { 0.00, 400 },
378 { 0.20, 500 },
379 { 0.30, 600 },
380 { 0.40, 700 },
381 { 0.60, 800 },
382 { 0.80, 900 },
383 { 1.00, 1000 },
384 };
385 static constexpr Interpolator dataProviderInterpolator(
386 dataProviderWeightMappings, SK_ARRAY_COUNT(dataProviderWeightMappings));
387
388 /** This mapping for native fonts is determined by running the following in an .mm file
389 * #include <AppKit/AppKit>
390 * printf("{ % #.2f, 100 },\n", NSFontWeightUltraLight);
391 * printf("{ % #.2f, 200 },\n", NSFontWeightThin);
392 * printf("{ % #.2f, 300 },\n", NSFontWeightLight);
393 * printf("{ % #.2f, 400 },\n", NSFontWeightRegular);
394 * printf("{ % #.2f, 500 },\n", NSFontWeightMedium);
395 * printf("{ % #.2f, 600 },\n", NSFontWeightSemibold);
396 * printf("{ % #.2f, 700 },\n", NSFontWeightBold);
397 * printf("{ % #.2f, 800 },\n", NSFontWeightHeavy);
398 * printf("{ % #.2f, 900 },\n", NSFontWeightBlack);
399 */
400 static constexpr Interpolator::Mapping nativeWeightMappings[] = {
401 { -1.00, 0 },
402 { -0.80, 100 },
403 { -0.60, 200 },
404 { -0.40, 300 },
405 { 0.00, 400 },
406 { 0.23, 500 },
407 { 0.30, 600 },
408 { 0.40, 700 },
409 { 0.56, 800 },
410 { 0.62, 900 },
411 { 1.00, 1000 },
412 };
413 static constexpr Interpolator nativeInterpolator(
414 nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings));
415
416 return fromDataProvider ? dataProviderInterpolator.map(cgWeight)
417 : nativeInterpolator.map(cgWeight);
418 }
419
420 /** Convert the [0, 10] CSS weight to [-1, 1] CTFontDescriptor width. */
fontstyle_to_ct_width(int fontstyleWidth)421 static int fontstyle_to_ct_width(int fontstyleWidth) {
422 using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>;
423
424 // Values determined by creating font data with every width, creating a CTFont,
425 // and asking the CTFont for its width. See TypefaceStyle test for basics.
426 static constexpr Interpolator::Mapping widthMappings[] = {
427 { 0, -0.5 },
428 { 10, 0.5 },
429 };
430 static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings));
431 return interpolator.map(fontstyleWidth);
432 }
433
434 /** Convert the [-1, 1] CTFontDescriptor width to [0, 10] CSS weight. */
ct_width_to_fontstyle(CGFloat cgWidth)435 static int ct_width_to_fontstyle(CGFloat cgWidth) {
436 using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>;
437
438 // Values determined by creating font data with every width, creating a CTFont,
439 // and asking the CTFont for its width. See TypefaceStyle test for basics.
440 static constexpr Interpolator::Mapping widthMappings[] = {
441 { -0.5, 0 },
442 { 0.5, 10 },
443 };
444 static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings));
445 return interpolator.map(cgWidth);
446 }
447
fontstyle_from_descriptor(CTFontDescriptorRef desc,bool fromDataProvider)448 static SkFontStyle fontstyle_from_descriptor(CTFontDescriptorRef desc, bool fromDataProvider) {
449 UniqueCFRef<CFTypeRef> fontTraits(CTFontDescriptorCopyAttribute(desc, kCTFontTraitsAttribute));
450 if (!fontTraits || CFDictionaryGetTypeID() != CFGetTypeID(fontTraits.get())) {
451 return SkFontStyle();
452 }
453 UniqueCFRef<CFDictionaryRef> fontTraitsDict(static_cast<CFDictionaryRef>(fontTraits.release()));
454
455 CGFloat weight, width, slant;
456 if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWeightTrait, &weight)) {
457 weight = 0;
458 }
459 if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWidthTrait, &width)) {
460 width = 0;
461 }
462 if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontSlantTrait, &slant)) {
463 slant = 0;
464 }
465
466 return SkFontStyle(ct_weight_to_fontstyle(weight, fromDataProvider),
467 ct_width_to_fontstyle(width),
468 slant ? SkFontStyle::kItalic_Slant
469 : SkFontStyle::kUpright_Slant);
470 }
471
472 class SkTypeface_Mac : public SkTypeface {
473 public:
SkTypeface_Mac(UniqueCFRef<CTFontRef> fontRef,UniqueCFRef<CFTypeRef> resourceRef,const SkFontStyle & fs,bool isFixedPitch,bool isLocalStream)474 SkTypeface_Mac(UniqueCFRef<CTFontRef> fontRef, UniqueCFRef<CFTypeRef> resourceRef,
475 const SkFontStyle& fs, bool isFixedPitch,
476 bool isLocalStream)
477 : SkTypeface(fs, isFixedPitch)
478 , fFontRef(std::move(fontRef))
479 , fOriginatingCFTypeRef(std::move(resourceRef))
480 , fHasColorGlyphs(
481 SkToBool(CTFontGetSymbolicTraits(fFontRef.get()) & kCTFontColorGlyphsTrait))
482 , fIsLocalStream(isLocalStream)
483 {
484 SkASSERT(fFontRef);
485 }
486
487 UniqueCFRef<CTFontRef> fFontRef;
488 UniqueCFRef<CFTypeRef> fOriginatingCFTypeRef;
489 const bool fHasColorGlyphs;
490
491 protected:
492 int onGetUPEM() const override;
493 SkStreamAsset* onOpenStream(int* ttcIndex) const override;
494 std::unique_ptr<SkFontData> onMakeFontData() const override;
495 int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
496 int coordinateCount) const override;
497 void onGetFamilyName(SkString* familyName) const override;
498 SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
499 int onGetTableTags(SkFontTableTag tags[]) const override;
500 size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
501 SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
502 const SkDescriptor*) const override;
503 void onFilterRec(SkScalerContextRec*) const override;
504 void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
505 SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
506 PerGlyphInfo, const uint32_t* glyphIDs, uint32_t glyphIDsCount) const override;
507 int onCharsToGlyphs(const void* chars, Encoding,
508 uint16_t glyphs[], int glyphCount) const override;
509 int onCountGlyphs() const override;
510
511 private:
512 bool fIsLocalStream;
513
514 typedef SkTypeface INHERITED;
515 };
516
find_by_CTFontRef(SkTypeface * cached,void * context)517 static bool find_by_CTFontRef(SkTypeface* cached, void* context) {
518 CTFontRef self = (CTFontRef)context;
519 CTFontRef other = ((SkTypeface_Mac*)cached)->fFontRef.get();
520
521 return CFEqual(self, other);
522 }
523
524 /** Creates a typeface, searching the cache if isLocalStream is false. */
create_from_CTFontRef(UniqueCFRef<CTFontRef> font,UniqueCFRef<CFTypeRef> resource,bool isLocalStream)525 static SkTypeface* create_from_CTFontRef(UniqueCFRef<CTFontRef> font,
526 UniqueCFRef<CFTypeRef> resource,
527 bool isLocalStream) {
528 SkASSERT(font);
529
530 if (!isLocalStream) {
531 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(find_by_CTFontRef, (void*)font.get());
532 if (face) {
533 return face;
534 }
535 }
536
537 UniqueCFRef<CTFontDescriptorRef> desc(CTFontCopyFontDescriptor(font.get()));
538 SkFontStyle style = fontstyle_from_descriptor(desc.get(), isLocalStream);
539 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font.get());
540 bool isFixedPitch = SkToBool(traits & kCTFontMonoSpaceTrait);
541
542 SkTypeface* face = new SkTypeface_Mac(std::move(font), std::move(resource),
543 style, isFixedPitch, isLocalStream);
544 if (!isLocalStream) {
545 SkTypefaceCache::Add(face);
546 }
547 return face;
548 }
549
550 /** Creates a typeface from a descriptor, searching the cache. */
create_from_desc(CTFontDescriptorRef desc)551 static SkTypeface* create_from_desc(CTFontDescriptorRef desc) {
552 UniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr));
553 if (!ctFont) {
554 return nullptr;
555 }
556
557 return create_from_CTFontRef(std::move(ctFont), nullptr, false);
558 }
559
create_descriptor(const char familyName[],const SkFontStyle & style)560 static UniqueCFRef<CTFontDescriptorRef> create_descriptor(const char familyName[],
561 const SkFontStyle& style) {
562 UniqueCFRef<CFMutableDictionaryRef> cfAttributes(
563 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
564 &kCFTypeDictionaryKeyCallBacks,
565 &kCFTypeDictionaryValueCallBacks));
566
567 UniqueCFRef<CFMutableDictionaryRef> cfTraits(
568 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
569 &kCFTypeDictionaryKeyCallBacks,
570 &kCFTypeDictionaryValueCallBacks));
571
572 if (!cfAttributes || !cfTraits) {
573 return nullptr;
574 }
575
576 // CTFontTraits (symbolic)
577 CTFontSymbolicTraits ctFontTraits = 0;
578 if (style.weight() >= SkFontStyle::kBold_Weight) {
579 ctFontTraits |= kCTFontBoldTrait;
580 }
581 if (style.slant() != SkFontStyle::kUpright_Slant) {
582 ctFontTraits |= kCTFontItalicTrait;
583 }
584 UniqueCFRef<CFNumberRef> cfFontTraits(
585 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits));
586 if (cfFontTraits) {
587 CFDictionaryAddValue(cfTraits.get(), kCTFontSymbolicTrait, cfFontTraits.get());
588 }
589 // CTFontTraits (weight)
590 CGFloat ctWeight = fontstyle_to_ct_weight(style.weight());
591 UniqueCFRef<CFNumberRef> cfFontWeight(
592 CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWeight));
593 if (cfFontWeight) {
594 CFDictionaryAddValue(cfTraits.get(), kCTFontWeightTrait, cfFontWeight.get());
595 }
596 // CTFontTraits (width)
597 CGFloat ctWidth = fontstyle_to_ct_width(style.weight());
598 UniqueCFRef<CFNumberRef> cfFontWidth(
599 CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWidth));
600 if (cfFontWidth) {
601 CFDictionaryAddValue(cfTraits.get(), kCTFontWidthTrait, cfFontWidth.get());
602 }
603 // CTFontTraits (slant)
604 CGFloat ctSlant = style.slant() == SkFontStyle::kUpright_Slant ? 0 : 1;
605 UniqueCFRef<CFNumberRef> cfFontSlant(
606 CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctSlant));
607 if (cfFontSlant) {
608 CFDictionaryAddValue(cfTraits.get(), kCTFontSlantTrait, cfFontSlant.get());
609 }
610 // CTFontTraits
611 CFDictionaryAddValue(cfAttributes.get(), kCTFontTraitsAttribute, cfTraits.get());
612
613 // CTFontFamilyName
614 if (familyName) {
615 UniqueCFRef<CFStringRef> cfFontName = make_CFString(familyName);
616 if (cfFontName) {
617 CFDictionaryAddValue(cfAttributes.get(), kCTFontFamilyNameAttribute, cfFontName.get());
618 }
619 }
620
621 return UniqueCFRef<CTFontDescriptorRef>(
622 CTFontDescriptorCreateWithAttributes(cfAttributes.get()));
623 }
624
625 /** Creates a typeface from a name, searching the cache. */
create_from_name(const char familyName[],const SkFontStyle & style)626 static SkTypeface* create_from_name(const char familyName[], const SkFontStyle& style) {
627 UniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
628 if (!desc) {
629 return nullptr;
630 }
631 return create_from_desc(desc.get());
632 }
633
634 ///////////////////////////////////////////////////////////////////////////////
635
636 extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face);
SkTypeface_GetCTFontRef(const SkTypeface * face)637 CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) {
638 const SkTypeface_Mac* macface = (const SkTypeface_Mac*)face;
639 return macface ? macface->fFontRef.get() : nullptr;
640 }
641
642 /* This function is visible on the outside. It first searches the cache, and if
643 * not found, returns a new entry (after adding it to the cache).
644 */
SkCreateTypefaceFromCTFont(CTFontRef font,CFTypeRef resource)645 SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef font, CFTypeRef resource) {
646 CFRetain(font);
647 if (resource) {
648 CFRetain(resource);
649 }
650 return create_from_CTFontRef(UniqueCFRef<CTFontRef>(font),
651 UniqueCFRef<CFTypeRef>(resource),
652 false);
653 }
654
map_css_names(const char * name)655 static const char* map_css_names(const char* name) {
656 static const struct {
657 const char* fFrom; // name the caller specified
658 const char* fTo; // "canonical" name we map to
659 } gPairs[] = {
660 { "sans-serif", "Helvetica" },
661 { "serif", "Times" },
662 { "monospace", "Courier" }
663 };
664
665 for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
666 if (strcmp(name, gPairs[i].fFrom) == 0) {
667 return gPairs[i].fTo;
668 }
669 }
670 return name; // no change
671 }
672
673 ///////////////////////////////////////////////////////////////////////////////
674
675 class SkScalerContext_Mac : public SkScalerContext {
676 public:
677 SkScalerContext_Mac(sk_sp<SkTypeface_Mac>, const SkScalerContextEffects&, const SkDescriptor*);
678
679 protected:
680 unsigned generateGlyphCount(void) override;
681 uint16_t generateCharToGlyph(SkUnichar uni) override;
682 void generateAdvance(SkGlyph* glyph) override;
683 void generateMetrics(SkGlyph* glyph) override;
684 void generateImage(const SkGlyph& glyph) override;
685 void generatePath(SkGlyphID glyph, SkPath* path) override;
686 void generateFontMetrics(SkPaint::FontMetrics*) override;
687
688 private:
689 static void CTPathElement(void *info, const CGPathElement *element);
690
691 /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */
692 void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const;
693
694 Offscreen fOffscreen;
695
696 /** Unrotated variant of fCTFont.
697 *
698 * In 10.10.1 CTFontGetAdvancesForGlyphs applies the font transform to the width of the
699 * advances, but always sets the height to 0. This font is used to get the advances of the
700 * unrotated glyph, and then the rotation is applied separately.
701 *
702 * CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise.
703 * This makes kCTFontOrientationDefault dangerous, because the metrics from
704 * kCTFontOrientationHorizontal are in a different space from kCTFontOrientationVertical.
705 * With kCTFontOrientationVertical the advances must be unrotated.
706 *
707 * Sometimes, creating a copy of a CTFont with the same size but different trasform will select
708 * different underlying font data. As a result, avoid ever creating more than one CTFont per
709 * SkScalerContext to ensure that only one CTFont is used.
710 *
711 * As a result of the above (and other constraints) this font contains the size, but not the
712 * transform. The transform must always be applied separately.
713 */
714 UniqueCFRef<CTFontRef> fCTFont;
715
716 /** The transform without the font size. */
717 CGAffineTransform fTransform;
718 CGAffineTransform fInvTransform;
719
720 UniqueCFRef<CGFontRef> fCGFont;
721 uint16_t fGlyphCount;
722 const bool fDoSubPosition;
723 const bool fVertical;
724
725 friend class Offscreen;
726
727 typedef SkScalerContext INHERITED;
728 };
729
730 // CTFontCreateCopyWithAttributes or CTFontCreateCopyWithSymbolicTraits cannot be used on 10.10
731 // and later, as they will return different underlying fonts depending on the size requested.
732 // It is not possible to use descriptors with CTFontCreateWithFontDescriptor, since that does not
733 // work with non-system fonts. As a result, create the strike specific CTFonts from the underlying
734 // CGFont.
ctfont_create_exact_copy(CTFontRef baseFont,CGFloat textSize,const CGAffineTransform * transform)735 static UniqueCFRef<CTFontRef> ctfont_create_exact_copy(CTFontRef baseFont, CGFloat textSize,
736 const CGAffineTransform* transform)
737 {
738 UniqueCFRef<CGFontRef> baseCGFont(CTFontCopyGraphicsFont(baseFont, nullptr));
739
740 // The last parameter (CTFontDescriptorRef attributes) *must* be nullptr.
741 // If non-nullptr then with fonts with variation axes, the copy will fail in
742 // CGFontVariationFromDictCallback when it assumes kCGFontVariationAxisName is CFNumberRef
743 // which it quite obviously is not.
744
745 // Because we cannot setup the CTFont descriptor to match, the same restriction applies here
746 // as other uses of CTFontCreateWithGraphicsFont which is that such CTFonts should not escape
747 // the scaler context, since they aren't 'normal'.
748 return UniqueCFRef<CTFontRef>(
749 CTFontCreateWithGraphicsFont(baseCGFont.get(), textSize, transform, nullptr));
750 }
751
SkScalerContext_Mac(sk_sp<SkTypeface_Mac> typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc)752 SkScalerContext_Mac::SkScalerContext_Mac(sk_sp<SkTypeface_Mac> typeface,
753 const SkScalerContextEffects& effects,
754 const SkDescriptor* desc)
755 : INHERITED(std::move(typeface), effects, desc)
756 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
757 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag))
758
759 {
760 AUTO_CG_LOCK();
761
762 CTFontRef ctFont = static_cast<SkTypeface_Mac*>(this->getTypeface())->fFontRef.get();
763 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
764 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
765 fGlyphCount = SkToU16(numGlyphs);
766
767 // CT on (at least) 10.9 will size color glyphs down from the requested size, but not up.
768 // As a result, it is necessary to know the actual device size and request that.
769 SkVector scale;
770 SkMatrix skTransform;
771 bool invertible = fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale,
772 &scale, &skTransform, nullptr, nullptr, nullptr);
773 fTransform = MatrixToCGAffineTransform(skTransform);
774 // CGAffineTransformInvert documents that if the transform is non-invertible it will return the
775 // passed transform unchanged. It does so, but then also prints a message to stdout. Avoid this.
776 if (invertible) {
777 fInvTransform = CGAffineTransformInvert(fTransform);
778 } else {
779 fInvTransform = fTransform;
780 }
781
782 // The transform contains everything except the requested text size.
783 // Some properties, like 'trak', are based on the text size (before applying the matrix).
784 CGFloat textSize = ScalarToCG(scale.y());
785 fCTFont = ctfont_create_exact_copy(ctFont, textSize, nullptr);
786 fCGFont.reset(CTFontCopyGraphicsFont(fCTFont.get(), nullptr));
787 }
788
getCG(const SkScalerContext_Mac & context,const SkGlyph & glyph,CGGlyph glyphID,size_t * rowBytesPtr,bool generateA8FromLCD)789 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
790 CGGlyph glyphID, size_t* rowBytesPtr,
791 bool generateA8FromLCD) {
792 if (!fRGBSpace) {
793 //It doesn't appear to matter what color space is specified.
794 //Regular blends and antialiased text are always (s*a + d*(1-a))
795 //and smoothed text is always g=2.0.
796 fRGBSpace.reset(CGColorSpaceCreateDeviceRGB());
797 }
798
799 // default to kBW_Format
800 bool doAA = false;
801 bool doLCD = false;
802
803 if (SkMask::kBW_Format != glyph.fMaskFormat) {
804 doLCD = true;
805 doAA = true;
806 }
807
808 // FIXME: lcd smoothed un-hinted rasterization unsupported.
809 if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) {
810 doLCD = false;
811 doAA = true;
812 }
813
814 // If this font might have color glyphs, disable LCD as there's no way to support it.
815 // CoreText doesn't tell us which format it ended up using, so we can't detect it.
816 // A8 will end up black on transparent, but TODO: we can detect gray and set to A8.
817 if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
818 doLCD = false;
819 }
820
821 size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
822 if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
823 if (fSize.fWidth < glyph.fWidth) {
824 fSize.fWidth = RoundSize(glyph.fWidth);
825 }
826 if (fSize.fHeight < glyph.fHeight) {
827 fSize.fHeight = RoundSize(glyph.fHeight);
828 }
829
830 rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
831 void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
832 const CGImageAlphaInfo alpha = (SkMask::kARGB32_Format == glyph.fMaskFormat)
833 ? kCGImageAlphaPremultipliedFirst
834 : kCGImageAlphaNoneSkipFirst;
835 const CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | alpha;
836 fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
837 rowBytes, fRGBSpace.get(), bitmapInfo));
838
839 // Skia handles quantization and subpixel positioning,
840 // so disable quantization and enabe subpixel positioning in CG.
841 CGContextSetAllowsFontSubpixelQuantization(fCG.get(), false);
842 CGContextSetShouldSubpixelQuantizeFonts(fCG.get(), false);
843
844 // Because CG always draws from the horizontal baseline,
845 // if there is a non-integral translation from the horizontal origin to the vertical origin,
846 // then CG cannot draw the glyph in the correct location without subpixel positioning.
847 CGContextSetAllowsFontSubpixelPositioning(fCG.get(), true);
848 CGContextSetShouldSubpixelPositionFonts(fCG.get(), true);
849
850 CGContextSetTextDrawingMode(fCG.get(), kCGTextFill);
851
852 // Draw black on white to create mask. (Special path exists to speed this up in CG.)
853 CGContextSetGrayFillColor(fCG.get(), 0.0f, 1.0f);
854
855 // force our checks below to happen
856 fDoAA = !doAA;
857 fDoLCD = !doLCD;
858
859 CGContextSetTextMatrix(fCG.get(), context.fTransform);
860 }
861
862 if (fDoAA != doAA) {
863 CGContextSetShouldAntialias(fCG.get(), doAA);
864 fDoAA = doAA;
865 }
866 if (fDoLCD != doLCD) {
867 CGContextSetShouldSmoothFonts(fCG.get(), doLCD);
868 fDoLCD = doLCD;
869 }
870
871 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
872 // skip rows based on the glyph's height
873 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
874
875 // Erase to white (or transparent black if it's a color glyph, to not composite against white).
876 uint32_t bgColor = (SkMask::kARGB32_Format != glyph.fMaskFormat) ? 0xFFFFFFFF : 0x00000000;
877 sk_memset_rect32(image, bgColor, glyph.fWidth, glyph.fHeight, rowBytes);
878
879 float subX = 0;
880 float subY = 0;
881 if (context.fDoSubPosition) {
882 subX = SkFixedToFloat(glyph.getSubXFixed());
883 subY = SkFixedToFloat(glyph.getSubYFixed());
884 }
885
886 // CoreText and CoreGraphics always draw using the horizontal baseline origin.
887 if (context.fVertical) {
888 SkPoint offset;
889 context.getVerticalOffset(glyphID, &offset);
890 subX += offset.fX;
891 subY += offset.fY;
892 }
893
894 CGPoint point = CGPointMake(-glyph.fLeft + subX, glyph.fTop + glyph.fHeight - subY);
895 // Prior to 10.10, CTFontDrawGlyphs acted like CGContextShowGlyphsAtPositions and took
896 // 'positions' which are in text space. The glyph location (in device space) must be
897 // mapped into text space, so that CG can convert it back into device space.
898 // In 10.10.1, this is handled directly in CTFontDrawGlyphs.
899 //
900 // However, in 10.10.2 color glyphs no longer rotate based on the font transform.
901 // So always make the font transform identity and place the transform on the context.
902 point = CGPointApplyAffineTransform(point, context.fInvTransform);
903
904 CTFontDrawGlyphs(context.fCTFont.get(), &glyphID, &point, 1, fCG.get());
905
906 SkASSERT(rowBytesPtr);
907 *rowBytesPtr = rowBytes;
908 return image;
909 }
910
getVerticalOffset(CGGlyph glyphID,SkPoint * offset) const911 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const {
912 // CTFontGetVerticalTranslationsForGlyphs produces cgVertOffset in CG units (pixels, y up).
913 CGSize cgVertOffset;
914 CTFontGetVerticalTranslationsForGlyphs(fCTFont.get(), &glyphID, &cgVertOffset, 1);
915 cgVertOffset = CGSizeApplyAffineTransform(cgVertOffset, fTransform);
916 SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) };
917 // From CG units (pixels, y up) to SkGlyph units (pixels, y down).
918 skVertOffset.fY = -skVertOffset.fY;
919 *offset = skVertOffset;
920 }
921
generateGlyphCount(void)922 unsigned SkScalerContext_Mac::generateGlyphCount(void) {
923 return fGlyphCount;
924 }
925
generateCharToGlyph(SkUnichar uni)926 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) {
927 AUTO_CG_LOCK();
928
929 CGGlyph cgGlyph[2];
930 UniChar theChar[2]; // UniChar is a UTF-16 16-bit code unit.
931
932 // Get the glyph
933 size_t numUniChar = SkUTF16_FromUnichar(uni, theChar);
934 SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t));
935
936 // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
937 // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
938 // It is documented that if a mapping is unavailable, the glyph will be set to 0.
939 CTFontGetGlyphsForCharacters(fCTFont.get(), theChar, cgGlyph, numUniChar);
940 return cgGlyph[0];
941 }
942
generateAdvance(SkGlyph * glyph)943 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
944 this->generateMetrics(glyph);
945 }
946
generateMetrics(SkGlyph * glyph)947 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
948 AUTO_CG_LOCK();
949
950 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID();
951 glyph->zeroMetrics();
952
953 // The following block produces cgAdvance in CG units (pixels, y up).
954 CGSize cgAdvance;
955 if (fVertical) {
956 CTFontGetAdvancesForGlyphs(fCTFont.get(), kCTFontOrientationVertical,
957 &cgGlyph, &cgAdvance, 1);
958 // Vertical advances are returned as widths instead of heights.
959 SkTSwap(cgAdvance.height, cgAdvance.width);
960 cgAdvance.height = -cgAdvance.height;
961 } else {
962 CTFontGetAdvancesForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal,
963 &cgGlyph, &cgAdvance, 1);
964 }
965 cgAdvance = CGSizeApplyAffineTransform(cgAdvance, fTransform);
966 glyph->fAdvanceX = CGToFloat(cgAdvance.width);
967 glyph->fAdvanceY = -CGToFloat(cgAdvance.height);
968
969 // The following produces skBounds in SkGlyph units (pixels, y down),
970 // or returns early if skBounds would be empty.
971 SkRect skBounds;
972
973 // Glyphs are always drawn from the horizontal origin. The caller must manually use the result
974 // of CTFontGetVerticalTranslationsForGlyphs to calculate where to draw the glyph for vertical
975 // glyphs. As a result, always get the horizontal bounds of a glyph and translate it if the
976 // glyph is vertical. This avoids any diagreement between the various means of retrieving
977 // vertical metrics.
978 {
979 // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up).
980 CGRect cgBounds;
981 CTFontGetBoundingRectsForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal,
982 &cgGlyph, &cgBounds, 1);
983 cgBounds = CGRectApplyAffineTransform(cgBounds, fTransform);
984
985 // BUG?
986 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when
987 // it should be empty. So, if we see a zero-advance, we check if it has an
988 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance
989 // is rare, so we won't incur a big performance cost for this extra check.
990 if (0 == cgAdvance.width && 0 == cgAdvance.height) {
991 UniqueCFRef<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph, nullptr));
992 if (!path || CGPathIsEmpty(path.get())) {
993 return;
994 }
995 }
996
997 if (CGRectIsEmpty_inline(cgBounds)) {
998 return;
999 }
1000
1001 // Convert cgBounds to SkGlyph units (pixels, y down).
1002 skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height,
1003 cgBounds.size.width, cgBounds.size.height);
1004 }
1005
1006 if (fVertical) {
1007 // Due to possible vertical bounds bugs and simplicity, skBounds is the horizontal bounds.
1008 // Convert these horizontal bounds into vertical bounds.
1009 SkPoint offset;
1010 this->getVerticalOffset(cgGlyph, &offset);
1011 skBounds.offset(offset);
1012 }
1013
1014 // Currently the bounds are based on being rendered at (0,0).
1015 // The top left must not move, since that is the base from which subpixel positioning is offset.
1016 if (fDoSubPosition) {
1017 skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed());
1018 skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed());
1019 }
1020
1021 SkIRect skIBounds;
1022 skBounds.roundOut(&skIBounds);
1023 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
1024 // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
1025 // is not currently known, as CG dilates the outlines by some percentage.
1026 // Note that if this context is A8 and not back-forming from LCD, there is no need to outset.
1027 skIBounds.outset(1, 1);
1028 glyph->fLeft = SkToS16(skIBounds.fLeft);
1029 glyph->fTop = SkToS16(skIBounds.fTop);
1030 glyph->fWidth = SkToU16(skIBounds.width());
1031 glyph->fHeight = SkToU16(skIBounds.height());
1032 }
1033
1034 #include "SkColorPriv.h"
1035
build_power_table(uint8_t table[])1036 static void build_power_table(uint8_t table[]) {
1037 for (int i = 0; i < 256; i++) {
1038 float x = i / 255.f;
1039 int xx = SkScalarRoundToInt(x * x * 255);
1040 table[i] = SkToU8(xx);
1041 }
1042 }
1043
1044 /**
1045 * This will invert the gamma applied by CoreGraphics, so we can get linear
1046 * values.
1047 *
1048 * CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value.
1049 * The color space used does not appear to affect this choice.
1050 */
getInverseGammaTableCoreGraphicSmoothing()1051 static const uint8_t* getInverseGammaTableCoreGraphicSmoothing() {
1052 static bool gInited;
1053 static uint8_t gTableCoreGraphicsSmoothing[256];
1054 if (!gInited) {
1055 build_power_table(gTableCoreGraphicsSmoothing);
1056 gInited = true;
1057 }
1058 return gTableCoreGraphicsSmoothing;
1059 }
1060
cgpixels_to_bits(uint8_t dst[],const CGRGBPixel src[],int count)1061 static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
1062 while (count > 0) {
1063 uint8_t mask = 0;
1064 for (int i = 7; i >= 0; --i) {
1065 mask |= ((CGRGBPixel_getAlpha(*src++) >> 7) ^ 0x1) << i;
1066 if (0 == --count) {
1067 break;
1068 }
1069 }
1070 *dst++ = mask;
1071 }
1072 }
1073
1074 template<bool APPLY_PREBLEND>
rgb_to_a8(CGRGBPixel rgb,const uint8_t * table8)1075 static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) {
1076 U8CPU r = 0xFF - ((rgb >> 16) & 0xFF);
1077 U8CPU g = 0xFF - ((rgb >> 8) & 0xFF);
1078 U8CPU b = 0xFF - ((rgb >> 0) & 0xFF);
1079 U8CPU lum = sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1080 #if SK_SHOW_TEXT_BLIT_COVERAGE
1081 lum = SkTMax(lum, (U8CPU)0x30);
1082 #endif
1083 return lum;
1084 }
1085 template<bool APPLY_PREBLEND>
rgb_to_a8(const CGRGBPixel * SK_RESTRICT cgPixels,size_t cgRowBytes,const SkGlyph & glyph,const uint8_t * table8)1086 static void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes,
1087 const SkGlyph& glyph, const uint8_t* table8) {
1088 const int width = glyph.fWidth;
1089 size_t dstRB = glyph.rowBytes();
1090 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
1091
1092 for (int y = 0; y < glyph.fHeight; y++) {
1093 for (int i = 0; i < width; ++i) {
1094 dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8);
1095 }
1096 cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes);
1097 dst = SkTAddOffset<uint8_t>(dst, dstRB);
1098 }
1099 }
1100
1101 template<bool APPLY_PREBLEND>
rgb_to_lcd16(CGRGBPixel rgb,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1102 static inline uint16_t rgb_to_lcd16(CGRGBPixel rgb, const uint8_t* tableR,
1103 const uint8_t* tableG,
1104 const uint8_t* tableB) {
1105 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 16) & 0xFF), tableR);
1106 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 8) & 0xFF), tableG);
1107 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 0) & 0xFF), tableB);
1108 #if SK_SHOW_TEXT_BLIT_COVERAGE
1109 r = SkTMax(r, (U8CPU)0x30);
1110 g = SkTMax(g, (U8CPU)0x30);
1111 b = SkTMax(b, (U8CPU)0x30);
1112 #endif
1113 return SkPack888ToRGB16(r, g, b);
1114 }
1115 template<bool APPLY_PREBLEND>
rgb_to_lcd16(const CGRGBPixel * SK_RESTRICT cgPixels,size_t cgRowBytes,const SkGlyph & glyph,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1116 static void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph,
1117 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1118 const int width = glyph.fWidth;
1119 size_t dstRB = glyph.rowBytes();
1120 uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage;
1121
1122 for (int y = 0; y < glyph.fHeight; y++) {
1123 for (int i = 0; i < width; i++) {
1124 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
1125 }
1126 cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes);
1127 dst = SkTAddOffset<uint16_t>(dst, dstRB);
1128 }
1129 }
1130
cgpixels_to_pmcolor(CGRGBPixel rgb)1131 static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb) {
1132 U8CPU a = (rgb >> 24) & 0xFF;
1133 U8CPU r = (rgb >> 16) & 0xFF;
1134 U8CPU g = (rgb >> 8) & 0xFF;
1135 U8CPU b = (rgb >> 0) & 0xFF;
1136 #if SK_SHOW_TEXT_BLIT_COVERAGE
1137 a = SkTMax(a, (U8CPU)0x30);
1138 #endif
1139 return SkPackARGB32(a, r, g, b);
1140 }
1141
generateImage(const SkGlyph & glyph)1142 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
1143 CGGlyph cgGlyph = SkTo<CGGlyph>(glyph.getGlyphID());
1144
1145 // FIXME: lcd smoothed un-hinted rasterization unsupported.
1146 bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting;
1147
1148 // Draw the glyph
1149 size_t cgRowBytes;
1150 CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, generateA8FromLCD);
1151 if (cgPixels == nullptr) {
1152 return;
1153 }
1154
1155 // Fix the glyph
1156 if ((glyph.fMaskFormat == SkMask::kLCD16_Format) ||
1157 (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD))
1158 {
1159 const uint8_t* table = getInverseGammaTableCoreGraphicSmoothing();
1160
1161 //Note that the following cannot really be integrated into the
1162 //pre-blend, since we may not be applying the pre-blend; when we aren't
1163 //applying the pre-blend it means that a filter wants linear anyway.
1164 //Other code may also be applying the pre-blend, so we'd need another
1165 //one with this and one without.
1166 CGRGBPixel* addr = cgPixels;
1167 for (int y = 0; y < glyph.fHeight; ++y) {
1168 for (int x = 0; x < glyph.fWidth; ++x) {
1169 int r = (addr[x] >> 16) & 0xFF;
1170 int g = (addr[x] >> 8) & 0xFF;
1171 int b = (addr[x] >> 0) & 0xFF;
1172 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1173 }
1174 addr = SkTAddOffset<CGRGBPixel>(addr, cgRowBytes);
1175 }
1176 }
1177
1178 // Convert glyph to mask
1179 switch (glyph.fMaskFormat) {
1180 case SkMask::kLCD16_Format: {
1181 if (fPreBlend.isApplicable()) {
1182 rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph,
1183 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1184 } else {
1185 rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph,
1186 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1187 }
1188 } break;
1189 case SkMask::kA8_Format: {
1190 if (fPreBlend.isApplicable()) {
1191 rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1192 } else {
1193 rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1194 }
1195 } break;
1196 case SkMask::kBW_Format: {
1197 const int width = glyph.fWidth;
1198 size_t dstRB = glyph.rowBytes();
1199 uint8_t* dst = (uint8_t*)glyph.fImage;
1200 for (int y = 0; y < glyph.fHeight; y++) {
1201 cgpixels_to_bits(dst, cgPixels, width);
1202 cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes);
1203 dst = SkTAddOffset<uint8_t>(dst, dstRB);
1204 }
1205 } break;
1206 case SkMask::kARGB32_Format: {
1207 const int width = glyph.fWidth;
1208 size_t dstRB = glyph.rowBytes();
1209 SkPMColor* dst = (SkPMColor*)glyph.fImage;
1210 for (int y = 0; y < glyph.fHeight; y++) {
1211 for (int x = 0; x < width; ++x) {
1212 dst[x] = cgpixels_to_pmcolor(cgPixels[x]);
1213 }
1214 cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes);
1215 dst = SkTAddOffset<SkPMColor>(dst, dstRB);
1216 }
1217 } break;
1218 default:
1219 SkDEBUGFAIL("unexpected mask format");
1220 break;
1221 }
1222 }
1223
1224 /*
1225 * Our subpixel resolution is only 2 bits in each direction, so a scale of 4
1226 * seems sufficient, and possibly even correct, to allow the hinted outline
1227 * to be subpixel positioned.
1228 */
1229 #define kScaleForSubPixelPositionHinting (4.0f)
1230
generatePath(SkGlyphID glyph,SkPath * path)1231 void SkScalerContext_Mac::generatePath(SkGlyphID glyph, SkPath* path) {
1232 AUTO_CG_LOCK();
1233
1234 SkScalar scaleX = SK_Scalar1;
1235 SkScalar scaleY = SK_Scalar1;
1236
1237 CGAffineTransform xform = fTransform;
1238 /*
1239 * For subpixel positioning, we want to return an unhinted outline, so it
1240 * can be positioned nicely at fractional offsets. However, we special-case
1241 * if the baseline of the (horizontal) text is axis-aligned. In those cases
1242 * we want to retain hinting in the direction orthogonal to the baseline.
1243 * e.g. for horizontal baseline, we want to retain hinting in Y.
1244 * The way we remove hinting is to scale the font by some value (4) in that
1245 * direction, ask for the path, and then scale the path back down.
1246 */
1247 if (fDoSubPosition) {
1248 // start out by assuming that we want no hining in X and Y
1249 scaleX = scaleY = kScaleForSubPixelPositionHinting;
1250 // now see if we need to restore hinting for axis-aligned baselines
1251 switch (this->computeAxisAlignmentForHText()) {
1252 case kX_SkAxisAlignment:
1253 scaleY = SK_Scalar1; // want hinting in the Y direction
1254 break;
1255 case kY_SkAxisAlignment:
1256 scaleX = SK_Scalar1; // want hinting in the X direction
1257 break;
1258 default:
1259 break;
1260 }
1261
1262 CGAffineTransform scale(CGAffineTransformMakeScale(ScalarToCG(scaleX), ScalarToCG(scaleY)));
1263 xform = CGAffineTransformConcat(fTransform, scale);
1264 }
1265
1266 CGGlyph cgGlyph = SkTo<CGGlyph>(glyph);
1267 UniqueCFRef<CGPathRef> cgPath(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph, &xform));
1268
1269 path->reset();
1270 if (cgPath != nullptr) {
1271 CGPathApply(cgPath.get(), path, SkScalerContext_Mac::CTPathElement);
1272 }
1273
1274 if (fDoSubPosition) {
1275 SkMatrix m;
1276 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY));
1277 path->transform(m);
1278 }
1279 if (fVertical) {
1280 SkPoint offset;
1281 getVerticalOffset(cgGlyph, &offset);
1282 path->offset(offset.fX, offset.fY);
1283 }
1284 }
1285
generateFontMetrics(SkPaint::FontMetrics * metrics)1286 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* metrics) {
1287 if (nullptr == metrics) {
1288 return;
1289 }
1290
1291 AUTO_CG_LOCK();
1292
1293 CGRect theBounds = CTFontGetBoundingBox(fCTFont.get());
1294
1295 metrics->fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds));
1296 metrics->fAscent = CGToScalar(-CTFontGetAscent(fCTFont.get()));
1297 metrics->fDescent = CGToScalar( CTFontGetDescent(fCTFont.get()));
1298 metrics->fBottom = CGToScalar(-CGRectGetMinY_inline(theBounds));
1299 metrics->fLeading = CGToScalar( CTFontGetLeading(fCTFont.get()));
1300 metrics->fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds));
1301 metrics->fXMin = CGToScalar( CGRectGetMinX_inline(theBounds));
1302 metrics->fXMax = CGToScalar( CGRectGetMaxX_inline(theBounds));
1303 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
1304 metrics->fXHeight = CGToScalar( CTFontGetXHeight(fCTFont.get()));
1305 metrics->fCapHeight = CGToScalar( CTFontGetCapHeight(fCTFont.get()));
1306 metrics->fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont.get()));
1307 metrics->fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont.get()));
1308
1309 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag;
1310 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
1311
1312 // See https://bugs.chromium.org/p/skia/issues/detail?id=6203
1313 // At least on 10.12.3 with memory based fonts the x-height is always 0.6666 of the ascent and
1314 // the cap-height is always 0.8888 of the ascent. It appears that the values from the 'OS/2'
1315 // table are read, but then overwritten if the font is not a system font. As a result, if there
1316 // is a valid 'OS/2' table available use the values from the table if they aren't too strange.
1317 struct OS2HeightMetrics {
1318 SK_OT_SHORT sxHeight;
1319 SK_OT_SHORT sCapHeight;
1320 } heights;
1321 size_t bytesRead = this->getTypeface()->getTableData(
1322 SkTEndian_SwapBE32(SkOTTableOS2::TAG), offsetof(SkOTTableOS2, version.v2.sxHeight),
1323 sizeof(heights), &heights);
1324 if (bytesRead == sizeof(heights)) {
1325 // 'fontSize' is correct because the entire resolved size is set by the constructor.
1326 CGFloat fontSize = CTFontGetSize(this->fCTFont.get());
1327 unsigned upem = CTFontGetUnitsPerEm(this->fCTFont.get());
1328 unsigned maxSaneHeight = upem * 2;
1329 uint16_t xHeight = SkEndian_SwapBE16(heights.sxHeight);
1330 if (xHeight && xHeight < maxSaneHeight) {
1331 metrics->fXHeight = CGToScalar(xHeight * fontSize / upem);
1332 }
1333 uint16_t capHeight = SkEndian_SwapBE16(heights.sCapHeight);
1334 if (capHeight && capHeight < maxSaneHeight) {
1335 metrics->fCapHeight = CGToScalar(capHeight * fontSize / upem);
1336 }
1337 }
1338 }
1339
CTPathElement(void * info,const CGPathElement * element)1340 void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) {
1341 SkPath* skPath = (SkPath*)info;
1342
1343 // Process the path element
1344 switch (element->type) {
1345 case kCGPathElementMoveToPoint:
1346 skPath->moveTo(element->points[0].x, -element->points[0].y);
1347 break;
1348
1349 case kCGPathElementAddLineToPoint:
1350 skPath->lineTo(element->points[0].x, -element->points[0].y);
1351 break;
1352
1353 case kCGPathElementAddQuadCurveToPoint:
1354 skPath->quadTo(element->points[0].x, -element->points[0].y,
1355 element->points[1].x, -element->points[1].y);
1356 break;
1357
1358 case kCGPathElementAddCurveToPoint:
1359 skPath->cubicTo(element->points[0].x, -element->points[0].y,
1360 element->points[1].x, -element->points[1].y,
1361 element->points[2].x, -element->points[2].y);
1362 break;
1363
1364 case kCGPathElementCloseSubpath:
1365 skPath->close();
1366 break;
1367
1368 default:
1369 SkDEBUGFAIL("Unknown path element!");
1370 break;
1371 }
1372 }
1373
1374
1375 ///////////////////////////////////////////////////////////////////////////////
1376
1377 // Returns nullptr on failure
1378 // Call must still manage its ownership of provider
create_from_dataProvider(UniqueCFRef<CGDataProviderRef> provider,int ttcIndex)1379 static SkTypeface* create_from_dataProvider(UniqueCFRef<CGDataProviderRef> provider, int ttcIndex) {
1380 if (ttcIndex != 0) {
1381 return nullptr;
1382 }
1383 UniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
1384 if (!cg) {
1385 return nullptr;
1386 }
1387 UniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg.get(), 0, nullptr, nullptr));
1388 if (!ct) {
1389 return nullptr;
1390 }
1391 return create_from_CTFontRef(std::move(ct), nullptr, true);
1392 }
1393
1394 // Web fonts added to the CTFont registry do not return their character set.
1395 // Iterate through the font in this case. The existing caller caches the result,
1396 // so the performance impact isn't too bad.
populate_glyph_to_unicode_slow(CTFontRef ctFont,CFIndex glyphCount,SkTDArray<SkUnichar> * glyphToUnicode)1397 static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
1398 SkTDArray<SkUnichar>* glyphToUnicode) {
1399 glyphToUnicode->setCount(SkToInt(glyphCount));
1400 SkUnichar* out = glyphToUnicode->begin();
1401 sk_bzero(out, glyphCount * sizeof(SkUnichar));
1402 UniChar unichar = 0;
1403 while (glyphCount > 0) {
1404 CGGlyph glyph;
1405 if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1406 out[glyph] = unichar;
1407 --glyphCount;
1408 }
1409 if (++unichar == 0) {
1410 break;
1411 }
1412 }
1413 }
1414
1415 // Construct Glyph to Unicode table.
1416 // Unicode code points that require conjugate pairs in utf16 are not
1417 // supported.
populate_glyph_to_unicode(CTFontRef ctFont,CFIndex glyphCount,SkTDArray<SkUnichar> * glyphToUnicode)1418 static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
1419 SkTDArray<SkUnichar>* glyphToUnicode) {
1420 UniqueCFRef<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
1421 if (!charSet) {
1422 populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
1423 return;
1424 }
1425
1426 UniqueCFRef<CFDataRef> bitmap(CFCharacterSetCreateBitmapRepresentation(nullptr, charSet.get()));
1427 if (!bitmap) {
1428 return;
1429 }
1430 CFIndex length = CFDataGetLength(bitmap.get());
1431 if (!length) {
1432 return;
1433 }
1434 if (length > 8192) {
1435 // TODO: Add support for Unicode above 0xFFFF
1436 // Consider only the BMP portion of the Unicode character points.
1437 // The bitmap may contain other planes, up to plane 16.
1438 // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html
1439 length = 8192;
1440 }
1441 const UInt8* bits = CFDataGetBytePtr(bitmap.get());
1442 glyphToUnicode->setCount(SkToInt(glyphCount));
1443 SkUnichar* out = glyphToUnicode->begin();
1444 sk_bzero(out, glyphCount * sizeof(SkUnichar));
1445 for (int i = 0; i < length; i++) {
1446 int mask = bits[i];
1447 if (!mask) {
1448 continue;
1449 }
1450 for (int j = 0; j < 8; j++) {
1451 CGGlyph glyph;
1452 UniChar unichar = static_cast<UniChar>((i << 3) + j);
1453 if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1454 out[glyph] = unichar;
1455 }
1456 }
1457 }
1458 }
1459
1460 /** Assumes src and dst are not nullptr. */
CFStringToSkString(CFStringRef src,SkString * dst)1461 static void CFStringToSkString(CFStringRef src, SkString* dst) {
1462 // Reserve enough room for the worst-case string,
1463 // plus 1 byte for the trailing null.
1464 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src),
1465 kCFStringEncodingUTF8) + 1;
1466 dst->resize(length);
1467 CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8);
1468 // Resize to the actual UTF-8 length used, stripping the null character.
1469 dst->resize(strlen(dst->c_str()));
1470 }
1471
onGetAdvancedTypefaceMetrics(PerGlyphInfo perGlyphInfo,const uint32_t * glyphIDs,uint32_t glyphIDsCount) const1472 SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics(
1473 PerGlyphInfo perGlyphInfo,
1474 const uint32_t* glyphIDs,
1475 uint32_t glyphIDsCount) const {
1476
1477 AUTO_CG_LOCK();
1478
1479 UniqueCFRef<CTFontRef> ctFont =
1480 ctfont_create_exact_copy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()), nullptr);
1481
1482 SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
1483
1484 {
1485 UniqueCFRef<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont.get()));
1486 if (fontName.get()) {
1487 CFStringToSkString(fontName.get(), &info->fFontName);
1488 }
1489 }
1490
1491 // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when
1492 // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always
1493 // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and
1494 // CGFontCopyVariations here until support for 10.10 and earlier is removed.
1495 UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont.get(), nullptr));
1496 if (cgFont) {
1497 UniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get()));
1498 if (cgAxes && CFArrayGetCount(cgAxes.get()) > 0) {
1499 info->fFlags |= SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag;
1500 }
1501 }
1502
1503 CFIndex glyphCount = CTFontGetGlyphCount(ctFont.get());
1504
1505 if (perGlyphInfo & kToUnicode_PerGlyphInfo) {
1506 populate_glyph_to_unicode(ctFont.get(), glyphCount, &info->fGlyphToUnicode);
1507 }
1508
1509 // If it's not a truetype font, mark it as 'other'. Assume that TrueType
1510 // fonts always have both glyf and loca tables. At the least, this is what
1511 // sfntly needs to subset the font. CTFontCopyAttribute() does not always
1512 // succeed in determining this directly.
1513 if (!this->getTableSize('glyf') || !this->getTableSize('loca')) {
1514 return info;
1515 }
1516
1517 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1518 CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get());
1519 if (symbolicTraits & kCTFontMonoSpaceTrait) {
1520 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1521 }
1522 if (symbolicTraits & kCTFontItalicTrait) {
1523 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1524 }
1525 CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
1526 if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
1527 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1528 } else if (stylisticClass & kCTFontScriptsClass) {
1529 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1530 }
1531 info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont.get());
1532 info->fAscent = (int16_t) CTFontGetAscent(ctFont.get());
1533 info->fDescent = (int16_t) CTFontGetDescent(ctFont.get());
1534 info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont.get());
1535 CGRect bbox = CTFontGetBoundingBox(ctFont.get());
1536
1537 SkRect r;
1538 r.set( CGToScalar(CGRectGetMinX_inline(bbox)), // Left
1539 CGToScalar(CGRectGetMaxY_inline(bbox)), // Top
1540 CGToScalar(CGRectGetMaxX_inline(bbox)), // Right
1541 CGToScalar(CGRectGetMinY_inline(bbox))); // Bottom
1542
1543 r.roundOut(&(info->fBBox));
1544
1545 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1546 // This probably isn't very good with an italic font.
1547 int16_t min_width = SHRT_MAX;
1548 info->fStemV = 0;
1549 static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
1550 const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
1551 CGGlyph glyphs[count];
1552 CGRect boundingRects[count];
1553 if (CTFontGetGlyphsForCharacters(ctFont.get(), stem_chars, glyphs, count)) {
1554 CTFontGetBoundingRectsForGlyphs(ctFont.get(), kCTFontOrientationHorizontal,
1555 glyphs, boundingRects, count);
1556 for (size_t i = 0; i < count; i++) {
1557 int16_t width = (int16_t) boundingRects[i].size.width;
1558 if (width > 0 && width < min_width) {
1559 min_width = width;
1560 info->fStemV = min_width;
1561 }
1562 }
1563 }
1564 return info;
1565 }
1566
1567 ///////////////////////////////////////////////////////////////////////////////
1568
get_font_type_tag(const SkTypeface_Mac * typeface)1569 static SK_SFNT_ULONG get_font_type_tag(const SkTypeface_Mac* typeface) {
1570 CTFontRef ctFont = typeface->fFontRef.get();
1571 UniqueCFRef<CFNumberRef> fontFormatRef(
1572 static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
1573 if (!fontFormatRef) {
1574 return 0;
1575 }
1576
1577 SInt32 fontFormatValue;
1578 if (!CFNumberGetValue(fontFormatRef.get(), kCFNumberSInt32Type, &fontFormatValue)) {
1579 return 0;
1580 }
1581
1582 switch (fontFormatValue) {
1583 case kCTFontFormatOpenTypePostScript:
1584 return SkSFNTHeader::fontType_OpenTypeCFF::TAG;
1585 case kCTFontFormatOpenTypeTrueType:
1586 return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1587 case kCTFontFormatTrueType:
1588 return SkSFNTHeader::fontType_MacTrueType::TAG;
1589 case kCTFontFormatPostScript:
1590 return SkSFNTHeader::fontType_PostScript::TAG;
1591 case kCTFontFormatBitmap:
1592 return SkSFNTHeader::fontType_MacTrueType::TAG;
1593 case kCTFontFormatUnrecognized:
1594 default:
1595 //CT seems to be unreliable in being able to obtain the type,
1596 //even if all we want is the first four bytes of the font resource.
1597 //Just the presence of the FontForge 'FFTM' table seems to throw it off.
1598 return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1599 }
1600 }
1601
onOpenStream(int * ttcIndex) const1602 SkStreamAsset* SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
1603 SK_SFNT_ULONG fontType = get_font_type_tag(this);
1604 if (0 == fontType) {
1605 return nullptr;
1606 }
1607
1608 // get table tags
1609 int numTables = this->countTables();
1610 SkTDArray<SkFontTableTag> tableTags;
1611 tableTags.setCount(numTables);
1612 this->getTableTags(tableTags.begin());
1613
1614 // calc total size for font, save sizes
1615 SkTDArray<size_t> tableSizes;
1616 size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1617 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1618 size_t tableSize = this->getTableSize(tableTags[tableIndex]);
1619 totalSize += (tableSize + 3) & ~3;
1620 *tableSizes.append() = tableSize;
1621 }
1622
1623 // reserve memory for stream, and zero it (tables must be zero padded)
1624 SkMemoryStream* stream = new SkMemoryStream(totalSize);
1625 char* dataStart = (char*)stream->getMemoryBase();
1626 sk_bzero(dataStart, totalSize);
1627 char* dataPtr = dataStart;
1628
1629 // compute font header entries
1630 uint16_t entrySelector = 0;
1631 uint16_t searchRange = 1;
1632 while (searchRange < numTables >> 1) {
1633 entrySelector++;
1634 searchRange <<= 1;
1635 }
1636 searchRange <<= 4;
1637 uint16_t rangeShift = (numTables << 4) - searchRange;
1638
1639 // write font header
1640 SkSFNTHeader* header = (SkSFNTHeader*)dataPtr;
1641 header->fontType = fontType;
1642 header->numTables = SkEndian_SwapBE16(numTables);
1643 header->searchRange = SkEndian_SwapBE16(searchRange);
1644 header->entrySelector = SkEndian_SwapBE16(entrySelector);
1645 header->rangeShift = SkEndian_SwapBE16(rangeShift);
1646 dataPtr += sizeof(SkSFNTHeader);
1647
1648 // write tables
1649 SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr;
1650 dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1651 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1652 size_t tableSize = tableSizes[tableIndex];
1653 this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
1654 entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]);
1655 entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr,
1656 tableSize));
1657 entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart));
1658 entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize));
1659
1660 dataPtr += (tableSize + 3) & ~3;
1661 ++entry;
1662 }
1663
1664 *ttcIndex = 0;
1665 return stream;
1666 }
1667
1668 struct NonDefaultAxesContext {
1669 SkFixed* axisValue;
1670 CFArrayRef cgAxes;
1671 };
set_non_default_axes(CFTypeRef key,CFTypeRef value,void * context)1672 static void set_non_default_axes(CFTypeRef key, CFTypeRef value, void* context) {
1673 NonDefaultAxesContext* self = static_cast<NonDefaultAxesContext*>(context);
1674
1675 if (CFGetTypeID(key) != CFStringGetTypeID() || CFGetTypeID(value) != CFNumberGetTypeID()) {
1676 return;
1677 }
1678
1679 // The key is a CFString which is a string from the 'name' table.
1680 // Search the cgAxes for an axis with this name, and use its index to store the value.
1681 CFIndex keyIndex = -1;
1682 CFStringRef keyString = static_cast<CFStringRef>(key);
1683 for (CFIndex i = 0; i < CFArrayGetCount(self->cgAxes); ++i) {
1684 CFTypeRef cgAxis = CFArrayGetValueAtIndex(self->cgAxes, i);
1685 if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) {
1686 continue;
1687 }
1688
1689 CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis);
1690 CFTypeRef cgAxisName = CFDictionaryGetValue(cgAxisDict, kCGFontVariationAxisName);
1691 if (!cgAxisName || CFGetTypeID(cgAxisName) != CFStringGetTypeID()) {
1692 continue;
1693 }
1694 CFStringRef cgAxisNameString = static_cast<CFStringRef>(cgAxisName);
1695 if (CFStringCompare(keyString, cgAxisNameString, 0) == kCFCompareEqualTo) {
1696 keyIndex = i;
1697 break;
1698 }
1699 }
1700 if (keyIndex == -1) {
1701 return;
1702 }
1703
1704 CFNumberRef valueNumber = static_cast<CFNumberRef>(value);
1705 double valueDouble;
1706 if (!CFNumberGetValue(valueNumber, kCFNumberDoubleType, &valueDouble) ||
1707 valueDouble < SkFixedToDouble(SK_FixedMin) || SkFixedToDouble(SK_FixedMax) < valueDouble)
1708 {
1709 return;
1710 }
1711 self->axisValue[keyIndex] = SkDoubleToFixed(valueDouble);
1712 }
get_variations(CTFontRef ctFont,CFIndex * cgAxisCount,SkAutoSTMalloc<4,SkFixed> * axisValues)1713 static bool get_variations(CTFontRef ctFont, CFIndex* cgAxisCount,
1714 SkAutoSTMalloc<4, SkFixed>* axisValues)
1715 {
1716 // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when
1717 // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always
1718 // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and
1719 // CGFontCopyVariations here until support for 10.10 and earlier is removed.
1720 UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr));
1721 if (!cgFont) {
1722 return false;
1723 }
1724
1725 UniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get()));
1726 // If a font has no variations CGFontCopyVariations returns nullptr (instead of an empty dict).
1727 if (!cgVariations) {
1728 return false;
1729 }
1730
1731 UniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get()));
1732 if (!cgAxes) {
1733 return false;
1734 }
1735 *cgAxisCount = CFArrayGetCount(cgAxes.get());
1736 axisValues->reset(*cgAxisCount);
1737
1738 // Set all of the axes to their default values.
1739 // Fail if any default value cannot be determined.
1740 for (CFIndex i = 0; i < *cgAxisCount; ++i) {
1741 CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes.get(), i);
1742 if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) {
1743 return false;
1744 }
1745
1746 CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis);
1747 CFTypeRef axisDefaultValue = CFDictionaryGetValue(cgAxisDict,
1748 kCGFontVariationAxisDefaultValue);
1749 if (!axisDefaultValue || CFGetTypeID(axisDefaultValue) != CFNumberGetTypeID()) {
1750 return false;
1751 }
1752 CFNumberRef axisDefaultValueNumber = static_cast<CFNumberRef>(axisDefaultValue);
1753 double axisDefaultValueDouble;
1754 if (!CFNumberGetValue(axisDefaultValueNumber, kCFNumberDoubleType, &axisDefaultValueDouble))
1755 {
1756 return false;
1757 }
1758 if (axisDefaultValueDouble < SkFixedToDouble(SK_FixedMin) ||
1759 SkFixedToDouble(SK_FixedMax) < axisDefaultValueDouble)
1760 {
1761 return false;
1762 }
1763 (*axisValues)[(int)i] = SkDoubleToFixed(axisDefaultValueDouble);
1764 }
1765
1766 // Override the default values with the given font's stated axis values.
1767 NonDefaultAxesContext c = { axisValues->get(), cgAxes.get() };
1768 CFDictionaryApplyFunction(cgVariations.get(), set_non_default_axes, &c);
1769
1770 return true;
1771 }
onMakeFontData() const1772 std::unique_ptr<SkFontData> SkTypeface_Mac::onMakeFontData() const {
1773 int index;
1774 std::unique_ptr<SkStreamAsset> stream(this->onOpenStream(&index));
1775
1776 CFIndex cgAxisCount;
1777 SkAutoSTMalloc<4, SkFixed> axisValues;
1778 if (get_variations(fFontRef.get(), &cgAxisCount, &axisValues)) {
1779 return skstd::make_unique<SkFontData>(std::move(stream), index,
1780 axisValues.get(), cgAxisCount);
1781 }
1782 return skstd::make_unique<SkFontData>(std::move(stream), index, nullptr, 0);
1783 }
1784
1785 /** Creates a CT variation dictionary {tag, value} from a CG variation dictionary {name, value}. */
ct_variation_from_cg_variation(CFDictionaryRef cgVariations,CFArrayRef ctAxes)1786 static UniqueCFRef<CFDictionaryRef> ct_variation_from_cg_variation(CFDictionaryRef cgVariations,
1787 CFArrayRef ctAxes) {
1788
1789 UniqueCFRef<CFMutableDictionaryRef> ctVariations(
1790 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1791 &kCFTypeDictionaryKeyCallBacks,
1792 &kCFTypeDictionaryValueCallBacks));
1793
1794 CFIndex axisCount = CFArrayGetCount(ctAxes);
1795 for (CFIndex i = 0; i < axisCount; ++i) {
1796 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes, i);
1797 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
1798 return nullptr;
1799 }
1800 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
1801
1802 // The assumption is that values produced by kCTFontVariationAxisNameKey and
1803 // kCGFontVariationAxisName will always be equal.
1804 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey);
1805 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
1806 return nullptr;
1807 }
1808
1809 CFTypeRef axisValue = CFDictionaryGetValue(cgVariations, axisName);
1810 if (!axisValue || CFGetTypeID(axisValue) != CFNumberGetTypeID()) {
1811 return nullptr;
1812 }
1813
1814 CFTypeRef axisTag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
1815 if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) {
1816 return nullptr;
1817 }
1818
1819 CFDictionaryAddValue(ctVariations.get(), axisTag, axisValue);
1820 }
1821 return std::move(ctVariations);
1822 }
1823
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount) const1824 int SkTypeface_Mac::onGetVariationDesignPosition(
1825 SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
1826 {
1827 // The CGFont variation data does not contain the tag.
1828
1829 // This call always returns nullptr on 10.10 and under for CGFontCreateWithDataProvider fonts.
1830 // When this happens, there is no API to provide the tag.
1831 UniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get()));
1832 if (!ctAxes) {
1833 return -1;
1834 }
1835 CFIndex axisCount = CFArrayGetCount(ctAxes.get());
1836 if (!coordinates || coordinateCount < axisCount) {
1837 return axisCount;
1838 }
1839
1840 // This call always returns nullptr on 10.11 and under for CGFontCreateWithDataProvider fonts.
1841 // When this happens, try converting the CG variation to a CT variation.
1842 // On 10.12 and later, this only returns non-default variations.
1843 UniqueCFRef<CFDictionaryRef> ctVariations(CTFontCopyVariation(fFontRef.get()));
1844 if (!ctVariations) {
1845 // When 10.11 and earlier are no longer supported, the following code can be replaced with
1846 // return -1 and ct_variation_from_cg_variation can be removed.
1847 UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr));
1848 if (!cgFont) {
1849 return -1;
1850 }
1851 UniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get()));
1852 if (!cgVariations) {
1853 return -1;
1854 }
1855 ctVariations = ct_variation_from_cg_variation(cgVariations.get(), ctAxes.get());
1856 if (!ctVariations) {
1857 return -1;
1858 }
1859 }
1860
1861 for (int i = 0; i < axisCount; ++i) {
1862 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
1863 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
1864 return -1;
1865 }
1866 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
1867
1868 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
1869 if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
1870 return -1;
1871 }
1872 CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
1873 int64_t tagLong;
1874 if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
1875 return -1;
1876 }
1877 coordinates[i].axis = tagLong;
1878
1879 CGFloat variationCGFloat;
1880 CFTypeRef variationValue = CFDictionaryGetValue(ctVariations.get(), tagNumber);
1881 if (variationValue) {
1882 if (CFGetTypeID(variationValue) != CFNumberGetTypeID()) {
1883 return -1;
1884 }
1885 CFNumberRef variationNumber = static_cast<CFNumberRef>(variationValue);
1886 if (!CFNumberGetValue(variationNumber, kCFNumberCGFloatType, &variationCGFloat)) {
1887 return -1;
1888 }
1889 } else {
1890 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
1891 if (!def || CFGetTypeID(def) != CFNumberGetTypeID()) {
1892 return -1;
1893 }
1894 CFNumberRef defNumber = static_cast<CFNumberRef>(def);
1895 if (!CFNumberGetValue(defNumber, kCFNumberCGFloatType, &variationCGFloat)) {
1896 return -1;
1897 }
1898 }
1899 coordinates[i].value = CGToScalar(variationCGFloat);
1900
1901 }
1902 return axisCount;
1903 }
1904
1905 ///////////////////////////////////////////////////////////////////////////////
1906 ///////////////////////////////////////////////////////////////////////////////
1907
onGetUPEM() const1908 int SkTypeface_Mac::onGetUPEM() const {
1909 UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr));
1910 return CGFontGetUnitsPerEm(cgFont.get());
1911 }
1912
onCreateFamilyNameIterator() const1913 SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const {
1914 SkTypeface::LocalizedStrings* nameIter =
1915 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
1916 if (nullptr == nameIter) {
1917 CFStringRef cfLanguageRaw;
1918 UniqueCFRef<CFStringRef> cfFamilyName(
1919 CTFontCopyLocalizedName(fFontRef.get(), kCTFontFamilyNameKey, &cfLanguageRaw));
1920 UniqueCFRef<CFStringRef> cfLanguage(cfLanguageRaw);
1921
1922 SkString skLanguage;
1923 SkString skFamilyName;
1924 if (cfLanguage) {
1925 CFStringToSkString(cfLanguage.get(), &skLanguage);
1926 } else {
1927 skLanguage = "und"; //undetermined
1928 }
1929 if (cfFamilyName) {
1930 CFStringToSkString(cfFamilyName.get(), &skFamilyName);
1931 }
1932
1933 nameIter = new SkOTUtils::LocalizedStrings_SingleName(skFamilyName, skLanguage);
1934 }
1935 return nameIter;
1936 }
1937
onGetTableTags(SkFontTableTag tags[]) const1938 int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
1939 UniqueCFRef<CFArrayRef> cfArray(
1940 CTFontCopyAvailableTables(fFontRef.get(), kCTFontTableOptionNoOptions));
1941 if (!cfArray) {
1942 return 0;
1943 }
1944 int count = SkToInt(CFArrayGetCount(cfArray.get()));
1945 if (tags) {
1946 for (int i = 0; i < count; ++i) {
1947 uintptr_t fontTag = reinterpret_cast<uintptr_t>(
1948 CFArrayGetValueAtIndex(cfArray.get(), i));
1949 tags[i] = static_cast<SkFontTableTag>(fontTag);
1950 }
1951 }
1952 return count;
1953 }
1954
1955 // If, as is the case with web fonts, the CTFont data isn't available,
1956 // the CGFont data may work. While the CGFont may always provide the
1957 // right result, leave the CTFont code path to minimize disruption.
copy_table_from_font(CTFontRef ctFont,SkFontTableTag tag)1958 static UniqueCFRef<CFDataRef> copy_table_from_font(CTFontRef ctFont, SkFontTableTag tag) {
1959 UniqueCFRef<CFDataRef> data(CTFontCopyTable(ctFont, (CTFontTableTag) tag,
1960 kCTFontTableOptionNoOptions));
1961 if (!data) {
1962 UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr));
1963 data.reset(CGFontCopyTableForTag(cgFont.get(), tag));
1964 }
1965 return data;
1966 }
1967
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * dstData) const1968 size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset,
1969 size_t length, void* dstData) const {
1970 UniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
1971 if (!srcData) {
1972 return 0;
1973 }
1974
1975 size_t srcSize = CFDataGetLength(srcData.get());
1976 if (offset >= srcSize) {
1977 return 0;
1978 }
1979 if (length > srcSize - offset) {
1980 length = srcSize - offset;
1981 }
1982 if (dstData) {
1983 memcpy(dstData, CFDataGetBytePtr(srcData.get()) + offset, length);
1984 }
1985 return length;
1986 }
1987
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const1988 SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkScalerContextEffects& effects,
1989 const SkDescriptor* desc) const {
1990 return new SkScalerContext_Mac(sk_ref_sp(const_cast<SkTypeface_Mac*>(this)), effects, desc);
1991 }
1992
onFilterRec(SkScalerContextRec * rec) const1993 void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
1994 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
1995 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
1996 {
1997 rec->fMaskFormat = SkMask::kA8_Format;
1998 // Render the glyphs as close as possible to what was requested.
1999 // The above turns off subpixel rendering, but the user requested it.
2000 // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks.
2001 // See comments below for more details.
2002 rec->setHinting(SkPaint::kNormal_Hinting);
2003 }
2004
2005 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
2006 SkScalerContext::kForceAutohinting_Flag |
2007 SkScalerContext::kLCD_BGROrder_Flag |
2008 SkScalerContext::kLCD_Vertical_Flag;
2009
2010 rec->fFlags &= ~flagsWeDontSupport;
2011
2012 bool lcdSupport = supports_LCD();
2013
2014 // Only two levels of hinting are supported.
2015 // kNo_Hinting means avoid CoreGraphics outline dilation.
2016 // kNormal_Hinting means CoreGraphics outline dilation is allowed.
2017 // If there is no lcd support, hinting (dilation) cannot be supported.
2018 SkPaint::Hinting hinting = rec->getHinting();
2019 if (SkPaint::kSlight_Hinting == hinting || !lcdSupport) {
2020 hinting = SkPaint::kNo_Hinting;
2021 } else if (SkPaint::kFull_Hinting == hinting) {
2022 hinting = SkPaint::kNormal_Hinting;
2023 }
2024 rec->setHinting(hinting);
2025
2026 // FIXME: lcd smoothed un-hinted rasterization unsupported.
2027 // Tracked by http://code.google.com/p/skia/issues/detail?id=915 .
2028 // There is no current means to honor a request for unhinted lcd,
2029 // so arbitrarilly ignore the hinting request and honor lcd.
2030
2031 // Hinting and smoothing should be orthogonal, but currently they are not.
2032 // CoreGraphics has no API to influence hinting. However, its lcd smoothed
2033 // output is drawn from auto-dilated outlines (the amount of which is
2034 // determined by AppleFontSmoothing). Its regular anti-aliased output is
2035 // drawn from un-dilated outlines.
2036
2037 // The behavior of Skia is as follows:
2038 // [AA][no-hint]: generate AA using CoreGraphic's AA output.
2039 // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single
2040 // channel. This matches [LCD][yes-hint] in weight.
2041 // [LCD][no-hint]: curently unable to honor, and must pick which to respect.
2042 // Currenly side with LCD, effectively ignoring the hinting setting.
2043 // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output.
2044
2045 if (rec->fMaskFormat == SkMask::kLCD16_Format) {
2046 if (lcdSupport) {
2047 //CoreGraphics creates 555 masks for smoothed text anyway.
2048 rec->fMaskFormat = SkMask::kLCD16_Format;
2049 rec->setHinting(SkPaint::kNormal_Hinting);
2050 } else {
2051 rec->fMaskFormat = SkMask::kA8_Format;
2052 }
2053 }
2054
2055 // CoreText provides no information as to whether a glyph will be color or not.
2056 // Fonts may mix outlines and bitmaps, so information is needed on a glyph by glyph basis.
2057 // If a font contains an 'sbix' table, consider it to be a color font, and disable lcd.
2058 if (fHasColorGlyphs) {
2059 rec->fMaskFormat = SkMask::kARGB32_Format;
2060 }
2061
2062 // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
2063 // All other masks can use regular gamma.
2064 if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hinting) {
2065 #ifndef SK_GAMMA_APPLY_TO_A8
2066 // SRGBTODO: Is this correct? Do we want contrast boost?
2067 rec->ignorePreBlend();
2068 #endif
2069 } else {
2070 //CoreGraphics dialates smoothed text as needed.
2071 rec->setContrast(0);
2072 }
2073 }
2074
2075 /** Takes ownership of the CFStringRef. */
get_str(CFStringRef ref,SkString * str)2076 static const char* get_str(CFStringRef ref, SkString* str) {
2077 if (nullptr == ref) {
2078 return nullptr;
2079 }
2080 CFStringToSkString(ref, str);
2081 CFRelease(ref);
2082 return str->c_str();
2083 }
2084
onGetFamilyName(SkString * familyName) const2085 void SkTypeface_Mac::onGetFamilyName(SkString* familyName) const {
2086 get_str(CTFontCopyFamilyName(fFontRef.get()), familyName);
2087 }
2088
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocalStream) const2089 void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc,
2090 bool* isLocalStream) const {
2091 SkString tmpStr;
2092
2093 desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef.get()), &tmpStr));
2094 desc->setFullName(get_str(CTFontCopyFullName(fFontRef.get()), &tmpStr));
2095 desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef.get()), &tmpStr));
2096 desc->setStyle(this->fontStyle());
2097 *isLocalStream = fIsLocalStream;
2098 }
2099
onCharsToGlyphs(const void * chars,Encoding encoding,uint16_t glyphs[],int glyphCount) const2100 int SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding,
2101 uint16_t glyphs[], int glyphCount) const
2102 {
2103 // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
2104 // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
2105 // It is documented that if a mapping is unavailable, the glyph will be set to 0.
2106
2107 SkAutoSTMalloc<1024, UniChar> charStorage;
2108 const UniChar* src; // UniChar is a UTF-16 16-bit code unit.
2109 int srcCount;
2110 switch (encoding) {
2111 case kUTF8_Encoding: {
2112 const char* utf8 = reinterpret_cast<const char*>(chars);
2113 UniChar* utf16 = charStorage.reset(2 * glyphCount);
2114 src = utf16;
2115 for (int i = 0; i < glyphCount; ++i) {
2116 SkUnichar uni = SkUTF8_NextUnichar(&utf8);
2117 utf16 += SkUTF16_FromUnichar(uni, utf16);
2118 }
2119 srcCount = SkToInt(utf16 - src);
2120 break;
2121 }
2122 case kUTF16_Encoding: {
2123 src = reinterpret_cast<const UniChar*>(chars);
2124 int extra = 0;
2125 for (int i = 0; i < glyphCount; ++i) {
2126 if (SkUTF16_IsHighSurrogate(src[i + extra])) {
2127 ++extra;
2128 }
2129 }
2130 srcCount = glyphCount + extra;
2131 break;
2132 }
2133 case kUTF32_Encoding: {
2134 const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(chars);
2135 UniChar* utf16 = charStorage.reset(2 * glyphCount);
2136 src = utf16;
2137 for (int i = 0; i < glyphCount; ++i) {
2138 utf16 += SkUTF16_FromUnichar(utf32[i], utf16);
2139 }
2140 srcCount = SkToInt(utf16 - src);
2141 break;
2142 }
2143 }
2144
2145 // If glyphs is nullptr, CT still needs glyph storage for finding the first failure.
2146 // Also, if there are any non-bmp code points, the provided 'glyphs' storage will be inadequate.
2147 SkAutoSTMalloc<1024, uint16_t> glyphStorage;
2148 uint16_t* macGlyphs = glyphs;
2149 if (nullptr == macGlyphs || srcCount > glyphCount) {
2150 macGlyphs = glyphStorage.reset(srcCount);
2151 }
2152
2153 bool allEncoded = CTFontGetGlyphsForCharacters(fFontRef.get(), src, macGlyphs, srcCount);
2154
2155 // If there were any non-bmp, then copy and compact.
2156 // If 'glyphs' is nullptr, then compact glyphStorage in-place.
2157 // If all are bmp and 'glyphs' is non-nullptr, 'glyphs' already contains the compact glyphs.
2158 // If some are non-bmp and 'glyphs' is non-nullptr, copy and compact into 'glyphs'.
2159 uint16_t* compactedGlyphs = glyphs;
2160 if (nullptr == compactedGlyphs) {
2161 compactedGlyphs = macGlyphs;
2162 }
2163 if (srcCount > glyphCount) {
2164 int extra = 0;
2165 for (int i = 0; i < glyphCount; ++i) {
2166 compactedGlyphs[i] = macGlyphs[i + extra];
2167 if (SkUTF16_IsHighSurrogate(src[i + extra])) {
2168 ++extra;
2169 }
2170 }
2171 }
2172
2173 if (allEncoded) {
2174 return glyphCount;
2175 }
2176
2177 // If we got false, then we need to manually look for first failure.
2178 for (int i = 0; i < glyphCount; ++i) {
2179 if (0 == compactedGlyphs[i]) {
2180 return i;
2181 }
2182 }
2183 // Odd to get here, as we expected CT to have returned true up front.
2184 return glyphCount;
2185 }
2186
onCountGlyphs() const2187 int SkTypeface_Mac::onCountGlyphs() const {
2188 return SkToInt(CTFontGetGlyphCount(fFontRef.get()));
2189 }
2190
2191 ///////////////////////////////////////////////////////////////////////////////
2192 ///////////////////////////////////////////////////////////////////////////////
2193
find_desc_str(CTFontDescriptorRef desc,CFStringRef name,SkString * value)2194 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
2195 UniqueCFRef<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
2196 if (!ref) {
2197 return false;
2198 }
2199 CFStringToSkString(ref.get(), value);
2200 return true;
2201 }
2202
2203 #include "SkFontMgr.h"
2204
sqr(int value)2205 static inline int sqr(int value) {
2206 SkASSERT(SkAbs32(value) < 0x7FFF); // check for overflow
2207 return value * value;
2208 }
2209
2210 // We normalize each axis (weight, width, italic) to be base-900
compute_metric(const SkFontStyle & a,const SkFontStyle & b)2211 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
2212 return sqr(a.weight() - b.weight()) +
2213 sqr((a.width() - b.width()) * 100) +
2214 sqr((a.slant() != b.slant()) * 900);
2215 }
2216
2217 class SkFontStyleSet_Mac : public SkFontStyleSet {
2218 public:
SkFontStyleSet_Mac(CTFontDescriptorRef desc)2219 SkFontStyleSet_Mac(CTFontDescriptorRef desc)
2220 : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, nullptr))
2221 , fCount(0)
2222 {
2223 if (!fArray) {
2224 fArray.reset(CFArrayCreate(nullptr, nullptr, 0, nullptr));
2225 }
2226 fCount = SkToInt(CFArrayGetCount(fArray.get()));
2227 }
2228
count()2229 int count() override {
2230 return fCount;
2231 }
2232
getStyle(int index,SkFontStyle * style,SkString * name)2233 void getStyle(int index, SkFontStyle* style, SkString* name) override {
2234 SkASSERT((unsigned)index < (unsigned)fCount);
2235 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
2236 if (style) {
2237 *style = fontstyle_from_descriptor(desc, false);
2238 }
2239 if (name) {
2240 if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
2241 name->reset();
2242 }
2243 }
2244 }
2245
createTypeface(int index)2246 SkTypeface* createTypeface(int index) override {
2247 SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray.get()));
2248 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
2249
2250 return create_from_desc(desc);
2251 }
2252
matchStyle(const SkFontStyle & pattern)2253 SkTypeface* matchStyle(const SkFontStyle& pattern) override {
2254 if (0 == fCount) {
2255 return nullptr;
2256 }
2257 return create_from_desc(findMatchingDesc(pattern));
2258 }
2259
2260 private:
2261 UniqueCFRef<CFArrayRef> fArray;
2262 int fCount;
2263
findMatchingDesc(const SkFontStyle & pattern) const2264 CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
2265 int bestMetric = SK_MaxS32;
2266 CTFontDescriptorRef bestDesc = nullptr;
2267
2268 for (int i = 0; i < fCount; ++i) {
2269 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), i);
2270 int metric = compute_metric(pattern, fontstyle_from_descriptor(desc, false));
2271 if (0 == metric) {
2272 return desc;
2273 }
2274 if (metric < bestMetric) {
2275 bestMetric = metric;
2276 bestDesc = desc;
2277 }
2278 }
2279 SkASSERT(bestDesc);
2280 return bestDesc;
2281 }
2282 };
2283
2284 class SkFontMgr_Mac : public SkFontMgr {
2285 UniqueCFRef<CFArrayRef> fNames;
2286 int fCount;
2287
getFamilyNameAt(int index) const2288 CFStringRef getFamilyNameAt(int index) const {
2289 SkASSERT((unsigned)index < (unsigned)fCount);
2290 return (CFStringRef)CFArrayGetValueAtIndex(fNames.get(), index);
2291 }
2292
CreateSet(CFStringRef cfFamilyName)2293 static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) {
2294 UniqueCFRef<CFMutableDictionaryRef> cfAttr(
2295 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2296 &kCFTypeDictionaryKeyCallBacks,
2297 &kCFTypeDictionaryValueCallBacks));
2298
2299 CFDictionaryAddValue(cfAttr.get(), kCTFontFamilyNameAttribute, cfFamilyName);
2300
2301 UniqueCFRef<CTFontDescriptorRef> desc(
2302 CTFontDescriptorCreateWithAttributes(cfAttr.get()));
2303 return new SkFontStyleSet_Mac(desc.get());
2304 }
2305
2306 /** CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we
2307 * provide a wrapper here that will return an empty array if need be.
2308 */
CopyAvailableFontFamilyNames()2309 static UniqueCFRef<CFArrayRef> CopyAvailableFontFamilyNames() {
2310 #ifdef SK_BUILD_FOR_IOS
2311 return UniqueCFRef<CFArrayRef>(CFArrayCreate(nullptr, nullptr, 0, nullptr));
2312 #else
2313 return UniqueCFRef<CFArrayRef>(CTFontManagerCopyAvailableFontFamilyNames());
2314 #endif
2315 }
2316
2317 public:
SkFontMgr_Mac()2318 SkFontMgr_Mac()
2319 : fNames(CopyAvailableFontFamilyNames())
2320 , fCount(fNames ? SkToInt(CFArrayGetCount(fNames.get())) : 0) {}
2321
2322 protected:
onCountFamilies() const2323 int onCountFamilies() const override {
2324 return fCount;
2325 }
2326
onGetFamilyName(int index,SkString * familyName) const2327 void onGetFamilyName(int index, SkString* familyName) const override {
2328 if ((unsigned)index < (unsigned)fCount) {
2329 CFStringToSkString(this->getFamilyNameAt(index), familyName);
2330 } else {
2331 familyName->reset();
2332 }
2333 }
2334
onCreateStyleSet(int index) const2335 SkFontStyleSet* onCreateStyleSet(int index) const override {
2336 if ((unsigned)index >= (unsigned)fCount) {
2337 return nullptr;
2338 }
2339 return CreateSet(this->getFamilyNameAt(index));
2340 }
2341
onMatchFamily(const char familyName[]) const2342 SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
2343 UniqueCFRef<CFStringRef> cfName = make_CFString(familyName);
2344 return CreateSet(cfName.get());
2345 }
2346
onMatchFamilyStyle(const char familyName[],const SkFontStyle & fontStyle) const2347 SkTypeface* onMatchFamilyStyle(const char familyName[],
2348 const SkFontStyle& fontStyle) const override {
2349 sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
2350 return sset->matchStyle(fontStyle);
2351 }
2352
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const2353 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
2354 const SkFontStyle& style,
2355 const char* bcp47[], int bcp47Count,
2356 SkUnichar character) const override {
2357 UniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
2358 UniqueCFRef<CTFontRef> currentFont(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
2359
2360 // kCFStringEncodingUTF32 is BE unless there is a BOM.
2361 // Since there is no machine endian option, explicitly state machine endian.
2362 #ifdef SK_CPU_LENDIAN
2363 constexpr CFStringEncoding encoding = kCFStringEncodingUTF32LE;
2364 #else
2365 constexpr CFStringEncoding encoding = kCFStringEncodingUTF32BE;
2366 #endif
2367 UniqueCFRef<CFStringRef> string(CFStringCreateWithBytes(
2368 kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(&character), sizeof(character),
2369 encoding, false));
2370 CFRange range = CFRangeMake(0, CFStringGetLength(string.get())); // in UniChar units.
2371 UniqueCFRef<CTFontRef> fallbackFont(
2372 CTFontCreateForString(currentFont.get(), string.get(), range));
2373 return create_from_CTFontRef(std::move(fallbackFont), nullptr, false);
2374 }
2375
onMatchFaceStyle(const SkTypeface * familyMember,const SkFontStyle &) const2376 SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2377 const SkFontStyle&) const override {
2378 return nullptr;
2379 }
2380
onCreateFromData(SkData * data,int ttcIndex) const2381 SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
2382 UniqueCFRef<CGDataProviderRef> pr(SkCreateDataProviderFromData(sk_ref_sp(data)));
2383 if (!pr) {
2384 return nullptr;
2385 }
2386 return create_from_dataProvider(std::move(pr), ttcIndex);
2387 }
2388
onCreateFromStream(SkStreamAsset * bareStream,int ttcIndex) const2389 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
2390 std::unique_ptr<SkStreamAsset> stream(bareStream);
2391 UniqueCFRef<CGDataProviderRef> pr(SkCreateDataProviderFromStream(std::move(stream)));
2392 if (!pr) {
2393 return nullptr;
2394 }
2395 return create_from_dataProvider(std::move(pr), ttcIndex);
2396 }
2397
2398 /** Creates a dictionary suitable for setting the axes on a CGFont. */
copy_axes(CGFontRef cg,const SkFontArguments & args)2399 static UniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, const SkFontArguments& args) {
2400 // The CGFont variation data is keyed by name, but lacks the tag.
2401 // The CTFont variation data is keyed by tag, and also has the name.
2402 // We would like to work with CTFont variations, but creating a CTFont font with
2403 // CTFont variation dictionary runs into bugs. So use the CTFont variation data
2404 // to match names to tags to create the appropriate CGFont.
2405 UniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr));
2406 // This call always returns nullptr on 10.10 and under.
2407 // When this happens, there is no API to provide the tag.
2408 UniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct.get()));
2409 if (!ctAxes) {
2410 return nullptr;
2411 }
2412 CFIndex axisCount = CFArrayGetCount(ctAxes.get());
2413
2414 const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
2415
2416 UniqueCFRef<CFMutableDictionaryRef> dict(
2417 CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
2418 &kCFTypeDictionaryKeyCallBacks,
2419 &kCFTypeDictionaryValueCallBacks));
2420
2421 for (int i = 0; i < axisCount; ++i) {
2422 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
2423 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
2424 return nullptr;
2425 }
2426 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
2427
2428 // The assumption is that values produced by kCTFontVariationAxisNameKey and
2429 // kCGFontVariationAxisName will always be equal.
2430 // If they are ever not, seach the project history for "get_tag_for_name".
2431 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey);
2432 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
2433 return nullptr;
2434 }
2435
2436 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
2437 if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
2438 return nullptr;
2439 }
2440 CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
2441 int64_t tagLong;
2442 if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
2443 return nullptr;
2444 }
2445
2446 // The variation axes can be set to any value, but cg will effectively pin them.
2447 // Pin them here to normalize.
2448 CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
2449 CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
2450 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
2451 if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
2452 !max || CFGetTypeID(max) != CFNumberGetTypeID() ||
2453 !def || CFGetTypeID(def) != CFNumberGetTypeID())
2454 {
2455 return nullptr;
2456 }
2457 CFNumberRef minNumber = static_cast<CFNumberRef>(min);
2458 CFNumberRef maxNumber = static_cast<CFNumberRef>(max);
2459 CFNumberRef defNumber = static_cast<CFNumberRef>(def);
2460 double minDouble;
2461 double maxDouble;
2462 double defDouble;
2463 if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) ||
2464 !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble) ||
2465 !CFNumberGetValue(defNumber, kCFNumberDoubleType, &defDouble))
2466 {
2467 return nullptr;
2468 }
2469
2470 double value = defDouble;
2471 for (int j = 0; j < position.coordinateCount; ++j) {
2472 if (position.coordinates[j].axis == tagLong) {
2473 value = SkTPin(SkScalarToDouble(position.coordinates[j].value),
2474 minDouble, maxDouble);
2475 break;
2476 }
2477 }
2478 UniqueCFRef<CFNumberRef> valueNumber(
2479 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
2480 CFDictionaryAddValue(dict.get(), axisName, valueNumber.get());
2481 }
2482 return std::move(dict);
2483 }
onCreateFromStream(SkStreamAsset * bs,const SkFontArguments & args) const2484 SkTypeface* onCreateFromStream(SkStreamAsset* bs, const SkFontArguments& args) const override {
2485 std::unique_ptr<SkStreamAsset> s(bs);
2486 if (args.getCollectionIndex() != 0) {
2487 return nullptr;
2488 }
2489 UniqueCFRef<CGDataProviderRef> provider(SkCreateDataProviderFromStream(std::move(s)));
2490 if (!provider) {
2491 return nullptr;
2492 }
2493 UniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
2494 if (!cg) {
2495 return nullptr;
2496 }
2497
2498 UniqueCFRef<CFDictionaryRef> cgVariations = copy_axes(cg.get(), args);
2499 // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was
2500 // created from a data provider does not appear to have any ownership of the underlying
2501 // data. The original CGFontRef must be kept alive until the copy will no longer be used.
2502 UniqueCFRef<CGFontRef> cgVariant;
2503 if (cgVariations) {
2504 cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.get()));
2505 } else {
2506 cgVariant.reset(cg.release());
2507 }
2508
2509 UniqueCFRef<CTFontRef> ct(
2510 CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, nullptr));
2511 if (!ct) {
2512 return nullptr;
2513 }
2514 return create_from_CTFontRef(std::move(ct), std::move(cg), true);
2515 }
2516
2517 /** Creates a dictionary suitable for setting the axes on a CGFont. */
copy_axes(CGFontRef cg,SkFontData * fontData)2518 static UniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, SkFontData* fontData) {
2519 UniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg));
2520 if (!cgAxes) {
2521 return nullptr;
2522 }
2523
2524 CFIndex axisCount = CFArrayGetCount(cgAxes.get());
2525 if (0 == axisCount || axisCount != fontData->getAxisCount()) {
2526 return nullptr;
2527 }
2528
2529 UniqueCFRef<CFMutableDictionaryRef> dict(
2530 CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
2531 &kCFTypeDictionaryKeyCallBacks,
2532 &kCFTypeDictionaryValueCallBacks));
2533
2534 for (int i = 0; i < fontData->getAxisCount(); ++i) {
2535 CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes.get(), i);
2536 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
2537 return nullptr;
2538 }
2539 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
2540
2541 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisName);
2542 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
2543 return nullptr;
2544 }
2545
2546 // The variation axes can be set to any value, but cg will effectively pin them.
2547 // Pin them here to normalize.
2548 CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMinValue);
2549 CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMaxValue);
2550 if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
2551 !max || CFGetTypeID(max) != CFNumberGetTypeID())
2552 {
2553 return nullptr;
2554 }
2555 CFNumberRef minNumber = static_cast<CFNumberRef>(min);
2556 CFNumberRef maxNumber = static_cast<CFNumberRef>(max);
2557 double minDouble;
2558 double maxDouble;
2559 if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) ||
2560 !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble))
2561 {
2562 return nullptr;
2563 }
2564 double value = SkTPin(SkFixedToDouble(fontData->getAxis()[i]), minDouble, maxDouble);
2565 UniqueCFRef<CFNumberRef> valueNumber(
2566 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
2567 CFDictionaryAddValue(dict.get(), axisName, valueNumber.get());
2568 }
2569 return std::move(dict);
2570 }
onCreateFromFontData(std::unique_ptr<SkFontData> fontData) const2571 SkTypeface* onCreateFromFontData(std::unique_ptr<SkFontData> fontData) const override {
2572 if (fontData->getIndex() != 0) {
2573 return nullptr;
2574 }
2575 UniqueCFRef<CGDataProviderRef> provider(
2576 SkCreateDataProviderFromStream(fontData->detachStream()));
2577 if (!provider) {
2578 return nullptr;
2579 }
2580 UniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
2581 if (!cg) {
2582 return nullptr;
2583 }
2584
2585 UniqueCFRef<CFDictionaryRef> cgVariations = copy_axes(cg.get(), fontData.get());
2586 // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was
2587 // created from a data provider does not appear to have any ownership of the underlying
2588 // data. The original CGFontRef must be kept alive until the copy will no longer be used.
2589 UniqueCFRef<CGFontRef> cgVariant;
2590 if (cgVariations) {
2591 cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.get()));
2592 } else {
2593 cgVariant.reset(cg.release());
2594 }
2595
2596 UniqueCFRef<CTFontRef> ct(
2597 CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, nullptr));
2598 if (!ct) {
2599 return nullptr;
2600 }
2601 return create_from_CTFontRef(std::move(ct), std::move(cg), true);
2602 }
2603
onCreateFromFile(const char path[],int ttcIndex) const2604 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
2605 UniqueCFRef<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path));
2606 if (!pr) {
2607 return nullptr;
2608 }
2609 return create_from_dataProvider(std::move(pr), ttcIndex);
2610 }
2611
onLegacyCreateTypeface(const char familyName[],SkFontStyle style) const2612 SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override {
2613 if (familyName) {
2614 familyName = map_css_names(familyName);
2615 }
2616
2617 SkTypeface* face = create_from_name(familyName, style);
2618 if (face) {
2619 return face;
2620 }
2621
2622 static SkTypeface* gDefaultFace;
2623 static SkOnce lookupDefault;
2624 static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
2625 lookupDefault([]{
2626 gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle());
2627 });
2628 return SkSafeRef(gDefaultFace);
2629 }
2630 };
2631
2632 ///////////////////////////////////////////////////////////////////////////////
2633
Factory()2634 sk_sp<SkFontMgr> SkFontMgr::Factory() { return sk_make_sp<SkFontMgr_Mac>(); }
2635
2636 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
2637