1 /*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkTypes.h"
9 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
10
11 #ifdef SK_BUILD_FOR_MAC
12 #import <ApplicationServices/ApplicationServices.h>
13 #endif
14
15 #ifdef SK_BUILD_FOR_IOS
16 #include <CoreText/CoreText.h>
17 #include <CoreText/CTFontManager.h>
18 #include <CoreGraphics/CoreGraphics.h>
19 #include <CoreFoundation/CoreFoundation.h>
20 #endif
21
22 #include "include/core/SkFontMetrics.h"
23 #include "include/core/SkFontMgr.h"
24 #include "include/core/SkPaint.h"
25 #include "include/core/SkPath.h"
26 #include "include/core/SkStream.h"
27 #include "include/core/SkString.h"
28 #include "include/ports/SkTypeface_mac.h"
29 #include "include/private/SkColorData.h"
30 #include "include/private/SkFloatingPoint.h"
31 #include "include/private/SkMutex.h"
32 #include "include/private/SkOnce.h"
33 #include "include/private/SkTemplates.h"
34 #include "include/private/SkTo.h"
35 #include "include/utils/mac/SkCGUtils.h"
36 #include "src/core/SkAdvancedTypefaceMetrics.h"
37 #include "src/core/SkAutoMalloc.h"
38 #include "src/core/SkDescriptor.h"
39 #include "src/core/SkEndian.h"
40 #include "src/core/SkFontDescriptor.h"
41 #include "src/core/SkGlyph.h"
42 #include "src/core/SkMakeUnique.h"
43 #include "src/core/SkMaskGamma.h"
44 #include "src/core/SkMathPriv.h"
45 #include "src/core/SkTypefaceCache.h"
46 #include "src/core/SkUtils.h"
47 #include "src/sfnt/SkOTTable_OS_2.h"
48 #include "src/sfnt/SkOTUtils.h"
49 #include "src/sfnt/SkSFNTHeader.h"
50 #include "src/utils/SkUTF.h"
51 #include "src/utils/mac/SkUniqueCFRef.h"
52
53 #include <dlfcn.h>
54
55 #include <utility>
56
57 // Set to make glyph bounding boxes visible.
58 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
59
SkTypeface_GetCTFontRef(const SkTypeface * face)60 CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) {
61 return face ? (CTFontRef)face->internal_private_getCTFontRef() : nullptr;
62 }
63
64 class SkScalerContext_Mac;
65
make_CFString(const char s[])66 static SkUniqueCFRef<CFStringRef> make_CFString(const char s[]) {
67 return SkUniqueCFRef<CFStringRef>(CFStringCreateWithCString(nullptr, s, kCFStringEncodingUTF8));
68 }
69
70 // inline versions of these rect helpers
71
CGRectIsEmpty_inline(const CGRect & rect)72 static bool CGRectIsEmpty_inline(const CGRect& rect) {
73 return rect.size.width <= 0 || rect.size.height <= 0;
74 }
75
CGRectGetMinX_inline(const CGRect & rect)76 static CGFloat CGRectGetMinX_inline(const CGRect& rect) {
77 return rect.origin.x;
78 }
79
CGRectGetMaxX_inline(const CGRect & rect)80 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) {
81 return rect.origin.x + rect.size.width;
82 }
83
CGRectGetMinY_inline(const CGRect & rect)84 static CGFloat CGRectGetMinY_inline(const CGRect& rect) {
85 return rect.origin.y;
86 }
87
CGRectGetMaxY_inline(const CGRect & rect)88 static CGFloat CGRectGetMaxY_inline(const CGRect& rect) {
89 return rect.origin.y + rect.size.height;
90 }
91
CGRectGetWidth_inline(const CGRect & rect)92 static CGFloat CGRectGetWidth_inline(const CGRect& rect) {
93 return rect.size.width;
94 }
95
96 ///////////////////////////////////////////////////////////////////////////////
97
sk_memset_rect32(uint32_t * ptr,uint32_t value,int width,int height,size_t rowBytes)98 static void sk_memset_rect32(uint32_t* ptr, uint32_t value,
99 int width, int height, size_t rowBytes) {
100 SkASSERT(width);
101 SkASSERT(width * sizeof(uint32_t) <= rowBytes);
102
103 if (width >= 32) {
104 while (height) {
105 sk_memset32(ptr, value, width);
106 ptr = (uint32_t*)((char*)ptr + rowBytes);
107 height -= 1;
108 }
109 return;
110 }
111
112 rowBytes -= width * sizeof(uint32_t);
113
114 if (width >= 8) {
115 while (height) {
116 int w = width;
117 do {
118 *ptr++ = value; *ptr++ = value;
119 *ptr++ = value; *ptr++ = value;
120 *ptr++ = value; *ptr++ = value;
121 *ptr++ = value; *ptr++ = value;
122 w -= 8;
123 } while (w >= 8);
124 while (--w >= 0) {
125 *ptr++ = value;
126 }
127 ptr = (uint32_t*)((char*)ptr + rowBytes);
128 height -= 1;
129 }
130 } else {
131 while (height) {
132 int w = width;
133 do {
134 *ptr++ = value;
135 } while (--w > 0);
136 ptr = (uint32_t*)((char*)ptr + rowBytes);
137 height -= 1;
138 }
139 }
140 }
141
142 typedef uint32_t CGRGBPixel;
143
CGRGBPixel_getAlpha(CGRGBPixel pixel)144 static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) {
145 return pixel & 0xFF;
146 }
147
ScalarToCG(SkScalar scalar)148 static CGFloat ScalarToCG(SkScalar scalar) {
149 if (sizeof(CGFloat) == sizeof(float)) {
150 return SkScalarToFloat(scalar);
151 } else {
152 SkASSERT(sizeof(CGFloat) == sizeof(double));
153 return (CGFloat) SkScalarToDouble(scalar);
154 }
155 }
156
CGToScalar(CGFloat cgFloat)157 static SkScalar CGToScalar(CGFloat cgFloat) {
158 if (sizeof(CGFloat) == sizeof(float)) {
159 return SkFloatToScalar(cgFloat);
160 } else {
161 SkASSERT(sizeof(CGFloat) == sizeof(double));
162 return SkDoubleToScalar(cgFloat);
163 }
164 }
165
CGToFloat(CGFloat cgFloat)166 static float CGToFloat(CGFloat cgFloat) {
167 if (sizeof(CGFloat) == sizeof(float)) {
168 return cgFloat;
169 } else {
170 SkASSERT(sizeof(CGFloat) == sizeof(double));
171 return static_cast<float>(cgFloat);
172 }
173 }
174
MatrixToCGAffineTransform(const SkMatrix & matrix)175 static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix) {
176 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX]),
177 -ScalarToCG(matrix[SkMatrix::kMSkewY] ),
178 -ScalarToCG(matrix[SkMatrix::kMSkewX] ),
179 ScalarToCG(matrix[SkMatrix::kMScaleY]),
180 ScalarToCG(matrix[SkMatrix::kMTransX]),
181 ScalarToCG(matrix[SkMatrix::kMTransY]));
182 }
183
184 ///////////////////////////////////////////////////////////////////////////////
185
186 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
187
188 /** Drawn in FontForge, reduced with fonttools ttx, converted by xxd -i,
189 * this TrueType font contains a glyph of the spider.
190 *
191 * To re-forge the original bytes of the TrueType font file,
192 * remove all ',|( +0x)' from this definition,
193 * copy the data to the clipboard,
194 * run 'pbpaste | xxd -p -r - spider.ttf'.
195 */
196 static constexpr const uint8_t kSpiderSymbol_ttf[] = {
197 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x80, 0x00, 0x03, 0x00, 0x40,
198 0x47, 0x44, 0x45, 0x46, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x07, 0xa8,
199 0x00, 0x00, 0x00, 0x18, 0x4f, 0x53, 0x2f, 0x32, 0x8a, 0xf4, 0xfb, 0xdb,
200 0x00, 0x00, 0x01, 0x48, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6d, 0x61, 0x70,
201 0xe0, 0x7f, 0x10, 0x7e, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x54,
202 0x67, 0x61, 0x73, 0x70, 0xff, 0xff, 0x00, 0x03, 0x00, 0x00, 0x07, 0xa0,
203 0x00, 0x00, 0x00, 0x08, 0x67, 0x6c, 0x79, 0x66, 0x97, 0x0b, 0x6a, 0xf6,
204 0x00, 0x00, 0x02, 0x18, 0x00, 0x00, 0x03, 0x40, 0x68, 0x65, 0x61, 0x64,
205 0x0f, 0xa2, 0x24, 0x1a, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x36,
206 0x68, 0x68, 0x65, 0x61, 0x0e, 0xd3, 0x07, 0x3f, 0x00, 0x00, 0x01, 0x04,
207 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78, 0x10, 0x03, 0x00, 0x44,
208 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x0e, 0x6c, 0x6f, 0x63, 0x61,
209 0x01, 0xb4, 0x00, 0x28, 0x00, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x0a,
210 0x6d, 0x61, 0x78, 0x70, 0x00, 0x4a, 0x01, 0x4d, 0x00, 0x00, 0x01, 0x28,
211 0x00, 0x00, 0x00, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0xc3, 0xe5, 0x39, 0xd4,
212 0x00, 0x00, 0x05, 0x58, 0x00, 0x00, 0x02, 0x28, 0x70, 0x6f, 0x73, 0x74,
213 0xff, 0x03, 0x00, 0x67, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x20,
214 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0f, 0x08, 0x1d,
215 0x5f, 0x0f, 0x3c, 0xf5, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
216 0xd1, 0x97, 0xa8, 0x5a, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xe8, 0x32, 0x33,
217 0x00, 0x03, 0xff, 0x3b, 0x08, 0x00, 0x05, 0x55, 0x00, 0x00, 0x00, 0x08,
218 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
219 0x05, 0x55, 0xff, 0x3b, 0x01, 0x79, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00,
220 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00,
222 0x00, 0x04, 0x01, 0x1c, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
223 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x2e,
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x01, 0x90, 0x00, 0x05,
225 0x00, 0x00, 0x05, 0x33, 0x05, 0x99, 0x00, 0x00, 0x01, 0x1e, 0x05, 0x33,
226 0x05, 0x99, 0x00, 0x00, 0x03, 0xd7, 0x00, 0x66, 0x02, 0x12, 0x00, 0x00,
227 0x05, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0x00, 0x00, 0x73, 0x6b, 0x69, 0x61, 0x00, 0xc0, 0x00, 0x00, 0xf0, 0x21,
230 0x06, 0x66, 0xfe, 0x66, 0x01, 0x79, 0x05, 0x55, 0x00, 0xc5, 0x80, 0x00,
231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 0x00, 0x20, 0x00, 0x01, 0x08, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00,
233 0x08, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
234 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x48,
235 0x00, 0x00, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00,
236 0x00, 0x09, 0x00, 0x0d, 0x00, 0x1d, 0x00, 0x21, 0xf0, 0x21, 0xff, 0xff,
237 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x1d, 0x00, 0x21,
238 0xf0, 0x21, 0xff, 0xff, 0x00, 0x01, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xe4,
239 0xff, 0xe2, 0x0f, 0xe2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14,
241 0x00, 0x14, 0x00, 0x14, 0x01, 0xa0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x44,
242 0x00, 0x00, 0x02, 0x64, 0x05, 0x55, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00,
243 0x33, 0x11, 0x21, 0x11, 0x25, 0x21, 0x11, 0x21, 0x44, 0x02, 0x20, 0xfe,
244 0x24, 0x01, 0x98, 0xfe, 0x68, 0x05, 0x55, 0xfa, 0xab, 0x44, 0x04, 0xcd,
245 0x00, 0x04, 0x00, 0x03, 0xff, 0x3b, 0x08, 0x00, 0x05, 0x4c, 0x00, 0x15,
246 0x00, 0x1d, 0x00, 0x25, 0x01, 0x1b, 0x00, 0x00, 0x01, 0x36, 0x37, 0x36,
247 0x27, 0x26, 0x07, 0x06, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x26, 0x07,
248 0x06, 0x17, 0x16, 0x17, 0x16, 0x32, 0x37, 0x32, 0x35, 0x34, 0x23, 0x22,
249 0x15, 0x14, 0x27, 0x32, 0x35, 0x34, 0x23, 0x22, 0x15, 0x14, 0x03, 0x32,
250 0x17, 0x30, 0x17, 0x31, 0x36, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x33,
251 0x32, 0x33, 0x16, 0x33, 0x32, 0x17, 0x16, 0x07, 0x06, 0x23, 0x22, 0x27,
252 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
253 0x1f, 0x02, 0x37, 0x36, 0x37, 0x36, 0x33, 0x32, 0x17, 0x17, 0x16, 0x33,
254 0x16, 0x17, 0x16, 0x07, 0x06, 0x23, 0x22, 0x27, 0x27, 0x26, 0x23, 0x22,
255 0x07, 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x33, 0x32, 0x33, 0x32,
256 0x37, 0x36, 0x37, 0x36, 0x17, 0x16, 0x1f, 0x02, 0x16, 0x17, 0x16, 0x15,
257 0x14, 0x23, 0x22, 0x27, 0x27, 0x26, 0x27, 0x27, 0x26, 0x27, 0x26, 0x07,
258 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x07,
259 0x06, 0x23, 0x22, 0x27, 0x26, 0x07, 0x06, 0x07, 0x06, 0x15, 0x14, 0x17,
260 0x16, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27,
261 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x37, 0x34, 0x27, 0x26, 0x07,
262 0x06, 0x07, 0x06, 0x0f, 0x02, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x34,
263 0x37, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27,
264 0x26, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x07, 0x06, 0x23, 0x22,
265 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x37, 0x36, 0x37, 0x37, 0x36,
266 0x37, 0x36, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26,
267 0x23, 0x22, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x27, 0x26, 0x27, 0x26,
268 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x33, 0x32,
269 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36,
270 0x33, 0x04, 0xf5, 0x23, 0x13, 0x11, 0x14, 0x16, 0x1d, 0x1b, 0x4c, 0x1f,
271 0x0e, 0x2d, 0x23, 0x14, 0x2c, 0x13, 0x18, 0x25, 0x2c, 0x10, 0x3c, 0x71,
272 0x1d, 0x5c, 0x5c, 0x3f, 0xae, 0x5c, 0x5c, 0x3f, 0x6a, 0x27, 0x31, 0x5b,
273 0x09, 0x27, 0x36, 0x03, 0x0a, 0x26, 0x35, 0x2e, 0x09, 0x08, 0xc6, 0x13,
274 0x81, 0x17, 0x20, 0x18, 0x21, 0x1e, 0x04, 0x04, 0x15, 0x5c, 0x22, 0x26,
275 0x48, 0x56, 0x3b, 0x10, 0x21, 0x01, 0x0c, 0x06, 0x06, 0x0f, 0x31, 0x44,
276 0x3c, 0x52, 0x4a, 0x1d, 0x11, 0x3f, 0xb4, 0x71, 0x01, 0x26, 0x06, 0x0d,
277 0x15, 0x1a, 0x2a, 0x13, 0x53, 0xaa, 0x42, 0x1d, 0x0a, 0x33, 0x20, 0x21,
278 0x2b, 0x01, 0x02, 0x3e, 0x21, 0x09, 0x02, 0x02, 0x0f, 0x2d, 0x4b, 0x0a,
279 0x22, 0x15, 0x20, 0x1f, 0x72, 0x8b, 0x2d, 0x2f, 0x1d, 0x1f, 0x0e, 0x25,
280 0x3f, 0x4d, 0x1b, 0x63, 0x2a, 0x2c, 0x14, 0x22, 0x18, 0x1c, 0x0f, 0x08,
281 0x2a, 0x08, 0x08, 0x0d, 0x3b, 0x4c, 0x52, 0x74, 0x27, 0x71, 0x2e, 0x01,
282 0x0c, 0x10, 0x15, 0x0d, 0x06, 0x0d, 0x05, 0x01, 0x06, 0x2c, 0x28, 0x14,
283 0x1b, 0x05, 0x04, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x16, 0x27, 0x03, 0x0d,
284 0x30, 0x4c, 0x4c, 0x4b, 0x1f, 0x0b, 0x22, 0x26, 0x0d, 0x15, 0x0d, 0x2d,
285 0x68, 0x34, 0x14, 0x3c, 0x25, 0x12, 0x04, 0x10, 0x18, 0x0b, 0x09, 0x30,
286 0x2b, 0x44, 0x66, 0x14, 0x47, 0x47, 0x59, 0x73, 0x25, 0x05, 0x03, 0x1f,
287 0x01, 0x08, 0x3f, 0x48, 0x4b, 0x4b, 0x76, 0x2f, 0x49, 0x2d, 0x22, 0x24,
288 0x0c, 0x15, 0x08, 0x0e, 0x33, 0x03, 0x44, 0x4c, 0x10, 0x46, 0x13, 0x1f,
289 0x27, 0x1b, 0x1d, 0x13, 0x02, 0x24, 0x08, 0x02, 0x42, 0x0e, 0x4d, 0x3c,
290 0x19, 0x1b, 0x40, 0x2b, 0x2b, 0x1e, 0x16, 0x11, 0x04, 0x1f, 0x11, 0x04,
291 0x18, 0x11, 0x35, 0x01, 0xa3, 0x13, 0x24, 0x1f, 0x0b, 0x0c, 0x19, 0x19,
292 0x18, 0x13, 0x0f, 0x0c, 0x1a, 0x18, 0x1f, 0x19, 0x1e, 0x07, 0x1a, 0xc3,
293 0x54, 0x51, 0x54, 0x51, 0x04, 0x53, 0x51, 0x54, 0x50, 0x02, 0x48, 0x1a,
294 0x31, 0x18, 0x55, 0x74, 0x04, 0x0e, 0x09, 0x0d, 0x06, 0x10, 0x16, 0x1b,
295 0x24, 0x01, 0x04, 0x0b, 0x04, 0x10, 0x3f, 0x0a, 0x41, 0x02, 0x41, 0x20,
296 0x06, 0x12, 0x16, 0x21, 0x17, 0x2a, 0x1e, 0x15, 0x40, 0x27, 0x11, 0x0e,
297 0x1e, 0x11, 0x15, 0x1f, 0x43, 0x13, 0x1a, 0x10, 0x15, 0x1b, 0x04, 0x09,
298 0x4d, 0x2a, 0x0f, 0x19, 0x0a, 0x0a, 0x03, 0x05, 0x15, 0x3c, 0x64, 0x21,
299 0x4b, 0x2e, 0x21, 0x28, 0x13, 0x47, 0x44, 0x19, 0x3f, 0x11, 0x18, 0x0b,
300 0x0a, 0x07, 0x18, 0x0d, 0x07, 0x24, 0x2c, 0x2b, 0x21, 0x32, 0x10, 0x48,
301 0x2a, 0x2d, 0x1e, 0x1a, 0x01, 0x0c, 0x43, 0x59, 0x28, 0x4e, 0x1c, 0x0d,
302 0x5d, 0x24, 0x14, 0x0a, 0x05, 0x1f, 0x24, 0x32, 0x46, 0x3e, 0x5f, 0x3e,
303 0x44, 0x1a, 0x30, 0x15, 0x0d, 0x07, 0x18, 0x2b, 0x03, 0x0d, 0x1a, 0x28,
304 0x28, 0x57, 0xb2, 0x29, 0x27, 0x40, 0x2c, 0x23, 0x16, 0x63, 0x58, 0x1a,
305 0x0a, 0x18, 0x11, 0x23, 0x08, 0x1b, 0x29, 0x05, 0x04, 0x0b, 0x15, 0x0d,
306 0x14, 0x0b, 0x2a, 0x29, 0x5a, 0x62, 0x01, 0x19, 0x1e, 0x05, 0x05, 0x26,
307 0x42, 0x42, 0x2a, 0x2a, 0x3f, 0x0d, 0x0f, 0x09, 0x05, 0x07, 0x01, 0x0b,
308 0x25, 0x3e, 0x0d, 0x17, 0x11, 0x01, 0x03, 0x0d, 0x13, 0x20, 0x19, 0x11,
309 0x03, 0x02, 0x01, 0x04, 0x11, 0x04, 0x05, 0x1b, 0x3d, 0x10, 0x29, 0x20,
310 0x04, 0x04, 0x0a, 0x07, 0x04, 0x1f, 0x15, 0x20, 0x3e, 0x0f, 0x2a, 0x1e,
311 0x00, 0x00, 0x00, 0x1b, 0x01, 0x4a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
313 0x00, 0x01, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x02, 0x00, 0x07, 0x00, 0x27, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x03, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x04, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
317 0x00, 0x05, 0x00, 0x02, 0x00, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
318 0x00, 0x06, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
319 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x30, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09,
321 0x00, 0x00, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09,
322 0x00, 0x01, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09,
323 0x00, 0x02, 0x00, 0x0e, 0x00, 0x98, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09,
324 0x00, 0x03, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09,
325 0x00, 0x04, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09,
326 0x00, 0x05, 0x00, 0x04, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09,
327 0x00, 0x06, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09,
328 0x00, 0x0d, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09,
329 0x00, 0x0e, 0x00, 0x34, 0x00, 0xaa, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
330 0x00, 0x00, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
331 0x00, 0x01, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
332 0x00, 0x02, 0x00, 0x0e, 0x00, 0x98, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
333 0x00, 0x03, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
334 0x00, 0x04, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
335 0x00, 0x05, 0x00, 0x04, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
336 0x00, 0x06, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
337 0x00, 0x0d, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
338 0x00, 0x0e, 0x00, 0x34, 0x00, 0xaa, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69,
339 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x35,
340 0x2c, 0x20, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x53, 0x70, 0x69,
341 0x64, 0x65, 0x72, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x52, 0x65, 0x67,
342 0x75, 0x6c, 0x61, 0x72, 0x56, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
343 0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x2e, 0x73, 0x69, 0x6c,
344 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x4f, 0x46, 0x4c, 0x00, 0x43, 0x00, 0x6f,
345 0x00, 0x70, 0x00, 0x79, 0x00, 0x72, 0x00, 0x69, 0x00, 0x67, 0x00, 0x68,
346 0x00, 0x74, 0x00, 0x20, 0x00, 0x28, 0x00, 0x63, 0x00, 0x29, 0x00, 0x20,
347 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x20,
348 0x00, 0x47, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65,
349 0x00, 0x2e, 0x00, 0x53, 0x00, 0x70, 0x00, 0x69, 0x00, 0x64, 0x00, 0x65,
350 0x00, 0x72, 0x00, 0x53, 0x00, 0x79, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x6f,
351 0x00, 0x6c, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00, 0x6c,
352 0x00, 0x61, 0x00, 0x72, 0x00, 0x56, 0x00, 0x31, 0x00, 0x68, 0x00, 0x74,
353 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x73,
354 0x00, 0x63, 0x00, 0x72, 0x00, 0x69, 0x00, 0x70, 0x00, 0x74, 0x00, 0x73,
355 0x00, 0x2e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x2e, 0x00, 0x6f,
356 0x00, 0x72, 0x00, 0x67, 0x00, 0x2f, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x4c,
357 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x66,
358 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
360 0xff, 0xff, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
362 0x00, 0x02, 0x00, 0x00
363 };
364
365 enum class SmoothBehavior {
366 none, // SmoothFonts produces no effect.
367 some, // SmoothFonts produces some effect, but not subpixel coverage.
368 subpixel, // SmoothFonts produces some effect and provides subpixel coverage.
369 };
370
371 /**
372 * There does not appear to be a publicly accessable API for determining if lcd
373 * font smoothing will be applied if we request it. The main issue is that if
374 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0.
375 */
smooth_behavior()376 static SmoothBehavior smooth_behavior() {
377 static SmoothBehavior gSmoothBehavior = []{
378 uint32_t noSmoothBitmap[16][16] = {};
379 uint32_t smoothBitmap[16][16] = {};
380
381 SkUniqueCFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
382 SkUniqueCFRef<CGContextRef> noSmoothContext(
383 CGBitmapContextCreate(&noSmoothBitmap, 16, 16, 8, 16*4,
384 colorspace.get(), BITMAP_INFO_RGB));
385 SkUniqueCFRef<CGContextRef> smoothContext(
386 CGBitmapContextCreate(&smoothBitmap, 16, 16, 8, 16*4,
387 colorspace.get(), BITMAP_INFO_RGB));
388
389 SkUniqueCFRef<CGDataProviderRef> data(
390 CGDataProviderCreateWithData(nullptr, kSpiderSymbol_ttf,
391 SK_ARRAY_COUNT(kSpiderSymbol_ttf), nullptr));
392 SkUniqueCFRef<CGFontRef> cgFont(CGFontCreateWithDataProvider(data.get()));
393 SkASSERT(cgFont);
394 SkUniqueCFRef<CTFontRef> ctFont(
395 CTFontCreateWithGraphicsFont(cgFont.get(), 16, nullptr, nullptr));
396 SkASSERT(ctFont);
397
398 CGContextSetShouldSmoothFonts(noSmoothContext.get(), false);
399 CGContextSetShouldAntialias(noSmoothContext.get(), true);
400 CGContextSetTextDrawingMode(noSmoothContext.get(), kCGTextFill);
401 CGContextSetGrayFillColor(noSmoothContext.get(), 1, 1);
402
403 CGContextSetShouldSmoothFonts(smoothContext.get(), true);
404 CGContextSetShouldAntialias(smoothContext.get(), true);
405 CGContextSetTextDrawingMode(smoothContext.get(), kCGTextFill);
406 CGContextSetGrayFillColor(smoothContext.get(), 1, 1);
407
408 CGPoint point = CGPointMake(0, 3);
409 CGGlyph spiderGlyph = 3;
410 CTFontDrawGlyphs(ctFont.get(), &spiderGlyph, &point, 1, noSmoothContext.get());
411 CTFontDrawGlyphs(ctFont.get(), &spiderGlyph, &point, 1, smoothContext.get());
412
413 // For debugging.
414 //SkUniqueCFRef<CGImageRef> image(CGBitmapContextCreateImage(noSmoothContext()));
415 //SkUniqueCFRef<CGImageRef> image(CGBitmapContextCreateImage(smoothContext()));
416
417 SmoothBehavior smoothBehavior = SmoothBehavior::none;
418 for (int x = 0; x < 16; ++x) {
419 for (int y = 0; y < 16; ++y) {
420 uint32_t smoothPixel = smoothBitmap[x][y];
421 uint32_t r = (smoothPixel >> 16) & 0xFF;
422 uint32_t g = (smoothPixel >> 8) & 0xFF;
423 uint32_t b = (smoothPixel >> 0) & 0xFF;
424 if (r != g || r != b) {
425 return SmoothBehavior::subpixel;
426 }
427 if (noSmoothBitmap[x][y] != smoothPixel) {
428 smoothBehavior = SmoothBehavior::some;
429 }
430 }
431 }
432 return smoothBehavior;
433 }();
434 return gSmoothBehavior;
435 }
436
437 class Offscreen {
438 public:
Offscreen()439 Offscreen()
440 : fRGBSpace(nullptr)
441 , fCG(nullptr)
442 , fDoAA(false)
443 , fDoLCD(false)
444 {
445 fSize.set(0, 0);
446 }
447
448 CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
449 CGGlyph glyphID, size_t* rowBytesPtr, bool generateA8FromLCD,
450 bool lightOnDark);
451
452 private:
453 enum {
454 kSize = 32 * 32 * sizeof(CGRGBPixel)
455 };
456 SkAutoSMalloc<kSize> fImageStorage;
457 SkUniqueCFRef<CGColorSpaceRef> fRGBSpace;
458
459 // cached state
460 SkUniqueCFRef<CGContextRef> fCG;
461 SkISize fSize;
462 bool fDoAA;
463 bool fDoLCD;
464
RoundSize(int dimension)465 static int RoundSize(int dimension) {
466 return SkNextPow2(dimension);
467 }
468 };
469
470 ///////////////////////////////////////////////////////////////////////////////
471
find_dict_CGFloat(CFDictionaryRef dict,CFStringRef name,CGFloat * value)472 static bool find_dict_CGFloat(CFDictionaryRef dict, CFStringRef name, CGFloat* value) {
473 CFNumberRef num;
474 return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num)
475 && CFNumberIsFloatType(num)
476 && CFNumberGetValue(num, kCFNumberCGFloatType, value);
477 }
478
479 template <typename S, typename D, typename C> struct LinearInterpolater {
480 struct Mapping {
481 S src_val;
482 D dst_val;
483 };
LinearInterpolaterLinearInterpolater484 constexpr LinearInterpolater(Mapping const mapping[], int mappingCount)
485 : fMapping(mapping), fMappingCount(mappingCount) {}
486
mapLinearInterpolater487 static D map(S value, S src_min, S src_max, D dst_min, D dst_max) {
488 SkASSERT(src_min < src_max);
489 SkASSERT(dst_min <= dst_max);
490 return C()(dst_min + (((value - src_min) * (dst_max - dst_min)) / (src_max - src_min)));
491 }
492
mapLinearInterpolater493 D map(S val) const {
494 // -Inf to [0]
495 if (val < fMapping[0].src_val) {
496 return fMapping[0].dst_val;
497 }
498
499 // Linear from [i] to [i+1]
500 for (int i = 0; i < fMappingCount - 1; ++i) {
501 if (val < fMapping[i+1].src_val) {
502 return map(val, fMapping[i].src_val, fMapping[i+1].src_val,
503 fMapping[i].dst_val, fMapping[i+1].dst_val);
504 }
505 }
506
507 // From [n] to +Inf
508 // if (fcweight < Inf)
509 return fMapping[fMappingCount - 1].dst_val;
510 }
511
512 Mapping const * fMapping;
513 int fMappingCount;
514 };
515
516 struct RoundCGFloatToInt {
operator ()RoundCGFloatToInt517 int operator()(CGFloat s) { return s + 0.5; }
518 };
519 struct CGFloatIdentity {
operator ()CGFloatIdentity520 CGFloat operator()(CGFloat s) { return s; }
521 };
522
523 /** Returns the [-1, 1] CTFontDescriptor weights for the
524 * <0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000> CSS weights.
525 *
526 * It is assumed that the values will be interpolated linearly between these points.
527 * NSFontWeightXXX were added in 10.11, appear in 10.10, but do not appear in 10.9.
528 * The actual values appear to be stable, but they may change in the future without notice.
529 */
get_NSFontWeight_mapping()530 static CGFloat(&get_NSFontWeight_mapping())[11] {
531
532 // Declarations in <AppKit/AppKit.h> on macOS, <UIKit/UIKit.h> on iOS
533 #ifdef SK_BUILD_FOR_MAC
534 # define SK_KIT_FONT_WEIGHT_PREFIX "NS"
535 #endif
536 #ifdef SK_BUILD_FOR_IOS
537 # define SK_KIT_FONT_WEIGHT_PREFIX "UI"
538 #endif
539 static constexpr struct {
540 CGFloat defaultValue;
541 const char* name;
542 } nsFontWeightLoaderInfos[] = {
543 { -0.80f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightUltraLight" },
544 { -0.60f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightThin" },
545 { -0.40f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightLight" },
546 { 0.00f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightRegular" },
547 { 0.23f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightMedium" },
548 { 0.30f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightSemibold" },
549 { 0.40f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightBold" },
550 { 0.56f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightHeavy" },
551 { 0.62f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightBlack" },
552 };
553
554 static_assert(SK_ARRAY_COUNT(nsFontWeightLoaderInfos) == 9, "");
555 static CGFloat nsFontWeights[11];
556 static SkOnce once;
557 once([&] {
558 size_t i = 0;
559 nsFontWeights[i++] = -1.00;
560 for (const auto& nsFontWeightLoaderInfo : nsFontWeightLoaderInfos) {
561 void* nsFontWeightValuePtr = dlsym(RTLD_DEFAULT, nsFontWeightLoaderInfo.name);
562 if (nsFontWeightValuePtr) {
563 nsFontWeights[i++] = *(static_cast<CGFloat*>(nsFontWeightValuePtr));
564 } else {
565 nsFontWeights[i++] = nsFontWeightLoaderInfo.defaultValue;
566 }
567 }
568 nsFontWeights[i++] = 1.00;
569 });
570 return nsFontWeights;
571 }
572
573 /** Convert the [0, 1000] CSS weight to [-1, 1] CTFontDescriptor weight (for system fonts).
574 *
575 * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the
576 * CTFont is native or created from a CGDataProvider.
577 */
578 static CGFloat fontstyle_to_ct_weight(int fontstyleWeight) {
579 using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>;
580
581 // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100.
582 // However, on this end we can't tell, so this is ignored.
583
584 static Interpolator::Mapping nativeWeightMappings[11];
585 static SkOnce once;
__anon65e1c2df0602null586 once([&] {
587 CGFloat(&nsFontWeights)[11] = get_NSFontWeight_mapping();
588 for (int i = 0; i < 11; ++i) {
589 nativeWeightMappings[i].src_val = i * 100;
590 nativeWeightMappings[i].dst_val = nsFontWeights[i];
591 }
592 });
593 static constexpr Interpolator nativeInterpolator(
594 nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings));
595
596 return nativeInterpolator.map(fontstyleWeight);
597 }
598
599
600 /** Convert the [-1, 1] CTFontDescriptor weight to [0, 1000] CSS weight.
601 *
602 * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the
603 * CTFont is native or created from a CGDataProvider.
604 */
ct_weight_to_fontstyle(CGFloat cgWeight,bool fromDataProvider)605 static int ct_weight_to_fontstyle(CGFloat cgWeight, bool fromDataProvider) {
606 using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>;
607
608 // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100.
609 // However, on this end we can't tell, so this is ignored.
610
611 /** This mapping for CGDataProvider created fonts is determined by creating font data with every
612 * weight, creating a CTFont, and asking the CTFont for its weight. See the TypefaceStyle test
613 * in tests/TypefaceTest.cpp for the code used to determine these values.
614 */
615 static constexpr Interpolator::Mapping dataProviderWeightMappings[] = {
616 { -1.00, 0 },
617 { -0.70, 100 },
618 { -0.50, 200 },
619 { -0.23, 300 },
620 { 0.00, 400 },
621 { 0.20, 500 },
622 { 0.30, 600 },
623 { 0.40, 700 },
624 { 0.60, 800 },
625 { 0.80, 900 },
626 { 1.00, 1000 },
627 };
628 static constexpr Interpolator dataProviderInterpolator(
629 dataProviderWeightMappings, SK_ARRAY_COUNT(dataProviderWeightMappings));
630
631 static Interpolator::Mapping nativeWeightMappings[11];
632 static SkOnce once;
633 once([&] {
634 CGFloat(&nsFontWeights)[11] = get_NSFontWeight_mapping();
635 for (int i = 0; i < 11; ++i) {
636 nativeWeightMappings[i].src_val = nsFontWeights[i];
637 nativeWeightMappings[i].dst_val = i * 100;
638 }
639 });
640 static constexpr Interpolator nativeInterpolator(
641 nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings));
642
643 return fromDataProvider ? dataProviderInterpolator.map(cgWeight)
644 : nativeInterpolator.map(cgWeight);
645 }
646
647 /** Convert the [0, 10] CSS weight to [-1, 1] CTFontDescriptor width. */
fontstyle_to_ct_width(int fontstyleWidth)648 static int fontstyle_to_ct_width(int fontstyleWidth) {
649 using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>;
650
651 // Values determined by creating font data with every width, creating a CTFont,
652 // and asking the CTFont for its width. See TypefaceStyle test for basics.
653 static constexpr Interpolator::Mapping widthMappings[] = {
654 { 0, -0.5 },
655 { 10, 0.5 },
656 };
657 static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings));
658 return interpolator.map(fontstyleWidth);
659 }
660
661 /** Convert the [-1, 1] CTFontDescriptor width to [0, 10] CSS weight. */
ct_width_to_fontstyle(CGFloat cgWidth)662 static int ct_width_to_fontstyle(CGFloat cgWidth) {
663 using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>;
664
665 // Values determined by creating font data with every width, creating a CTFont,
666 // and asking the CTFont for its width. See TypefaceStyle test for basics.
667 static constexpr Interpolator::Mapping widthMappings[] = {
668 { -0.5, 0 },
669 { 0.5, 10 },
670 };
671 static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings));
672 return interpolator.map(cgWidth);
673 }
674
fontstyle_from_descriptor(CTFontDescriptorRef desc,bool fromDataProvider)675 static SkFontStyle fontstyle_from_descriptor(CTFontDescriptorRef desc, bool fromDataProvider) {
676 SkUniqueCFRef<CFTypeRef> traits(CTFontDescriptorCopyAttribute(desc, kCTFontTraitsAttribute));
677 if (!traits || CFDictionaryGetTypeID() != CFGetTypeID(traits.get())) {
678 return SkFontStyle();
679 }
680 SkUniqueCFRef<CFDictionaryRef> fontTraitsDict(static_cast<CFDictionaryRef>(traits.release()));
681
682 CGFloat weight, width, slant;
683 if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWeightTrait, &weight)) {
684 weight = 0;
685 }
686 if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWidthTrait, &width)) {
687 width = 0;
688 }
689 if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontSlantTrait, &slant)) {
690 slant = 0;
691 }
692
693 return SkFontStyle(ct_weight_to_fontstyle(weight, fromDataProvider),
694 ct_width_to_fontstyle(width),
695 slant ? SkFontStyle::kItalic_Slant
696 : SkFontStyle::kUpright_Slant);
697 }
698
699 class SkTypeface_Mac : public SkTypeface {
700 public:
SkTypeface_Mac(SkUniqueCFRef<CTFontRef> fontRef,SkUniqueCFRef<CFTypeRef> resourceRef,const SkFontStyle & fs,bool isFixedPitch,std::unique_ptr<SkStreamAsset> providedData)701 SkTypeface_Mac(SkUniqueCFRef<CTFontRef> fontRef, SkUniqueCFRef<CFTypeRef> resourceRef,
702 const SkFontStyle& fs, bool isFixedPitch,
703 std::unique_ptr<SkStreamAsset> providedData)
704 : SkTypeface(fs, isFixedPitch)
705 , fFontRef(std::move(fontRef))
706 , fOriginatingCFTypeRef(std::move(resourceRef))
707 , fHasColorGlyphs(
708 SkToBool(CTFontGetSymbolicTraits(fFontRef.get()) & kCTFontColorGlyphsTrait))
709 , fStream(std::move(providedData))
710 , fIsFromStream(fStream)
711 {
712 SkASSERT(fFontRef);
713 }
714
715 SkUniqueCFRef<CTFontRef> fFontRef;
716 SkUniqueCFRef<CFTypeRef> fOriginatingCFTypeRef;
717 const bool fHasColorGlyphs;
hasColorGlyphs() const718 bool hasColorGlyphs() const override { return fHasColorGlyphs; }
719
720 protected:
721 int onGetUPEM() const override;
722 std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override;
723 std::unique_ptr<SkFontData> onMakeFontData() const override;
724 int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
725 int coordinateCount) const override;
726 void onGetFamilyName(SkString* familyName) const override;
727 SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
728 int onGetTableTags(SkFontTableTag tags[]) const override;
729 size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
730 sk_sp<SkData> onCopyTableData(SkFontTableTag) const override;
731 SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
732 const SkDescriptor*) const override;
733 void onFilterRec(SkScalerContextRec*) const override;
734 void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
735 void getGlyphToUnicodeMap(SkUnichar*) const override;
736 std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override;
737 void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override;
738 int onCountGlyphs() const override;
getPostScriptGlyphNames(SkString *) const739 void getPostScriptGlyphNames(SkString*) const override {}
onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],int parameterCount) const740 int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
741 int parameterCount) const override
742 {
743 return -1;
744 }
onMakeClone(const SkFontArguments &) const745 sk_sp<SkTypeface> onMakeClone(const SkFontArguments&) const override {
746 return nullptr;
747 }
748
onGetCTFontRef() const749 void* onGetCTFontRef() const override { return (void*)fFontRef.get(); }
750
751 private:
752 mutable std::unique_ptr<SkStreamAsset> fStream;
753 bool fIsFromStream;
754 mutable SkOnce fInitStream;
755
756 typedef SkTypeface INHERITED;
757 };
758
find_by_CTFontRef(SkTypeface * cached,void * context)759 static bool find_by_CTFontRef(SkTypeface* cached, void* context) {
760 CTFontRef self = (CTFontRef)context;
761 CTFontRef other = (CTFontRef)cached->internal_private_getCTFontRef();
762
763 return CFEqual(self, other);
764 }
765
766 /** Creates a typeface, searching the cache if isLocalStream is false. */
create_from_CTFontRef(SkUniqueCFRef<CTFontRef> font,SkUniqueCFRef<CFTypeRef> resource,std::unique_ptr<SkStreamAsset> providedData)767 static sk_sp<SkTypeface> create_from_CTFontRef(SkUniqueCFRef<CTFontRef> font,
768 SkUniqueCFRef<CFTypeRef> resource,
769 std::unique_ptr<SkStreamAsset> providedData) {
770 SkASSERT(font);
771 const bool isFromStream(providedData);
772
773 if (!isFromStream) {
774 sk_sp<SkTypeface> face = SkTypefaceCache::FindByProcAndRef(find_by_CTFontRef,
775 (void*)font.get());
776 if (face) {
777 return face;
778 }
779 }
780
781 SkUniqueCFRef<CTFontDescriptorRef> desc(CTFontCopyFontDescriptor(font.get()));
782 SkFontStyle style = fontstyle_from_descriptor(desc.get(), isFromStream);
783 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font.get());
784 bool isFixedPitch = SkToBool(traits & kCTFontMonoSpaceTrait);
785
786 sk_sp<SkTypeface> face(new SkTypeface_Mac(std::move(font), std::move(resource),
787 style, isFixedPitch, std::move(providedData)));
788 if (!isFromStream) {
789 SkTypefaceCache::Add(face);
790 }
791 return face;
792 }
793
794 /** Creates a typeface from a descriptor, searching the cache. */
create_from_desc(CTFontDescriptorRef desc)795 static sk_sp<SkTypeface> create_from_desc(CTFontDescriptorRef desc) {
796 SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr));
797 if (!ctFont) {
798 return nullptr;
799 }
800
801 return create_from_CTFontRef(std::move(ctFont), nullptr, nullptr);
802 }
803
create_descriptor(const char familyName[],const SkFontStyle & style)804 static SkUniqueCFRef<CTFontDescriptorRef> create_descriptor(const char familyName[],
805 const SkFontStyle& style) {
806 SkUniqueCFRef<CFMutableDictionaryRef> cfAttributes(
807 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
808 &kCFTypeDictionaryKeyCallBacks,
809 &kCFTypeDictionaryValueCallBacks));
810
811 SkUniqueCFRef<CFMutableDictionaryRef> cfTraits(
812 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
813 &kCFTypeDictionaryKeyCallBacks,
814 &kCFTypeDictionaryValueCallBacks));
815
816 if (!cfAttributes || !cfTraits) {
817 return nullptr;
818 }
819
820 // CTFontTraits (symbolic)
821 // macOS 14 and iOS 12 seem to behave badly when kCTFontSymbolicTrait is set.
822
823 // CTFontTraits (weight)
824 CGFloat ctWeight = fontstyle_to_ct_weight(style.weight());
825 SkUniqueCFRef<CFNumberRef> cfFontWeight(
826 CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWeight));
827 if (cfFontWeight) {
828 CFDictionaryAddValue(cfTraits.get(), kCTFontWeightTrait, cfFontWeight.get());
829 }
830 // CTFontTraits (width)
831 CGFloat ctWidth = fontstyle_to_ct_width(style.width());
832 SkUniqueCFRef<CFNumberRef> cfFontWidth(
833 CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWidth));
834 if (cfFontWidth) {
835 CFDictionaryAddValue(cfTraits.get(), kCTFontWidthTrait, cfFontWidth.get());
836 }
837 // CTFontTraits (slant)
838 CGFloat ctSlant = style.slant() == SkFontStyle::kUpright_Slant ? 0 : 1;
839 SkUniqueCFRef<CFNumberRef> cfFontSlant(
840 CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctSlant));
841 if (cfFontSlant) {
842 CFDictionaryAddValue(cfTraits.get(), kCTFontSlantTrait, cfFontSlant.get());
843 }
844 // CTFontTraits
845 CFDictionaryAddValue(cfAttributes.get(), kCTFontTraitsAttribute, cfTraits.get());
846
847 // CTFontFamilyName
848 if (familyName) {
849 SkUniqueCFRef<CFStringRef> cfFontName = make_CFString(familyName);
850 if (cfFontName) {
851 CFDictionaryAddValue(cfAttributes.get(), kCTFontFamilyNameAttribute, cfFontName.get());
852 }
853 }
854
855 return SkUniqueCFRef<CTFontDescriptorRef>(
856 CTFontDescriptorCreateWithAttributes(cfAttributes.get()));
857 }
858
859 // Same as the above function except style is included so we can
860 // compare whether the created font conforms to the style. If not, we need
861 // to recreate the font with symbolic traits. This is needed due to MacOS 10.11
862 // font creation problem https://bugs.chromium.org/p/skia/issues/detail?id=8447.
create_from_desc_and_style(CTFontDescriptorRef desc,const SkFontStyle & style)863 static sk_sp<SkTypeface> create_from_desc_and_style(CTFontDescriptorRef desc,
864 const SkFontStyle& style) {
865 SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr));
866 if (!ctFont) {
867 return nullptr;
868 }
869
870 const CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctFont.get());
871 CTFontSymbolicTraits expected_traits = traits;
872 if (style.slant() != SkFontStyle::kUpright_Slant) {
873 expected_traits |= kCTFontItalicTrait;
874 }
875 if (style.weight() >= SkFontStyle::kBold_Weight) {
876 expected_traits |= kCTFontBoldTrait;
877 }
878
879 if (expected_traits != traits) {
880 SkUniqueCFRef<CTFontRef> ctNewFont(CTFontCreateCopyWithSymbolicTraits(ctFont.get(), 0, nullptr, expected_traits, expected_traits));
881 if (ctNewFont) {
882 ctFont = std::move(ctNewFont);
883 }
884 }
885
886 return create_from_CTFontRef(std::move(ctFont), nullptr, nullptr);
887 }
888
889 /** Creates a typeface from a name, searching the cache. */
create_from_name(const char familyName[],const SkFontStyle & style)890 static sk_sp<SkTypeface> create_from_name(const char familyName[], const SkFontStyle& style) {
891 SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
892 if (!desc) {
893 return nullptr;
894 }
895 return create_from_desc_and_style(desc.get(), style);
896 }
897
898 ///////////////////////////////////////////////////////////////////////////////
899
900 /* This function is visible on the outside. It first searches the cache, and if
901 * not found, returns a new entry (after adding it to the cache).
902 */
SkCreateTypefaceFromCTFont(CTFontRef font,CFTypeRef resource)903 SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef font, CFTypeRef resource) {
904 CFRetain(font);
905 if (resource) {
906 CFRetain(resource);
907 }
908 return create_from_CTFontRef(SkUniqueCFRef<CTFontRef>(font),
909 SkUniqueCFRef<CFTypeRef>(resource),
910 nullptr).release();
911 }
912
map_css_names(const char * name)913 static const char* map_css_names(const char* name) {
914 static const struct {
915 const char* fFrom; // name the caller specified
916 const char* fTo; // "canonical" name we map to
917 } gPairs[] = {
918 { "sans-serif", "Helvetica" },
919 { "serif", "Times" },
920 { "monospace", "Courier" }
921 };
922
923 for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
924 if (strcmp(name, gPairs[i].fFrom) == 0) {
925 return gPairs[i].fTo;
926 }
927 }
928 return name; // no change
929 }
930
931 ///////////////////////////////////////////////////////////////////////////////
932
933 class SkScalerContext_Mac : public SkScalerContext {
934 public:
935 SkScalerContext_Mac(sk_sp<SkTypeface_Mac>, const SkScalerContextEffects&, const SkDescriptor*);
936
937 protected:
938 unsigned generateGlyphCount(void) override;
939 bool generateAdvance(SkGlyph* glyph) override;
940 void generateMetrics(SkGlyph* glyph) override;
941 void generateImage(const SkGlyph& glyph) override;
942 bool generatePath(SkGlyphID glyph, SkPath* path) override;
943 void generateFontMetrics(SkFontMetrics*) override;
944
945 private:
946 static void CTPathElement(void *info, const CGPathElement *element);
947 template<bool APPLY_PREBLEND>
948 static void RGBToA8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes,
949 const SkGlyph& glyph, const uint8_t* table8);
950 template<bool APPLY_PREBLEND>
951 static uint16_t RGBToLcd16(CGRGBPixel rgb, const uint8_t* tableR,
952 const uint8_t* tableG,
953 const uint8_t* tableB);
954 template<bool APPLY_PREBLEND>
955 static void RGBToLcd16(const CGRGBPixel* SK_RESTRICT cgPixels,
956 size_t cgRowBytes,
957 const SkGlyph& glyph,
958 const uint8_t* tableR,
959 const uint8_t* tableG,
960 const uint8_t* tableB);
961
962 Offscreen fOffscreen;
963
964 /** Unrotated variant of fCTFont.
965 *
966 * In 10.10.1 CTFontGetAdvancesForGlyphs applies the font transform to the width of the
967 * advances, but always sets the height to 0. This font is used to get the advances of the
968 * unrotated glyph, and then the rotation is applied separately.
969 *
970 * CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise.
971 * This makes kCTFontOrientationDefault dangerous, because the metrics from
972 * kCTFontOrientationHorizontal are in a different space from kCTFontOrientationVertical.
973 * With kCTFontOrientationVertical the advances must be unrotated.
974 *
975 * Sometimes, creating a copy of a CTFont with the same size but different trasform will select
976 * different underlying font data. As a result, avoid ever creating more than one CTFont per
977 * SkScalerContext to ensure that only one CTFont is used.
978 *
979 * As a result of the above (and other constraints) this font contains the size, but not the
980 * transform. The transform must always be applied separately.
981 */
982 SkUniqueCFRef<CTFontRef> fCTFont;
983
984 /** The transform without the font size. */
985 CGAffineTransform fTransform;
986 CGAffineTransform fInvTransform;
987
988 SkUniqueCFRef<CGFontRef> fCGFont;
989 uint16_t fGlyphCount;
990 const bool fDoSubPosition;
991
992 friend class Offscreen;
993
994 typedef SkScalerContext INHERITED;
995 };
996
997 // CTFontCreateCopyWithAttributes or CTFontCreateCopyWithSymbolicTraits cannot be used on 10.10
998 // and later, as they will return different underlying fonts depending on the size requested.
ctfont_create_exact_copy(CTFontRef baseFont,CGFloat textSize,const CGAffineTransform * transform)999 static SkUniqueCFRef<CTFontRef> ctfont_create_exact_copy(CTFontRef baseFont, CGFloat textSize,
1000 const CGAffineTransform* transform)
1001 {
1002 // To figure out if a font is installed locally or used from a @font-face
1003 // resource, we check whether its descriptor can provide a URL. This will
1004 // be present for installed fonts, but not for those activated from an
1005 // in-memory resource.
1006 auto IsInstalledFont = [](CTFontRef aFont) {
1007 CTFontDescriptorRef desc = CTFontCopyFontDescriptor(aFont);
1008 CFTypeRef attr = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
1009 CFRelease(desc);
1010 bool result = false;
1011 if (attr) {
1012 result = true;
1013 CFRelease(attr);
1014 }
1015 return result;
1016 };
1017
1018 // If we have a system font we need to use the CGFont APIs to avoid having the
1019 // underlying font change for us when using CTFontCreateCopyWithAttributes.
1020 if (IsInstalledFont(baseFont)) {
1021 SkUniqueCFRef<CGFontRef> baseCGFont(CTFontCopyGraphicsFont(baseFont, nullptr));
1022
1023 // The last parameter (CTFontDescriptorRef attributes) *must* be nullptr.
1024 // If non-nullptr then with fonts with variation axes, the copy will fail in
1025 // CGFontVariationFromDictCallback when it assumes kCGFontVariationAxisName is CFNumberRef
1026 // which it quite obviously is not.
1027
1028 // Because we cannot setup the CTFont descriptor to match, the same restriction applies here
1029 // as other uses of CTFontCreateWithGraphicsFont which is that such CTFonts should not escape
1030 // the scaler context, since they aren't 'normal'.
1031
1032 // Avoid calling potentially buggy variation APIs on pre-Sierra macOS
1033 // versions (see bug 1331683).
1034 //
1035 // And on HighSierra, CTFontCreateWithGraphicsFont properly carries over
1036 // variation settings from the CGFont to CTFont, so we don't need to do
1037 // the extra work here -- and this seems to avoid Core Text crashiness
1038 // seen in bug 1454094.
1039 //
1040 // However, for installed fonts it seems we DO need to copy the variations
1041 // explicitly even on 10.13, otherwise fonts fail to render (as in bug
1042 // 1455494) when non-default values are used. Fortunately, the crash
1043 // mentioned above occurs with data fonts, not (AFAICT) with system-
1044 // installed fonts.
1045 //
1046 // So we only need to do this "the hard way" on Sierra, and for installed
1047 // fonts on HighSierra+; otherwise, just let the standard CTFont function
1048 // do its thing.
1049 //
1050 // NOTE in case this ever needs further adjustment: there is similar logic
1051 // in four places in the tree (sadly):
1052 // CreateCTFontFromCGFontWithVariations in gfxMacFont.cpp
1053 // CreateCTFontFromCGFontWithVariations in ScaledFontMac.cpp
1054 // CreateCTFontFromCGFontWithVariations in cairo-quartz-font.c
1055 // ctfont_create_exact_copy in SkFontHost_mac.cpp
1056
1057 // Not UniqueCFRef<> because CGFontCopyVariations can return null!
1058 CFDictionaryRef variations = CGFontCopyVariations(baseCGFont.get());
1059 if (variations) {
1060 SkUniqueCFRef<CFDictionaryRef>
1061 varAttr(CFDictionaryCreate(nullptr,
1062 (const void**)&kCTFontVariationAttribute,
1063 (const void**)&variations,
1064 1,
1065 &kCFTypeDictionaryKeyCallBacks,
1066 &kCFTypeDictionaryValueCallBacks));
1067 CFRelease(variations);
1068
1069 SkUniqueCFRef<CTFontDescriptorRef>
1070 varDesc(CTFontDescriptorCreateWithAttributes(varAttr.get()));
1071
1072 return SkUniqueCFRef<CTFontRef>(
1073 CTFontCreateWithGraphicsFont(baseCGFont.get(), textSize, transform, varDesc.get()));
1074 }
1075 return SkUniqueCFRef<CTFontRef>(
1076 CTFontCreateWithGraphicsFont(baseCGFont.get(), textSize, transform, nullptr));
1077 } else {
1078 return SkUniqueCFRef<CTFontRef>(CTFontCreateCopyWithAttributes(baseFont, textSize, transform, nullptr));
1079 }
1080 }
1081
SkScalerContext_Mac(sk_sp<SkTypeface_Mac> typeface,const SkScalerContextEffects & effects,const SkDescriptor * desc)1082 SkScalerContext_Mac::SkScalerContext_Mac(sk_sp<SkTypeface_Mac> typeface,
1083 const SkScalerContextEffects& effects,
1084 const SkDescriptor* desc)
1085 : INHERITED(std::move(typeface), effects, desc)
1086 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag))
1087
1088 {
1089 CTFontRef ctFont = (CTFontRef)this->getTypeface()->internal_private_getCTFontRef();
1090 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
1091 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
1092 fGlyphCount = SkToU16(numGlyphs);
1093
1094 // CT on (at least) 10.9 will size color glyphs down from the requested size, but not up.
1095 // As a result, it is necessary to know the actual device size and request that.
1096 SkVector scale;
1097 SkMatrix skTransform;
1098 bool invertible = fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale,
1099 &scale, &skTransform, nullptr, nullptr, nullptr);
1100 fTransform = MatrixToCGAffineTransform(skTransform);
1101 // CGAffineTransformInvert documents that if the transform is non-invertible it will return the
1102 // passed transform unchanged. It does so, but then also prints a message to stdout. Avoid this.
1103 if (invertible) {
1104 fInvTransform = CGAffineTransformInvert(fTransform);
1105 } else {
1106 fInvTransform = fTransform;
1107 }
1108
1109 // The transform contains everything except the requested text size.
1110 // Some properties, like 'trak', are based on the text size (before applying the matrix).
1111 CGFloat textSize = ScalarToCG(scale.y());
1112 fCTFont = ctfont_create_exact_copy(ctFont, textSize, nullptr);
1113 fCGFont.reset(CTFontCopyGraphicsFont(fCTFont.get(), nullptr));
1114 }
1115
getCG(const SkScalerContext_Mac & context,const SkGlyph & glyph,CGGlyph glyphID,size_t * rowBytesPtr,bool generateA8FromLCD,bool lightOnDark)1116 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
1117 CGGlyph glyphID, size_t* rowBytesPtr,
1118 bool generateA8FromLCD, bool lightOnDark) {
1119 if (!fRGBSpace) {
1120 //It doesn't appear to matter what color space is specified.
1121 //Regular blends and antialiased text are always (s*a + d*(1-a))
1122 //and subpixel antialiased text is always g=2.0.
1123 fRGBSpace.reset(CGColorSpaceCreateDeviceRGB());
1124 }
1125
1126 // default to kBW_Format
1127 bool doAA = false;
1128 bool doLCD = false;
1129
1130 if (SkMask::kBW_Format != glyph.maskFormat()) {
1131 doLCD = true;
1132 doAA = true;
1133 }
1134
1135 // FIXME: lcd smoothed un-hinted rasterization unsupported.
1136 if (!generateA8FromLCD && SkMask::kA8_Format == glyph.maskFormat()) {
1137 doLCD = false;
1138 doAA = true;
1139 }
1140
1141 // If this font might have color glyphs, disable LCD as there's no way to support it.
1142 // CoreText doesn't tell us which format it ended up using, so we can't detect it.
1143 // A8 will end up black on transparent, but TODO: we can detect gray and set to A8.
1144 if (SkMask::kARGB32_Format == glyph.maskFormat()) {
1145 doLCD = false;
1146 }
1147
1148 size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
1149 if (!fCG || fSize.fWidth < glyph.width() || fSize.fHeight < glyph.height()) {
1150 if (fSize.fWidth < glyph.width()) {
1151 fSize.fWidth = RoundSize(glyph.width());
1152 }
1153 if (fSize.fHeight < glyph.height()) {
1154 fSize.fHeight = RoundSize(glyph.height());
1155 }
1156
1157 rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
1158 void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
1159 const CGImageAlphaInfo alpha = (glyph.isColor())
1160 ? kCGImageAlphaPremultipliedFirst
1161 : kCGImageAlphaNoneSkipFirst;
1162 const CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | alpha;
1163 fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
1164 rowBytes, fRGBSpace.get(), bitmapInfo));
1165
1166 // Skia handles quantization and subpixel positioning,
1167 // so disable quantization and enabe subpixel positioning in CG.
1168 CGContextSetAllowsFontSubpixelQuantization(fCG.get(), false);
1169 CGContextSetShouldSubpixelQuantizeFonts(fCG.get(), false);
1170
1171 // Because CG always draws from the horizontal baseline,
1172 // if there is a non-integral translation from the horizontal origin to the vertical origin,
1173 // then CG cannot draw the glyph in the correct location without subpixel positioning.
1174 CGContextSetAllowsFontSubpixelPositioning(fCG.get(), true);
1175 CGContextSetShouldSubpixelPositionFonts(fCG.get(), true);
1176
1177 CGContextSetTextDrawingMode(fCG.get(), kCGTextFill);
1178
1179 // Draw black on white to create mask. (Special path exists to speed this up in CG.)
1180 // If light-on-dark is requested, draw white on black.
1181 CGContextSetGrayFillColor(fCG.get(), lightOnDark ? 1.0f : 0.0f, 1.0f);
1182
1183 // force our checks below to happen
1184 fDoAA = !doAA;
1185 fDoLCD = !doLCD;
1186
1187 CGContextSetTextMatrix(fCG.get(), context.fTransform);
1188 }
1189
1190 if (fDoAA != doAA) {
1191 CGContextSetShouldAntialias(fCG.get(), doAA);
1192 fDoAA = doAA;
1193 }
1194 if (fDoLCD != doLCD) {
1195 CGContextSetShouldSmoothFonts(fCG.get(), doLCD);
1196 fDoLCD = doLCD;
1197 }
1198
1199 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
1200 // skip rows based on the glyph's height
1201 image += (fSize.fHeight - glyph.height()) * fSize.fWidth;
1202
1203 // Erase to white (or transparent black if it's a color glyph, to not composite against white).
1204 // For light-on-dark, instead erase to black.
1205 uint32_t bgColor = (!glyph.isColor()) ? (lightOnDark ? 0xFF000000 : 0xFFFFFFFF) : 0x00000000;
1206 sk_memset_rect32(image, bgColor, glyph.width(), glyph.height(), rowBytes);
1207
1208 float subX = 0;
1209 float subY = 0;
1210 if (context.fDoSubPosition) {
1211 subX = SkFixedToFloat(glyph.getSubXFixed());
1212 subY = SkFixedToFloat(glyph.getSubYFixed());
1213 }
1214
1215 CGPoint point = CGPointMake(-glyph.left() + subX, glyph.top() + glyph.height() - subY);
1216 // Prior to 10.10, CTFontDrawGlyphs acted like CGContextShowGlyphsAtPositions and took
1217 // 'positions' which are in text space. The glyph location (in device space) must be
1218 // mapped into text space, so that CG can convert it back into device space.
1219 // In 10.10.1, this is handled directly in CTFontDrawGlyphs.
1220 //
1221 // However, in 10.10.2 color glyphs no longer rotate based on the font transform.
1222 // So always make the font transform identity and place the transform on the context.
1223 point = CGPointApplyAffineTransform(point, context.fInvTransform);
1224
1225 CTFontDrawGlyphs(context.fCTFont.get(), &glyphID, &point, 1, fCG.get());
1226
1227 SkASSERT(rowBytesPtr);
1228 *rowBytesPtr = rowBytes;
1229 return image;
1230 }
1231
generateGlyphCount(void)1232 unsigned SkScalerContext_Mac::generateGlyphCount(void) {
1233 return fGlyphCount;
1234 }
1235
generateAdvance(SkGlyph * glyph)1236 bool SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
1237 return false;
1238 }
1239
generateMetrics(SkGlyph * glyph)1240 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
1241 glyph->fMaskFormat = fRec.fMaskFormat;
1242
1243 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID();
1244 glyph->zeroMetrics();
1245
1246 // The following block produces cgAdvance in CG units (pixels, y up).
1247 CGSize cgAdvance;
1248 CTFontGetAdvancesForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal,
1249 &cgGlyph, &cgAdvance, 1);
1250 cgAdvance = CGSizeApplyAffineTransform(cgAdvance, fTransform);
1251 glyph->fAdvanceX = CGToFloat(cgAdvance.width);
1252 glyph->fAdvanceY = -CGToFloat(cgAdvance.height);
1253
1254 // The following produces skBounds in SkGlyph units (pixels, y down),
1255 // or returns early if skBounds would be empty.
1256 SkRect skBounds;
1257
1258 // Glyphs are always drawn from the horizontal origin. The caller must manually use the result
1259 // of CTFontGetVerticalTranslationsForGlyphs to calculate where to draw the glyph for vertical
1260 // glyphs. As a result, always get the horizontal bounds of a glyph and translate it if the
1261 // glyph is vertical. This avoids any diagreement between the various means of retrieving
1262 // vertical metrics.
1263 {
1264 // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up).
1265 CGRect cgBounds;
1266 CTFontGetBoundingRectsForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal,
1267 &cgGlyph, &cgBounds, 1);
1268 cgBounds = CGRectApplyAffineTransform(cgBounds, fTransform);
1269
1270 // BUG?
1271 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when
1272 // it should be empty. So, if we see a zero-advance, we check if it has an
1273 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance
1274 // is rare, so we won't incur a big performance cost for this extra check.
1275 // Avoid trying to create a path from a color font due to crashing on 10.9.
1276 if (0 == cgAdvance.width && 0 == cgAdvance.height &&
1277 SkMask::kARGB32_Format != glyph->fMaskFormat) {
1278 SkUniqueCFRef<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph,nullptr));
1279 if (!path || CGPathIsEmpty(path.get())) {
1280 return;
1281 }
1282 }
1283
1284 if (CGRectIsEmpty_inline(cgBounds)) {
1285 return;
1286 }
1287
1288 // Convert cgBounds to SkGlyph units (pixels, y down).
1289 skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height,
1290 cgBounds.size.width, cgBounds.size.height);
1291 }
1292
1293 // Currently the bounds are based on being rendered at (0,0).
1294 // The top left must not move, since that is the base from which subpixel positioning is offset.
1295 if (fDoSubPosition) {
1296 skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed());
1297 skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed());
1298 }
1299
1300 // We're trying to pack left and top into int16_t,
1301 // and width and height into uint16_t, after outsetting by 1.
1302 if (!SkRect::MakeXYWH(-32767, -32767, 65535, 65535).contains(skBounds)) {
1303 return;
1304 }
1305
1306 SkIRect skIBounds;
1307 skBounds.roundOut(&skIBounds);
1308 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
1309 // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
1310 // is not currently known, as CG dilates the outlines by some percentage.
1311 // Note that if this context is A8 and not back-forming from LCD, there is no need to outset.
1312 skIBounds.outset(1, 1);
1313 glyph->fLeft = SkToS16(skIBounds.fLeft);
1314 glyph->fTop = SkToS16(skIBounds.fTop);
1315 glyph->fWidth = SkToU16(skIBounds.width());
1316 glyph->fHeight = SkToU16(skIBounds.height());
1317 }
1318
1319 #include "include/private/SkColorData.h"
1320
sk_pow2_table(size_t i)1321 static constexpr uint8_t sk_pow2_table(size_t i) {
1322 return SkToU8(((i * i + 128) / 255));
1323 }
1324
1325 /**
1326 * This will invert the gamma applied by CoreGraphics, so we can get linear
1327 * values.
1328 *
1329 * CoreGraphics obscurely defaults to 2.0 as the subpixel coverage gamma value.
1330 * The color space used does not appear to affect this choice.
1331 */
1332 static constexpr auto gLinearCoverageFromCGLCDValue = SkMakeArray<256>(sk_pow2_table);
1333
cgpixels_to_bits(uint8_t dst[],const CGRGBPixel src[],int count)1334 static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
1335 while (count > 0) {
1336 uint8_t mask = 0;
1337 for (int i = 7; i >= 0; --i) {
1338 mask |= ((CGRGBPixel_getAlpha(*src++) >> 7) ^ 0x1) << i;
1339 if (0 == --count) {
1340 break;
1341 }
1342 }
1343 *dst++ = mask;
1344 }
1345 }
1346
1347 template<bool APPLY_PREBLEND>
rgb_to_a8(CGRGBPixel rgb,const uint8_t * table8)1348 static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) {
1349 U8CPU r = 0xFF - ((rgb >> 16) & 0xFF);
1350 U8CPU g = 0xFF - ((rgb >> 8) & 0xFF);
1351 U8CPU b = 0xFF - ((rgb >> 0) & 0xFF);
1352 U8CPU lum = sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1353 #if SK_SHOW_TEXT_BLIT_COVERAGE
1354 lum = SkTMax(lum, (U8CPU)0x30);
1355 #endif
1356 return lum;
1357 }
1358
1359 template<bool APPLY_PREBLEND>
RGBToA8(const CGRGBPixel * SK_RESTRICT cgPixels,size_t cgRowBytes,const SkGlyph & glyph,const uint8_t * table8)1360 void SkScalerContext_Mac::RGBToA8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes,
1361 const SkGlyph& glyph, const uint8_t* table8) {
1362 const int width = glyph.fWidth;
1363 size_t dstRB = glyph.rowBytes();
1364 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
1365
1366 for (int y = 0; y < glyph.fHeight; y++) {
1367 for (int i = 0; i < width; ++i) {
1368 dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8);
1369 }
1370 cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes);
1371 dst = SkTAddOffset<uint8_t>(dst, dstRB);
1372 }
1373 }
1374
1375 template<bool APPLY_PREBLEND>
RGBToLcd16(CGRGBPixel rgb,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1376 uint16_t SkScalerContext_Mac::RGBToLcd16(CGRGBPixel rgb, const uint8_t* tableR,
1377 const uint8_t* tableG,
1378 const uint8_t* tableB) {
1379 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 16) & 0xFF), tableR);
1380 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 8) & 0xFF), tableG);
1381 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 0) & 0xFF), tableB);
1382 #if SK_SHOW_TEXT_BLIT_COVERAGE
1383 r = SkTMax(r, (U8CPU)0x30);
1384 g = SkTMax(g, (U8CPU)0x30);
1385 b = SkTMax(b, (U8CPU)0x30);
1386 #endif
1387 return SkPack888ToRGB16(r, g, b);
1388 }
1389
1390 template<bool APPLY_PREBLEND>
RGBToLcd16(const CGRGBPixel * SK_RESTRICT cgPixels,size_t cgRowBytes,const SkGlyph & glyph,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1391 void SkScalerContext_Mac::RGBToLcd16(const CGRGBPixel* SK_RESTRICT cgPixels,
1392 size_t cgRowBytes,
1393 const SkGlyph& glyph,
1394 const uint8_t* tableR,
1395 const uint8_t* tableG,
1396 const uint8_t* tableB) {
1397 const int width = glyph.fWidth;
1398 size_t dstRB = glyph.rowBytes();
1399 uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage;
1400
1401 for (int y = 0; y < glyph.fHeight; y++) {
1402 for (int i = 0; i < width; i++) {
1403 dst[i] = RGBToLcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
1404 }
1405 cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes);
1406 dst = SkTAddOffset<uint16_t>(dst, dstRB);
1407 }
1408 }
1409
cgpixels_to_pmcolor(CGRGBPixel rgb)1410 static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb) {
1411 U8CPU a = (rgb >> 24) & 0xFF;
1412 U8CPU r = (rgb >> 16) & 0xFF;
1413 U8CPU g = (rgb >> 8) & 0xFF;
1414 U8CPU b = (rgb >> 0) & 0xFF;
1415 #if SK_SHOW_TEXT_BLIT_COVERAGE
1416 a = SkTMax(a, (U8CPU)0x30);
1417 #endif
1418 return SkPackARGB32(a, r, g, b);
1419 }
1420
generateImage(const SkGlyph & glyph)1421 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
1422 CGGlyph cgGlyph = SkTo<CGGlyph>(glyph.getGlyphID());
1423
1424 // FIXME: lcd smoothed un-hinted rasterization unsupported.
1425 bool requestSmooth = fRec.getHinting() != SkFontHinting::kNone;
1426 bool lightOnDark = (fRec.fFlags & SkScalerContext::kLightOnDark_Flag) != 0;
1427
1428 // Draw the glyph
1429 size_t cgRowBytes;
1430 CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, requestSmooth, lightOnDark);
1431 if (cgPixels == nullptr) {
1432 return;
1433 }
1434
1435 // Fix the glyph
1436 if ((glyph.fMaskFormat == SkMask::kLCD16_Format) ||
1437 (glyph.fMaskFormat == SkMask::kA8_Format
1438 && requestSmooth
1439 && smooth_behavior() != SmoothBehavior::none))
1440 {
1441 const uint8_t* linear = gLinearCoverageFromCGLCDValue.data();
1442
1443 //Note that the following cannot really be integrated into the
1444 //pre-blend, since we may not be applying the pre-blend; when we aren't
1445 //applying the pre-blend it means that a filter wants linear anyway.
1446 //Other code may also be applying the pre-blend, so we'd need another
1447 //one with this and one without.
1448 CGRGBPixel* addr = cgPixels;
1449 for (int y = 0; y < glyph.fHeight; ++y) {
1450 for (int x = 0; x < glyph.fWidth; ++x) {
1451 int r = linear[(addr[x] >> 16) & 0xFF];
1452 int g = linear[(addr[x] >> 8) & 0xFF];
1453 int b = linear[(addr[x] >> 0) & 0xFF];
1454 // If light-on-dark was requested, the mask is drawn inverted.
1455 if (lightOnDark) {
1456 r = 255 - r;
1457 g = 255 - g;
1458 b = 255 - b;
1459 }
1460 addr[x] = (r << 16) | (g << 8) | b;
1461 }
1462 addr = SkTAddOffset<CGRGBPixel>(addr, cgRowBytes);
1463 }
1464 }
1465
1466 // Convert glyph to mask
1467 switch (glyph.fMaskFormat) {
1468 case SkMask::kLCD16_Format: {
1469 if (fPreBlend.isApplicable()) {
1470 RGBToLcd16<true>(cgPixels, cgRowBytes, glyph,
1471 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1472 } else {
1473 RGBToLcd16<false>(cgPixels, cgRowBytes, glyph,
1474 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1475 }
1476 } break;
1477 case SkMask::kA8_Format: {
1478 if (fPreBlend.isApplicable()) {
1479 RGBToA8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1480 } else {
1481 RGBToA8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1482 }
1483 } break;
1484 case SkMask::kBW_Format: {
1485 const int width = glyph.fWidth;
1486 size_t dstRB = glyph.rowBytes();
1487 uint8_t* dst = (uint8_t*)glyph.fImage;
1488 for (int y = 0; y < glyph.fHeight; y++) {
1489 cgpixels_to_bits(dst, cgPixels, width);
1490 cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes);
1491 dst = SkTAddOffset<uint8_t>(dst, dstRB);
1492 }
1493 } break;
1494 case SkMask::kARGB32_Format: {
1495 const int width = glyph.fWidth;
1496 size_t dstRB = glyph.rowBytes();
1497 SkPMColor* dst = (SkPMColor*)glyph.fImage;
1498 for (int y = 0; y < glyph.fHeight; y++) {
1499 for (int x = 0; x < width; ++x) {
1500 dst[x] = cgpixels_to_pmcolor(cgPixels[x]);
1501 }
1502 cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes);
1503 dst = SkTAddOffset<SkPMColor>(dst, dstRB);
1504 }
1505 } break;
1506 default:
1507 SkDEBUGFAIL("unexpected mask format");
1508 break;
1509 }
1510 }
1511
1512 /*
1513 * Our subpixel resolution is only 2 bits in each direction, so a scale of 4
1514 * seems sufficient, and possibly even correct, to allow the hinted outline
1515 * to be subpixel positioned.
1516 */
1517 #define kScaleForSubPixelPositionHinting (4.0f)
1518
generatePath(SkGlyphID glyph,SkPath * path)1519 bool SkScalerContext_Mac::generatePath(SkGlyphID glyph, SkPath* path) {
1520 SkScalar scaleX = SK_Scalar1;
1521 SkScalar scaleY = SK_Scalar1;
1522
1523 CGAffineTransform xform = fTransform;
1524 /*
1525 * For subpixel positioning, we want to return an unhinted outline, so it
1526 * can be positioned nicely at fractional offsets. However, we special-case
1527 * if the baseline of the (horizontal) text is axis-aligned. In those cases
1528 * we want to retain hinting in the direction orthogonal to the baseline.
1529 * e.g. for horizontal baseline, we want to retain hinting in Y.
1530 * The way we remove hinting is to scale the font by some value (4) in that
1531 * direction, ask for the path, and then scale the path back down.
1532 */
1533 if (fDoSubPosition) {
1534 // start out by assuming that we want no hining in X and Y
1535 scaleX = scaleY = kScaleForSubPixelPositionHinting;
1536 // now see if we need to restore hinting for axis-aligned baselines
1537 switch (this->computeAxisAlignmentForHText()) {
1538 case kX_SkAxisAlignment:
1539 scaleY = SK_Scalar1; // want hinting in the Y direction
1540 break;
1541 case kY_SkAxisAlignment:
1542 scaleX = SK_Scalar1; // want hinting in the X direction
1543 break;
1544 default:
1545 break;
1546 }
1547
1548 CGAffineTransform scale(CGAffineTransformMakeScale(ScalarToCG(scaleX), ScalarToCG(scaleY)));
1549 xform = CGAffineTransformConcat(fTransform, scale);
1550 }
1551
1552 CGGlyph cgGlyph = SkTo<CGGlyph>(glyph);
1553 SkUniqueCFRef<CGPathRef> cgPath(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph, &xform));
1554
1555 path->reset();
1556 if (!cgPath) {
1557 return false;
1558 }
1559
1560 CGPathApply(cgPath.get(), path, SkScalerContext_Mac::CTPathElement);
1561 if (fDoSubPosition) {
1562 SkMatrix m;
1563 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY));
1564 path->transform(m);
1565 }
1566 return true;
1567 }
1568
generateFontMetrics(SkFontMetrics * metrics)1569 void SkScalerContext_Mac::generateFontMetrics(SkFontMetrics* metrics) {
1570 if (nullptr == metrics) {
1571 return;
1572 }
1573
1574 CGRect theBounds = CTFontGetBoundingBox(fCTFont.get());
1575
1576 metrics->fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds));
1577 metrics->fAscent = CGToScalar(-CTFontGetAscent(fCTFont.get()));
1578 metrics->fDescent = CGToScalar( CTFontGetDescent(fCTFont.get()));
1579 metrics->fBottom = CGToScalar(-CGRectGetMinY_inline(theBounds));
1580 metrics->fLeading = CGToScalar( CTFontGetLeading(fCTFont.get()));
1581 metrics->fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds));
1582 metrics->fXMin = CGToScalar( CGRectGetMinX_inline(theBounds));
1583 metrics->fXMax = CGToScalar( CGRectGetMaxX_inline(theBounds));
1584 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
1585 metrics->fXHeight = CGToScalar( CTFontGetXHeight(fCTFont.get()));
1586 metrics->fCapHeight = CGToScalar( CTFontGetCapHeight(fCTFont.get()));
1587 metrics->fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont.get()));
1588 metrics->fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont.get()));
1589
1590 metrics->fFlags = 0;
1591 metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag;
1592 metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag;
1593
1594 // See https://bugs.chromium.org/p/skia/issues/detail?id=6203
1595 // At least on 10.12.3 with memory based fonts the x-height is always 0.6666 of the ascent and
1596 // the cap-height is always 0.8888 of the ascent. It appears that the values from the 'OS/2'
1597 // table are read, but then overwritten if the font is not a system font. As a result, if there
1598 // is a valid 'OS/2' table available use the values from the table if they aren't too strange.
1599 struct OS2HeightMetrics {
1600 SK_OT_SHORT sxHeight;
1601 SK_OT_SHORT sCapHeight;
1602 } heights;
1603 size_t bytesRead = this->getTypeface()->getTableData(
1604 SkTEndian_SwapBE32(SkOTTableOS2::TAG), offsetof(SkOTTableOS2, version.v2.sxHeight),
1605 sizeof(heights), &heights);
1606 if (bytesRead == sizeof(heights)) {
1607 // 'fontSize' is correct because the entire resolved size is set by the constructor.
1608 CGFloat fontSize = CTFontGetSize(this->fCTFont.get());
1609 unsigned upem = CTFontGetUnitsPerEm(this->fCTFont.get());
1610 unsigned maxSaneHeight = upem * 2;
1611 uint16_t xHeight = SkEndian_SwapBE16(heights.sxHeight);
1612 if (xHeight && xHeight < maxSaneHeight) {
1613 metrics->fXHeight = CGToScalar(xHeight * fontSize / upem);
1614 }
1615 uint16_t capHeight = SkEndian_SwapBE16(heights.sCapHeight);
1616 if (capHeight && capHeight < maxSaneHeight) {
1617 metrics->fCapHeight = CGToScalar(capHeight * fontSize / upem);
1618 }
1619 }
1620 }
1621
CTPathElement(void * info,const CGPathElement * element)1622 void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) {
1623 SkPath* skPath = (SkPath*)info;
1624
1625 // Process the path element
1626 switch (element->type) {
1627 case kCGPathElementMoveToPoint:
1628 skPath->moveTo(element->points[0].x, -element->points[0].y);
1629 break;
1630
1631 case kCGPathElementAddLineToPoint:
1632 skPath->lineTo(element->points[0].x, -element->points[0].y);
1633 break;
1634
1635 case kCGPathElementAddQuadCurveToPoint:
1636 skPath->quadTo(element->points[0].x, -element->points[0].y,
1637 element->points[1].x, -element->points[1].y);
1638 break;
1639
1640 case kCGPathElementAddCurveToPoint:
1641 skPath->cubicTo(element->points[0].x, -element->points[0].y,
1642 element->points[1].x, -element->points[1].y,
1643 element->points[2].x, -element->points[2].y);
1644 break;
1645
1646 case kCGPathElementCloseSubpath:
1647 skPath->close();
1648 break;
1649
1650 default:
1651 SkDEBUGFAIL("Unknown path element!");
1652 break;
1653 }
1654 }
1655
1656
1657 ///////////////////////////////////////////////////////////////////////////////
1658
1659 // Returns nullptr on failure
1660 // Call must still manage its ownership of provider
create_from_dataProvider(SkUniqueCFRef<CGDataProviderRef> provider,std::unique_ptr<SkStreamAsset> providedData,int ttcIndex)1661 static sk_sp<SkTypeface> create_from_dataProvider(SkUniqueCFRef<CGDataProviderRef> provider,
1662 std::unique_ptr<SkStreamAsset> providedData,
1663 int ttcIndex) {
1664 if (ttcIndex != 0) {
1665 return nullptr;
1666 }
1667 SkUniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
1668 if (!cg) {
1669 return nullptr;
1670 }
1671 SkUniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg.get(), 0, nullptr, nullptr));
1672 if (!ct) {
1673 return nullptr;
1674 }
1675 return create_from_CTFontRef(std::move(ct), nullptr, std::move(providedData));
1676 }
1677
1678 // Web fonts added to the CTFont registry do not return their character set.
1679 // Iterate through the font in this case. The existing caller caches the result,
1680 // so the performance impact isn't too bad.
populate_glyph_to_unicode_slow(CTFontRef ctFont,CFIndex glyphCount,SkUnichar * out)1681 static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
1682 SkUnichar* out) {
1683 sk_bzero(out, glyphCount * sizeof(SkUnichar));
1684 UniChar unichar = 0;
1685 while (glyphCount > 0) {
1686 CGGlyph glyph;
1687 if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1688 if (out[glyph] == 0) {
1689 out[glyph] = unichar;
1690 --glyphCount;
1691 }
1692 }
1693 if (++unichar == 0) {
1694 break;
1695 }
1696 }
1697 }
1698
1699 static constexpr uint16_t kPlaneSize = 1 << 13;
1700
get_plane_glyph_map(const uint8_t * bits,CTFontRef ctFont,CFIndex glyphCount,SkUnichar * glyphToUnicode,uint8_t planeIndex)1701 static void get_plane_glyph_map(const uint8_t* bits,
1702 CTFontRef ctFont,
1703 CFIndex glyphCount,
1704 SkUnichar* glyphToUnicode,
1705 uint8_t planeIndex) {
1706 SkUnichar planeOrigin = (SkUnichar)planeIndex << 16; // top half of codepoint.
1707 for (uint16_t i = 0; i < kPlaneSize; i++) {
1708 uint8_t mask = bits[i];
1709 if (!mask) {
1710 continue;
1711 }
1712 for (uint8_t j = 0; j < 8; j++) {
1713 if (0 == (mask & ((uint8_t)1 << j))) {
1714 continue;
1715 }
1716 uint16_t planeOffset = (i << 3) | j;
1717 SkUnichar codepoint = planeOrigin | (SkUnichar)planeOffset;
1718 uint16_t utf16[2] = {planeOffset, 0};
1719 size_t count = 1;
1720 if (planeOrigin != 0) {
1721 count = SkUTF::ToUTF16(codepoint, utf16);
1722 }
1723 CGGlyph glyphs[2] = {0, 0};
1724 if (CTFontGetGlyphsForCharacters(ctFont, utf16, glyphs, count)) {
1725 SkASSERT(glyphs[1] == 0);
1726 SkASSERT(glyphs[0] < glyphCount);
1727 // CTFontCopyCharacterSet and CTFontGetGlyphsForCharacters seem to add 'support'
1728 // for characters 0x9, 0xA, and 0xD mapping them to the glyph for character 0x20?
1729 // Prefer mappings to codepoints at or above 0x20.
1730 if (glyphToUnicode[glyphs[0]] < 0x20) {
1731 glyphToUnicode[glyphs[0]] = codepoint;
1732 }
1733 }
1734 }
1735 }
1736 }
1737 // Construct Glyph to Unicode table.
populate_glyph_to_unicode(CTFontRef ctFont,CFIndex glyphCount,SkUnichar * glyphToUnicode)1738 static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
1739 SkUnichar* glyphToUnicode) {
1740 sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount);
1741 SkUniqueCFRef<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
1742 if (!charSet) {
1743 populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
1744 return;
1745 }
1746
1747 SkUniqueCFRef<CFDataRef> bitmap(
1748 CFCharacterSetCreateBitmapRepresentation(nullptr, charSet.get()));
1749 if (!bitmap) {
1750 return;
1751 }
1752 CFIndex dataLength = CFDataGetLength(bitmap.get());
1753 if (!dataLength) {
1754 return;
1755 }
1756 SkASSERT(dataLength >= kPlaneSize);
1757 const UInt8* bits = CFDataGetBytePtr(bitmap.get());
1758
1759 get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, 0);
1760 /*
1761 A CFData object that specifies the bitmap representation of the Unicode
1762 character points the for the new character set. The bitmap representation could
1763 contain all the Unicode character range starting from BMP to Plane 16. The
1764 first 8KiB (8192 bytes) of the data represent the BMP range. The BMP range 8KiB
1765 can be followed by zero to sixteen 8KiB bitmaps, each prepended with the plane
1766 index byte. For example, the bitmap representing the BMP and Plane 2 has the
1767 size of 16385 bytes (8KiB for BMP, 1 byte index, and a 8KiB bitmap for Plane
1768 2). The plane index byte, in this case, contains the integer value two.
1769 */
1770
1771 if (dataLength <= kPlaneSize) {
1772 return;
1773 }
1774 int extraPlaneCount = (dataLength - kPlaneSize) / (1 + kPlaneSize);
1775 SkASSERT(dataLength == kPlaneSize + extraPlaneCount * (1 + kPlaneSize));
1776 while (extraPlaneCount-- > 0) {
1777 bits += kPlaneSize;
1778 uint8_t planeIndex = *bits++;
1779 SkASSERT(planeIndex >= 1);
1780 SkASSERT(planeIndex <= 16);
1781 get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, planeIndex);
1782 }
1783 }
1784
1785 /** Assumes src and dst are not nullptr. */
CFStringToSkString(CFStringRef src,SkString * dst)1786 static void CFStringToSkString(CFStringRef src, SkString* dst) {
1787 // Reserve enough room for the worst-case string,
1788 // plus 1 byte for the trailing null.
1789 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src),
1790 kCFStringEncodingUTF8) + 1;
1791 dst->resize(length);
1792 CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8);
1793 // Resize to the actual UTF-8 length used, stripping the null character.
1794 dst->resize(strlen(dst->c_str()));
1795 }
1796
getGlyphToUnicodeMap(SkUnichar * dstArray) const1797 void SkTypeface_Mac::getGlyphToUnicodeMap(SkUnichar* dstArray) const {
1798 SkUniqueCFRef<CTFontRef> ctFont =
1799 ctfont_create_exact_copy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()), nullptr);
1800 CFIndex glyphCount = CTFontGetGlyphCount(ctFont.get());
1801 populate_glyph_to_unicode(ctFont.get(), glyphCount, dstArray);
1802 }
1803
onGetAdvancedMetrics() const1804 std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_Mac::onGetAdvancedMetrics() const {
1805
1806 SkUniqueCFRef<CTFontRef> ctFont =
1807 ctfont_create_exact_copy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()), nullptr);
1808
1809 std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics);
1810
1811 {
1812 SkUniqueCFRef<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont.get()));
1813 if (fontName.get()) {
1814 CFStringToSkString(fontName.get(), &info->fPostScriptName);
1815 info->fFontName = info->fPostScriptName;
1816 }
1817 }
1818
1819 // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when
1820 // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always
1821 // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and
1822 // CGFontCopyVariations here until support for 10.10 and earlier is removed.
1823 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont.get(), nullptr));
1824 if (cgFont) {
1825 SkUniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get()));
1826 if (cgAxes && CFArrayGetCount(cgAxes.get()) > 0) {
1827 info->fFlags |= SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag;
1828 }
1829 }
1830
1831 SkOTTableOS2_V4::Type fsType;
1832 if (sizeof(fsType) == this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG),
1833 offsetof(SkOTTableOS2_V4, fsType),
1834 sizeof(fsType),
1835 &fsType)) {
1836 SkOTUtils::SetAdvancedTypefaceFlags(fsType, info.get());
1837 }
1838
1839 // If it's not a truetype font, mark it as 'other'. Assume that TrueType
1840 // fonts always have both glyf and loca tables. At the least, this is what
1841 // sfntly needs to subset the font. CTFontCopyAttribute() does not always
1842 // succeed in determining this directly.
1843 if (!this->getTableSize('glyf') || !this->getTableSize('loca')) {
1844 return info;
1845 }
1846
1847 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1848 CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get());
1849 if (symbolicTraits & kCTFontMonoSpaceTrait) {
1850 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1851 }
1852 if (symbolicTraits & kCTFontItalicTrait) {
1853 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1854 }
1855 CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
1856 if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
1857 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1858 } else if (stylisticClass & kCTFontScriptsClass) {
1859 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1860 }
1861 info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont.get());
1862 info->fAscent = (int16_t) CTFontGetAscent(ctFont.get());
1863 info->fDescent = (int16_t) CTFontGetDescent(ctFont.get());
1864 info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont.get());
1865 CGRect bbox = CTFontGetBoundingBox(ctFont.get());
1866
1867 SkRect r;
1868 r.setLTRB(CGToScalar(CGRectGetMinX_inline(bbox)), // Left
1869 CGToScalar(CGRectGetMaxY_inline(bbox)), // Top
1870 CGToScalar(CGRectGetMaxX_inline(bbox)), // Right
1871 CGToScalar(CGRectGetMinY_inline(bbox))); // Bottom
1872
1873 r.roundOut(&(info->fBBox));
1874
1875 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1876 // This probably isn't very good with an italic font.
1877 int16_t min_width = SHRT_MAX;
1878 info->fStemV = 0;
1879 static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
1880 const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
1881 CGGlyph glyphs[count];
1882 CGRect boundingRects[count];
1883 if (CTFontGetGlyphsForCharacters(ctFont.get(), stem_chars, glyphs, count)) {
1884 CTFontGetBoundingRectsForGlyphs(ctFont.get(), kCTFontOrientationHorizontal,
1885 glyphs, boundingRects, count);
1886 for (size_t i = 0; i < count; i++) {
1887 int16_t width = (int16_t) boundingRects[i].size.width;
1888 if (width > 0 && width < min_width) {
1889 min_width = width;
1890 info->fStemV = min_width;
1891 }
1892 }
1893 }
1894 return info;
1895 }
1896
1897 ///////////////////////////////////////////////////////////////////////////////
1898
get_font_type_tag(CTFontRef ctFont)1899 static SK_SFNT_ULONG get_font_type_tag(CTFontRef ctFont) {
1900 SkUniqueCFRef<CFNumberRef> fontFormatRef(
1901 static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
1902 if (!fontFormatRef) {
1903 return 0;
1904 }
1905
1906 SInt32 fontFormatValue;
1907 if (!CFNumberGetValue(fontFormatRef.get(), kCFNumberSInt32Type, &fontFormatValue)) {
1908 return 0;
1909 }
1910
1911 switch (fontFormatValue) {
1912 case kCTFontFormatOpenTypePostScript:
1913 return SkSFNTHeader::fontType_OpenTypeCFF::TAG;
1914 case kCTFontFormatOpenTypeTrueType:
1915 return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1916 case kCTFontFormatTrueType:
1917 return SkSFNTHeader::fontType_MacTrueType::TAG;
1918 case kCTFontFormatPostScript:
1919 return SkSFNTHeader::fontType_PostScript::TAG;
1920 case kCTFontFormatBitmap:
1921 return SkSFNTHeader::fontType_MacTrueType::TAG;
1922 case kCTFontFormatUnrecognized:
1923 default:
1924 return 0;
1925 }
1926 }
1927
onOpenStream(int * ttcIndex) const1928 std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
1929 *ttcIndex = 0;
1930
1931 fInitStream([this]{
1932 if (fStream) {
1933 return;
1934 }
1935
1936 SK_SFNT_ULONG fontType = get_font_type_tag(fFontRef.get());
1937
1938 // get table tags
1939 int numTables = this->countTables();
1940 SkTDArray<SkFontTableTag> tableTags;
1941 tableTags.setCount(numTables);
1942 this->getTableTags(tableTags.begin());
1943
1944 // CT seems to be unreliable in being able to obtain the type,
1945 // even if all we want is the first four bytes of the font resource.
1946 // Just the presence of the FontForge 'FFTM' table seems to throw it off.
1947 if (fontType == 0) {
1948 fontType = SkSFNTHeader::fontType_WindowsTrueType::TAG;
1949
1950 // see https://skbug.com/7630#c7
1951 bool couldBeCFF = false;
1952 constexpr SkFontTableTag CFFTag = SkSetFourByteTag('C', 'F', 'F', ' ');
1953 constexpr SkFontTableTag CFF2Tag = SkSetFourByteTag('C', 'F', 'F', '2');
1954 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1955 if (CFFTag == tableTags[tableIndex] || CFF2Tag == tableTags[tableIndex]) {
1956 couldBeCFF = true;
1957 }
1958 }
1959 if (couldBeCFF) {
1960 fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG;
1961 }
1962 }
1963
1964 // Sometimes CoreGraphics incorrectly thinks a font is kCTFontFormatPostScript.
1965 // It is exceedingly unlikely that this is the case, so double check
1966 // (see https://crbug.com/809763 ).
1967 if (fontType == SkSFNTHeader::fontType_PostScript::TAG) {
1968 // see if there are any required 'typ1' tables (see Adobe Technical Note #5180)
1969 bool couldBeTyp1 = false;
1970 constexpr SkFontTableTag TYPE1Tag = SkSetFourByteTag('T', 'Y', 'P', '1');
1971 constexpr SkFontTableTag CIDTag = SkSetFourByteTag('C', 'I', 'D', ' ');
1972 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1973 if (TYPE1Tag == tableTags[tableIndex] || CIDTag == tableTags[tableIndex]) {
1974 couldBeTyp1 = true;
1975 }
1976 }
1977 if (!couldBeTyp1) {
1978 fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG;
1979 }
1980 }
1981
1982 // get the table sizes and accumulate the total size of the font
1983 SkTDArray<size_t> tableSizes;
1984 size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1985 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1986 size_t tableSize = this->getTableSize(tableTags[tableIndex]);
1987 totalSize += (tableSize + 3) & ~3;
1988 *tableSizes.append() = tableSize;
1989 }
1990
1991 // reserve memory for stream, and zero it (tables must be zero padded)
1992 fStream.reset(new SkMemoryStream(totalSize));
1993 char* dataStart = (char*)fStream->getMemoryBase();
1994 sk_bzero(dataStart, totalSize);
1995 char* dataPtr = dataStart;
1996
1997 // compute font header entries
1998 uint16_t entrySelector = 0;
1999 uint16_t searchRange = 1;
2000 while (searchRange < numTables >> 1) {
2001 entrySelector++;
2002 searchRange <<= 1;
2003 }
2004 searchRange <<= 4;
2005 uint16_t rangeShift = (numTables << 4) - searchRange;
2006
2007 // write font header
2008 SkSFNTHeader* header = (SkSFNTHeader*)dataPtr;
2009 header->fontType = fontType;
2010 header->numTables = SkEndian_SwapBE16(numTables);
2011 header->searchRange = SkEndian_SwapBE16(searchRange);
2012 header->entrySelector = SkEndian_SwapBE16(entrySelector);
2013 header->rangeShift = SkEndian_SwapBE16(rangeShift);
2014 dataPtr += sizeof(SkSFNTHeader);
2015
2016 // write tables
2017 SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr;
2018 dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
2019 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
2020 size_t tableSize = tableSizes[tableIndex];
2021 this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
2022 entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]);
2023 entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr,
2024 tableSize));
2025 entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart));
2026 entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize));
2027
2028 dataPtr += (tableSize + 3) & ~3;
2029 ++entry;
2030 }
2031 });
2032 return fStream->duplicate();
2033 }
2034
2035 struct NonDefaultAxesContext {
2036 SkFixed* axisValue;
2037 CFArrayRef cgAxes;
2038 };
set_non_default_axes(CFTypeRef key,CFTypeRef value,void * context)2039 static void set_non_default_axes(CFTypeRef key, CFTypeRef value, void* context) {
2040 NonDefaultAxesContext* self = static_cast<NonDefaultAxesContext*>(context);
2041
2042 if (CFGetTypeID(key) != CFStringGetTypeID() || CFGetTypeID(value) != CFNumberGetTypeID()) {
2043 return;
2044 }
2045
2046 // The key is a CFString which is a string from the 'name' table.
2047 // Search the cgAxes for an axis with this name, and use its index to store the value.
2048 CFIndex keyIndex = -1;
2049 CFStringRef keyString = static_cast<CFStringRef>(key);
2050 for (CFIndex i = 0; i < CFArrayGetCount(self->cgAxes); ++i) {
2051 CFTypeRef cgAxis = CFArrayGetValueAtIndex(self->cgAxes, i);
2052 if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) {
2053 continue;
2054 }
2055
2056 CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis);
2057 CFTypeRef cgAxisName = CFDictionaryGetValue(cgAxisDict, kCGFontVariationAxisName);
2058 if (!cgAxisName || CFGetTypeID(cgAxisName) != CFStringGetTypeID()) {
2059 continue;
2060 }
2061 CFStringRef cgAxisNameString = static_cast<CFStringRef>(cgAxisName);
2062 if (CFStringCompare(keyString, cgAxisNameString, 0) == kCFCompareEqualTo) {
2063 keyIndex = i;
2064 break;
2065 }
2066 }
2067 if (keyIndex == -1) {
2068 return;
2069 }
2070
2071 CFNumberRef valueNumber = static_cast<CFNumberRef>(value);
2072 double valueDouble;
2073 if (!CFNumberGetValue(valueNumber, kCFNumberDoubleType, &valueDouble) ||
2074 valueDouble < SkFixedToDouble(SK_FixedMin) || SkFixedToDouble(SK_FixedMax) < valueDouble)
2075 {
2076 return;
2077 }
2078 self->axisValue[keyIndex] = SkDoubleToFixed(valueDouble);
2079 }
get_variations(CTFontRef ctFont,CFIndex * cgAxisCount,SkAutoSTMalloc<4,SkFixed> * axisValues)2080 static bool get_variations(CTFontRef ctFont, CFIndex* cgAxisCount,
2081 SkAutoSTMalloc<4, SkFixed>* axisValues)
2082 {
2083 // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when
2084 // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always
2085 // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and
2086 // CGFontCopyVariations here until support for 10.10 and earlier is removed.
2087 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr));
2088 if (!cgFont) {
2089 return false;
2090 }
2091
2092 SkUniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get()));
2093 // If a font has no variations CGFontCopyVariations returns nullptr (instead of an empty dict).
2094 if (!cgVariations) {
2095 return false;
2096 }
2097
2098 SkUniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get()));
2099 if (!cgAxes) {
2100 return false;
2101 }
2102 *cgAxisCount = CFArrayGetCount(cgAxes.get());
2103 axisValues->reset(*cgAxisCount);
2104
2105 // Set all of the axes to their default values.
2106 // Fail if any default value cannot be determined.
2107 for (CFIndex i = 0; i < *cgAxisCount; ++i) {
2108 CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes.get(), i);
2109 if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) {
2110 return false;
2111 }
2112
2113 CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis);
2114 CFTypeRef axisDefaultValue = CFDictionaryGetValue(cgAxisDict,
2115 kCGFontVariationAxisDefaultValue);
2116 if (!axisDefaultValue || CFGetTypeID(axisDefaultValue) != CFNumberGetTypeID()) {
2117 return false;
2118 }
2119 CFNumberRef axisDefaultValueNumber = static_cast<CFNumberRef>(axisDefaultValue);
2120 double axisDefaultValueDouble;
2121 if (!CFNumberGetValue(axisDefaultValueNumber, kCFNumberDoubleType, &axisDefaultValueDouble))
2122 {
2123 return false;
2124 }
2125 if (axisDefaultValueDouble < SkFixedToDouble(SK_FixedMin) ||
2126 SkFixedToDouble(SK_FixedMax) < axisDefaultValueDouble)
2127 {
2128 return false;
2129 }
2130 (*axisValues)[(int)i] = SkDoubleToFixed(axisDefaultValueDouble);
2131 }
2132
2133 // Override the default values with the given font's stated axis values.
2134 NonDefaultAxesContext c = { axisValues->get(), cgAxes.get() };
2135 CFDictionaryApplyFunction(cgVariations.get(), set_non_default_axes, &c);
2136
2137 return true;
2138 }
onMakeFontData() const2139 std::unique_ptr<SkFontData> SkTypeface_Mac::onMakeFontData() const {
2140 int index;
2141 std::unique_ptr<SkStreamAsset> stream(this->onOpenStream(&index));
2142
2143 CFIndex cgAxisCount;
2144 SkAutoSTMalloc<4, SkFixed> axisValues;
2145 if (get_variations(fFontRef.get(), &cgAxisCount, &axisValues)) {
2146 return skstd::make_unique<SkFontData>(std::move(stream), index,
2147 axisValues.get(), cgAxisCount);
2148 }
2149 return skstd::make_unique<SkFontData>(std::move(stream), index, nullptr, 0);
2150 }
2151
2152 /** Creates a CT variation dictionary {tag, value} from a CG variation dictionary {name, value}. */
ct_variation_from_cg_variation(CFDictionaryRef cgVariations,CFArrayRef ctAxes)2153 static SkUniqueCFRef<CFDictionaryRef> ct_variation_from_cg_variation(CFDictionaryRef cgVariations,
2154 CFArrayRef ctAxes) {
2155
2156 SkUniqueCFRef<CFMutableDictionaryRef> ctVariations(
2157 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2158 &kCFTypeDictionaryKeyCallBacks,
2159 &kCFTypeDictionaryValueCallBacks));
2160
2161 CFIndex axisCount = CFArrayGetCount(ctAxes);
2162 for (CFIndex i = 0; i < axisCount; ++i) {
2163 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes, i);
2164 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
2165 return nullptr;
2166 }
2167 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
2168
2169 // The assumption is that values produced by kCTFontVariationAxisNameKey and
2170 // kCGFontVariationAxisName will always be equal.
2171 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey);
2172 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
2173 return nullptr;
2174 }
2175
2176 CFTypeRef axisValue = CFDictionaryGetValue(cgVariations, axisName);
2177 if (!axisValue || CFGetTypeID(axisValue) != CFNumberGetTypeID()) {
2178 return nullptr;
2179 }
2180
2181 CFTypeRef axisTag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
2182 if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) {
2183 return nullptr;
2184 }
2185
2186 CFDictionaryAddValue(ctVariations.get(), axisTag, axisValue);
2187 }
2188 return ctVariations;
2189 }
2190
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount) const2191 int SkTypeface_Mac::onGetVariationDesignPosition(
2192 SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
2193 {
2194 // The CGFont variation data does not contain the tag.
2195
2196 // CTFontCopyVariationAxes returns nullptr for CGFontCreateWithDataProvider fonts with
2197 // macOS 10.10 and iOS 9 or earlier. When this happens, there is no API to provide the tag.
2198 SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get()));
2199 if (!ctAxes) {
2200 return -1;
2201 }
2202 CFIndex axisCount = CFArrayGetCount(ctAxes.get());
2203 if (!coordinates || coordinateCount < axisCount) {
2204 return axisCount;
2205 }
2206
2207 // This call always returns nullptr on 10.11 and under for CGFontCreateWithDataProvider fonts.
2208 // When this happens, try converting the CG variation to a CT variation.
2209 // On 10.12 and later, this only returns non-default variations.
2210 SkUniqueCFRef<CFDictionaryRef> ctVariations(CTFontCopyVariation(fFontRef.get()));
2211 if (!ctVariations) {
2212 // When 10.11 and earlier are no longer supported, the following code can be replaced with
2213 // return -1 and ct_variation_from_cg_variation can be removed.
2214 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr));
2215 if (!cgFont) {
2216 return -1;
2217 }
2218 SkUniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get()));
2219 if (!cgVariations) {
2220 return -1;
2221 }
2222 ctVariations = ct_variation_from_cg_variation(cgVariations.get(), ctAxes.get());
2223 if (!ctVariations) {
2224 return -1;
2225 }
2226 }
2227
2228 for (int i = 0; i < axisCount; ++i) {
2229 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
2230 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
2231 return -1;
2232 }
2233 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
2234
2235 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
2236 if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
2237 return -1;
2238 }
2239 CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
2240 int64_t tagLong;
2241 if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
2242 return -1;
2243 }
2244 coordinates[i].axis = tagLong;
2245
2246 CGFloat variationCGFloat;
2247 CFTypeRef variationValue = CFDictionaryGetValue(ctVariations.get(), tagNumber);
2248 if (variationValue) {
2249 if (CFGetTypeID(variationValue) != CFNumberGetTypeID()) {
2250 return -1;
2251 }
2252 CFNumberRef variationNumber = static_cast<CFNumberRef>(variationValue);
2253 if (!CFNumberGetValue(variationNumber, kCFNumberCGFloatType, &variationCGFloat)) {
2254 return -1;
2255 }
2256 } else {
2257 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
2258 if (!def || CFGetTypeID(def) != CFNumberGetTypeID()) {
2259 return -1;
2260 }
2261 CFNumberRef defNumber = static_cast<CFNumberRef>(def);
2262 if (!CFNumberGetValue(defNumber, kCFNumberCGFloatType, &variationCGFloat)) {
2263 return -1;
2264 }
2265 }
2266 coordinates[i].value = CGToScalar(variationCGFloat);
2267
2268 }
2269 return axisCount;
2270 }
2271
2272 ///////////////////////////////////////////////////////////////////////////////
2273 ///////////////////////////////////////////////////////////////////////////////
2274
onGetUPEM() const2275 int SkTypeface_Mac::onGetUPEM() const {
2276 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr));
2277 return CGFontGetUnitsPerEm(cgFont.get());
2278 }
2279
onCreateFamilyNameIterator() const2280 SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const {
2281 sk_sp<SkTypeface::LocalizedStrings> nameIter =
2282 SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this);
2283 if (!nameIter) {
2284 CFStringRef cfLanguageRaw;
2285 SkUniqueCFRef<CFStringRef> cfFamilyName(
2286 CTFontCopyLocalizedName(fFontRef.get(), kCTFontFamilyNameKey, &cfLanguageRaw));
2287 SkUniqueCFRef<CFStringRef> cfLanguage(cfLanguageRaw);
2288
2289 SkString skLanguage;
2290 SkString skFamilyName;
2291 if (cfLanguage) {
2292 CFStringToSkString(cfLanguage.get(), &skLanguage);
2293 } else {
2294 skLanguage = "und"; //undetermined
2295 }
2296 if (cfFamilyName) {
2297 CFStringToSkString(cfFamilyName.get(), &skFamilyName);
2298 }
2299
2300 nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(skFamilyName, skLanguage);
2301 }
2302 return nameIter.release();
2303 }
2304
onGetTableTags(SkFontTableTag tags[]) const2305 int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
2306 SkUniqueCFRef<CFArrayRef> cfArray(
2307 CTFontCopyAvailableTables(fFontRef.get(), kCTFontTableOptionNoOptions));
2308 if (!cfArray) {
2309 return 0;
2310 }
2311 int count = SkToInt(CFArrayGetCount(cfArray.get()));
2312 if (tags) {
2313 for (int i = 0; i < count; ++i) {
2314 uintptr_t fontTag = reinterpret_cast<uintptr_t>(
2315 CFArrayGetValueAtIndex(cfArray.get(), i));
2316 tags[i] = static_cast<SkFontTableTag>(fontTag);
2317 }
2318 }
2319 return count;
2320 }
2321
2322 // If, as is the case with web fonts, the CTFont data isn't available,
2323 // the CGFont data may work. While the CGFont may always provide the
2324 // right result, leave the CTFont code path to minimize disruption.
copy_table_from_font(CTFontRef ctFont,SkFontTableTag tag)2325 static SkUniqueCFRef<CFDataRef> copy_table_from_font(CTFontRef ctFont, SkFontTableTag tag) {
2326 SkUniqueCFRef<CFDataRef> data(CTFontCopyTable(ctFont, (CTFontTableTag) tag,
2327 kCTFontTableOptionNoOptions));
2328 if (!data) {
2329 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr));
2330 data.reset(CGFontCopyTableForTag(cgFont.get(), tag));
2331 }
2332 return data;
2333 }
2334
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * dstData) const2335 size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset,
2336 size_t length, void* dstData) const {
2337 SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
2338 if (!srcData) {
2339 return 0;
2340 }
2341
2342 size_t srcSize = CFDataGetLength(srcData.get());
2343 if (offset >= srcSize) {
2344 return 0;
2345 }
2346 if (length > srcSize - offset) {
2347 length = srcSize - offset;
2348 }
2349 if (dstData) {
2350 memcpy(dstData, CFDataGetBytePtr(srcData.get()) + offset, length);
2351 }
2352 return length;
2353 }
2354
onCopyTableData(SkFontTableTag tag) const2355 sk_sp<SkData> SkTypeface_Mac::onCopyTableData(SkFontTableTag tag) const {
2356 SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
2357 if (!srcData) {
2358 return nullptr;
2359 }
2360 const UInt8* data = CFDataGetBytePtr(srcData.get());
2361 CFIndex length = CFDataGetLength(srcData.get());
2362 return SkData::MakeWithProc(data, length,
2363 [](const void*, void* ctx) {
2364 CFRelease((CFDataRef)ctx);
2365 }, (void*)srcData.release());
2366 }
2367
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const2368 SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkScalerContextEffects& effects,
2369 const SkDescriptor* desc) const {
2370 return new SkScalerContext_Mac(sk_ref_sp(const_cast<SkTypeface_Mac*>(this)), effects, desc);
2371 }
2372
onFilterRec(SkScalerContextRec * rec) const2373 void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
2374 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
2375 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
2376 {
2377 rec->fMaskFormat = SkMask::kA8_Format;
2378 // Render the glyphs as close as possible to what was requested.
2379 // The above turns off subpixel rendering, but the user requested it.
2380 // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks.
2381 // See comments below for more details.
2382 rec->setHinting(SkFontHinting::kNormal);
2383 }
2384
2385 unsigned flagsWeDontSupport = SkScalerContext::kForceAutohinting_Flag |
2386 SkScalerContext::kLCD_BGROrder_Flag |
2387 SkScalerContext::kLCD_Vertical_Flag;
2388
2389 rec->fFlags &= ~flagsWeDontSupport;
2390
2391 const SmoothBehavior smoothBehavior = smooth_behavior();
2392
2393 // Only two levels of hinting are supported.
2394 // kNo_Hinting means avoid CoreGraphics outline dilation (smoothing).
2395 // kNormal_Hinting means CoreGraphics outline dilation (smoothing) is allowed.
2396 if (rec->getHinting() != SkFontHinting::kNone) {
2397 rec->setHinting(SkFontHinting::kNormal);
2398 }
2399 // If smoothing has no effect, don't request it.
2400 if (smoothBehavior == SmoothBehavior::none) {
2401 rec->setHinting(SkFontHinting::kNone);
2402 }
2403
2404 // FIXME: lcd smoothed un-hinted rasterization unsupported.
2405 // Tracked by http://code.google.com/p/skia/issues/detail?id=915 .
2406 // There is no current means to honor a request for unhinted lcd,
2407 // so arbitrarilly ignore the hinting request and honor lcd.
2408
2409 // Hinting and smoothing should be orthogonal, but currently they are not.
2410 // CoreGraphics has no API to influence hinting. However, its lcd smoothed
2411 // output is drawn from auto-dilated outlines (the amount of which is
2412 // determined by AppleFontSmoothing). Its regular anti-aliased output is
2413 // drawn from un-dilated outlines.
2414
2415 // The behavior of Skia is as follows:
2416 // [AA][no-hint]: generate AA using CoreGraphic's AA output.
2417 // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single
2418 // channel. This matches [LCD][yes-hint] in weight.
2419 // [LCD][no-hint]: curently unable to honor, and must pick which to respect.
2420 // Currenly side with LCD, effectively ignoring the hinting setting.
2421 // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output.
2422 if (rec->fMaskFormat == SkMask::kLCD16_Format) {
2423 if (smoothBehavior == SmoothBehavior::subpixel) {
2424 //CoreGraphics creates 555 masks for smoothed text anyway.
2425 rec->fMaskFormat = SkMask::kLCD16_Format;
2426 rec->setHinting(SkFontHinting::kNormal);
2427 } else {
2428 rec->fMaskFormat = SkMask::kA8_Format;
2429 if (smoothBehavior != SmoothBehavior::none) {
2430 rec->setHinting(SkFontHinting::kNormal);
2431 }
2432 }
2433 }
2434
2435 // CoreText provides no information as to whether a glyph will be color or not.
2436 // Fonts may mix outlines and bitmaps, so information is needed on a glyph by glyph basis.
2437 // If a font contains an 'sbix' table, consider it to be a color font, and disable lcd.
2438 if (fHasColorGlyphs) {
2439 rec->fMaskFormat = SkMask::kARGB32_Format;
2440 }
2441
2442 // Smoothing will be used if the format is either LCD or if there is hinting.
2443 // In those cases, we need to choose the proper dilation mask based on the color.
2444 if (rec->fMaskFormat == SkMask::kLCD16_Format ||
2445 (rec->fMaskFormat == SkMask::kA8_Format && rec->getHinting() != SkFontHinting::kNone)) {
2446 SkColor color = rec->getLuminanceColor();
2447 int r = SkColorGetR(color);
2448 int g = SkColorGetG(color);
2449 int b = SkColorGetB(color);
2450 // Choose whether to draw using a light-on-dark mask based on observed
2451 // color/luminance thresholds that CoreText uses.
2452 if (r >= 85 && g >= 85 && b >= 85 && r + g + b >= 2 * 255) {
2453 rec->fFlags |= SkScalerContext::kLightOnDark_Flag;
2454 }
2455 }
2456
2457 // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
2458 // All other masks can use regular gamma.
2459 if (SkMask::kA8_Format == rec->fMaskFormat && SkFontHinting::kNone == rec->getHinting()) {
2460 #ifndef SK_GAMMA_APPLY_TO_A8
2461 // SRGBTODO: Is this correct? Do we want contrast boost?
2462 rec->ignorePreBlend();
2463 #endif
2464 } else {
2465 #ifndef SK_IGNORE_MAC_BLENDING_MATCH_FIX
2466 SkColor color = rec->getLuminanceColor();
2467 if (smoothBehavior == SmoothBehavior::some) {
2468 // CoreGraphics smoothed text without subpixel coverage blitting goes from a gamma of
2469 // 2.0 for black foreground to a gamma of 1.0 for white foreground. Emulate this
2470 // through the mask gamma by reducing the color values to 1/2.
2471 color = SkColorSetRGB(SkColorGetR(color) * 1/2,
2472 SkColorGetG(color) * 1/2,
2473 SkColorGetB(color) * 1/2);
2474 } else if (smoothBehavior == SmoothBehavior::subpixel) {
2475 // CoreGraphics smoothed text with subpixel coverage blitting goes from a gamma of
2476 // 2.0 for black foreground to a gamma of ~1.4? for white foreground. Emulate this
2477 // through the mask gamma by reducing the color values to 3/4.
2478 color = SkColorSetRGB(SkColorGetR(color) * 3/4,
2479 SkColorGetG(color) * 3/4,
2480 SkColorGetB(color) * 3/4);
2481 }
2482 rec->setLuminanceColor(color);
2483 #endif
2484 // CoreGraphics dialates smoothed text to provide contrast.
2485 rec->setContrast(0);
2486 }
2487 }
2488
2489 /** Takes ownership of the CFStringRef. */
get_str(CFStringRef ref,SkString * str)2490 static const char* get_str(CFStringRef ref, SkString* str) {
2491 if (nullptr == ref) {
2492 return nullptr;
2493 }
2494 CFStringToSkString(ref, str);
2495 CFRelease(ref);
2496 return str->c_str();
2497 }
2498
onGetFamilyName(SkString * familyName) const2499 void SkTypeface_Mac::onGetFamilyName(SkString* familyName) const {
2500 get_str(CTFontCopyFamilyName(fFontRef.get()), familyName);
2501 }
2502
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocalStream) const2503 void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc,
2504 bool* isLocalStream) const {
2505 SkString tmpStr;
2506
2507 desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef.get()), &tmpStr));
2508 desc->setFullName(get_str(CTFontCopyFullName(fFontRef.get()), &tmpStr));
2509 desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef.get()), &tmpStr));
2510 desc->setStyle(this->fontStyle());
2511 *isLocalStream = fIsFromStream;
2512 }
2513
onCharsToGlyphs(const SkUnichar uni[],int count,SkGlyphID glyphs[]) const2514 void SkTypeface_Mac::onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const {
2515 // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
2516 // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
2517 // It is documented that if a mapping is unavailable, the glyph will be set to 0.
2518
2519 SkAutoSTMalloc<1024, UniChar> charStorage;
2520 const UniChar* src; // UniChar is a UTF-16 16-bit code unit.
2521 int srcCount;
2522 const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(uni);
2523 UniChar* utf16 = charStorage.reset(2 * count);
2524 src = utf16;
2525 for (int i = 0; i < count; ++i) {
2526 utf16 += SkUTF::ToUTF16(utf32[i], utf16);
2527 }
2528 srcCount = SkToInt(utf16 - src);
2529
2530 // If there are any non-bmp code points, the provided 'glyphs' storage will be inadequate.
2531 SkAutoSTMalloc<1024, uint16_t> glyphStorage;
2532 uint16_t* macGlyphs = glyphs;
2533 if (srcCount > count) {
2534 macGlyphs = glyphStorage.reset(srcCount);
2535 }
2536
2537 CTFontGetGlyphsForCharacters(fFontRef.get(), src, macGlyphs, srcCount);
2538
2539 // If there were any non-bmp, then copy and compact.
2540 // If all are bmp, 'glyphs' already contains the compact glyphs.
2541 // If some are non-bmp, copy and compact into 'glyphs'.
2542 if (srcCount > count) {
2543 SkASSERT(glyphs != macGlyphs);
2544 int extra = 0;
2545 for (int i = 0; i < count; ++i) {
2546 glyphs[i] = macGlyphs[i + extra];
2547 if (SkUTF16_IsLeadingSurrogate(src[i + extra])) {
2548 ++extra;
2549 }
2550 }
2551 } else {
2552 SkASSERT(glyphs == macGlyphs);
2553 }
2554 }
2555
onCountGlyphs() const2556 int SkTypeface_Mac::onCountGlyphs() const {
2557 return SkToInt(CTFontGetGlyphCount(fFontRef.get()));
2558 }
2559
2560 ///////////////////////////////////////////////////////////////////////////////
2561 ///////////////////////////////////////////////////////////////////////////////
2562
find_desc_str(CTFontDescriptorRef desc,CFStringRef name,SkString * value)2563 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
2564 SkUniqueCFRef<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
2565 if (!ref) {
2566 return false;
2567 }
2568 CFStringToSkString(ref.get(), value);
2569 return true;
2570 }
2571
2572 #include "include/core/SkFontMgr.h"
2573
sqr(int value)2574 static inline int sqr(int value) {
2575 SkASSERT(SkAbs32(value) < 0x7FFF); // check for overflow
2576 return value * value;
2577 }
2578
2579 // We normalize each axis (weight, width, italic) to be base-900
compute_metric(const SkFontStyle & a,const SkFontStyle & b)2580 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
2581 return sqr(a.weight() - b.weight()) +
2582 sqr((a.width() - b.width()) * 100) +
2583 sqr((a.slant() != b.slant()) * 900);
2584 }
2585
2586 class SkFontStyleSet_Mac : public SkFontStyleSet {
2587 public:
SkFontStyleSet_Mac(CTFontDescriptorRef desc)2588 SkFontStyleSet_Mac(CTFontDescriptorRef desc)
2589 : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, nullptr))
2590 , fCount(0)
2591 {
2592 if (!fArray) {
2593 fArray.reset(CFArrayCreate(nullptr, nullptr, 0, nullptr));
2594 }
2595 fCount = SkToInt(CFArrayGetCount(fArray.get()));
2596 }
2597
count()2598 int count() override {
2599 return fCount;
2600 }
2601
getStyle(int index,SkFontStyle * style,SkString * name)2602 void getStyle(int index, SkFontStyle* style, SkString* name) override {
2603 SkASSERT((unsigned)index < (unsigned)fCount);
2604 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
2605 if (style) {
2606 *style = fontstyle_from_descriptor(desc, false);
2607 }
2608 if (name) {
2609 if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
2610 name->reset();
2611 }
2612 }
2613 }
2614
createTypeface(int index)2615 SkTypeface* createTypeface(int index) override {
2616 SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray.get()));
2617 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
2618
2619 return create_from_desc(desc).release();
2620 }
2621
matchStyle(const SkFontStyle & pattern)2622 SkTypeface* matchStyle(const SkFontStyle& pattern) override {
2623 if (0 == fCount) {
2624 return nullptr;
2625 }
2626 return create_from_desc(findMatchingDesc(pattern)).release();
2627 }
2628
2629 private:
2630 SkUniqueCFRef<CFArrayRef> fArray;
2631 int fCount;
2632
findMatchingDesc(const SkFontStyle & pattern) const2633 CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
2634 int bestMetric = SK_MaxS32;
2635 CTFontDescriptorRef bestDesc = nullptr;
2636
2637 for (int i = 0; i < fCount; ++i) {
2638 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), i);
2639 int metric = compute_metric(pattern, fontstyle_from_descriptor(desc, false));
2640 if (0 == metric) {
2641 return desc;
2642 }
2643 if (metric < bestMetric) {
2644 bestMetric = metric;
2645 bestDesc = desc;
2646 }
2647 }
2648 SkASSERT(bestDesc);
2649 return bestDesc;
2650 }
2651 };
2652
2653 class SkFontMgr_Mac : public SkFontMgr {
2654 SkUniqueCFRef<CFArrayRef> fNames;
2655 int fCount;
2656
getFamilyNameAt(int index) const2657 CFStringRef getFamilyNameAt(int index) const {
2658 SkASSERT((unsigned)index < (unsigned)fCount);
2659 return (CFStringRef)CFArrayGetValueAtIndex(fNames.get(), index);
2660 }
2661
CreateSet(CFStringRef cfFamilyName)2662 static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) {
2663 SkUniqueCFRef<CFMutableDictionaryRef> cfAttr(
2664 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2665 &kCFTypeDictionaryKeyCallBacks,
2666 &kCFTypeDictionaryValueCallBacks));
2667
2668 CFDictionaryAddValue(cfAttr.get(), kCTFontFamilyNameAttribute, cfFamilyName);
2669
2670 SkUniqueCFRef<CTFontDescriptorRef> desc(
2671 CTFontDescriptorCreateWithAttributes(cfAttr.get()));
2672 return new SkFontStyleSet_Mac(desc.get());
2673 }
2674
2675 /** CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we
2676 * provide a wrapper here that will return an empty array if need be.
2677 */
CopyAvailableFontFamilyNames()2678 static SkUniqueCFRef<CFArrayRef> CopyAvailableFontFamilyNames() {
2679 #ifdef SK_BUILD_FOR_IOS
2680 return SkUniqueCFRef<CFArrayRef>(CFArrayCreate(nullptr, nullptr, 0, nullptr));
2681 #else
2682 return SkUniqueCFRef<CFArrayRef>(CTFontManagerCopyAvailableFontFamilyNames());
2683 #endif
2684 }
2685
2686 public:
SkFontMgr_Mac()2687 SkFontMgr_Mac()
2688 : fNames(CopyAvailableFontFamilyNames())
2689 , fCount(fNames ? SkToInt(CFArrayGetCount(fNames.get())) : 0) {}
2690
2691 protected:
onCountFamilies() const2692 int onCountFamilies() const override {
2693 return fCount;
2694 }
2695
onGetFamilyName(int index,SkString * familyName) const2696 void onGetFamilyName(int index, SkString* familyName) const override {
2697 if ((unsigned)index < (unsigned)fCount) {
2698 CFStringToSkString(this->getFamilyNameAt(index), familyName);
2699 } else {
2700 familyName->reset();
2701 }
2702 }
2703
onCreateStyleSet(int index) const2704 SkFontStyleSet* onCreateStyleSet(int index) const override {
2705 if ((unsigned)index >= (unsigned)fCount) {
2706 return nullptr;
2707 }
2708 return CreateSet(this->getFamilyNameAt(index));
2709 }
2710
onMatchFamily(const char familyName[]) const2711 SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
2712 if (!familyName) {
2713 return nullptr;
2714 }
2715 SkUniqueCFRef<CFStringRef> cfName = make_CFString(familyName);
2716 return CreateSet(cfName.get());
2717 }
2718
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const2719 SkTypeface* onMatchFamilyStyle(const char familyName[],
2720 const SkFontStyle& style) const override {
2721 SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
2722 return create_from_desc(desc.get()).release();
2723 }
2724
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const2725 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
2726 const SkFontStyle& style,
2727 const char* bcp47[], int bcp47Count,
2728 SkUnichar character) const override {
2729 SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
2730 SkUniqueCFRef<CTFontRef> familyFont(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
2731
2732 // kCFStringEncodingUTF32 is BE unless there is a BOM.
2733 // Since there is no machine endian option, explicitly state machine endian.
2734 #ifdef SK_CPU_LENDIAN
2735 constexpr CFStringEncoding encoding = kCFStringEncodingUTF32LE;
2736 #else
2737 constexpr CFStringEncoding encoding = kCFStringEncodingUTF32BE;
2738 #endif
2739 SkUniqueCFRef<CFStringRef> string(CFStringCreateWithBytes(
2740 kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(&character), sizeof(character),
2741 encoding, false));
2742 CFRange range = CFRangeMake(0, CFStringGetLength(string.get())); // in UniChar units.
2743 SkUniqueCFRef<CTFontRef> fallbackFont(
2744 CTFontCreateForString(familyFont.get(), string.get(), range));
2745 return create_from_CTFontRef(std::move(fallbackFont), nullptr, nullptr).release();
2746 }
2747
onMatchFaceStyle(const SkTypeface * familyMember,const SkFontStyle &) const2748 SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2749 const SkFontStyle&) const override {
2750 return nullptr;
2751 }
2752
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const2753 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
2754 SkUniqueCFRef<CGDataProviderRef> pr(SkCreateDataProviderFromData(data));
2755 if (!pr) {
2756 return nullptr;
2757 }
2758 return create_from_dataProvider(std::move(pr), SkMemoryStream::Make(std::move(data)),
2759 ttcIndex);
2760 }
2761
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const2762 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
2763 int ttcIndex) const override {
2764 SkUniqueCFRef<CGDataProviderRef> pr(SkCreateDataProviderFromStream(stream->duplicate()));
2765 if (!pr) {
2766 return nullptr;
2767 }
2768 return create_from_dataProvider(std::move(pr), std::move(stream), ttcIndex);
2769 }
2770
2771 /** Creates a dictionary suitable for setting the axes on a CGFont. */
copy_axes(CGFontRef cg,const SkFontArguments & args)2772 static SkUniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, const SkFontArguments& args) {
2773 // The CGFont variation data is keyed by name, but lacks the tag.
2774 // The CTFont variation data is keyed by tag, and also has the name.
2775 // We would like to work with CTFont variations, but creating a CTFont font with
2776 // CTFont variation dictionary runs into bugs. So use the CTFont variation data
2777 // to match names to tags to create the appropriate CGFont.
2778 SkUniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr));
2779 // CTFontCopyVariationAxes returns nullptr for CGFontCreateWithDataProvider fonts with
2780 // macOS 10.10 and iOS 9 or earlier. When this happens, there is no API to provide the tag.
2781 SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct.get()));
2782 if (!ctAxes) {
2783 return nullptr;
2784 }
2785 CFIndex axisCount = CFArrayGetCount(ctAxes.get());
2786
2787 const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
2788
2789 SkUniqueCFRef<CFMutableDictionaryRef> dict(
2790 CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
2791 &kCFTypeDictionaryKeyCallBacks,
2792 &kCFTypeDictionaryValueCallBacks));
2793
2794 for (int i = 0; i < axisCount; ++i) {
2795 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
2796 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
2797 return nullptr;
2798 }
2799 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
2800
2801 // The assumption is that values produced by kCTFontVariationAxisNameKey and
2802 // kCGFontVariationAxisName will always be equal.
2803 // If they are ever not, seach the project history for "get_tag_for_name".
2804 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey);
2805 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
2806 return nullptr;
2807 }
2808
2809 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
2810 if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
2811 return nullptr;
2812 }
2813 CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
2814 int64_t tagLong;
2815 if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
2816 return nullptr;
2817 }
2818
2819 // The variation axes can be set to any value, but cg will effectively pin them.
2820 // Pin them here to normalize.
2821 CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
2822 CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
2823 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
2824 if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
2825 !max || CFGetTypeID(max) != CFNumberGetTypeID() ||
2826 !def || CFGetTypeID(def) != CFNumberGetTypeID())
2827 {
2828 return nullptr;
2829 }
2830 CFNumberRef minNumber = static_cast<CFNumberRef>(min);
2831 CFNumberRef maxNumber = static_cast<CFNumberRef>(max);
2832 CFNumberRef defNumber = static_cast<CFNumberRef>(def);
2833 double minDouble;
2834 double maxDouble;
2835 double defDouble;
2836 if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) ||
2837 !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble) ||
2838 !CFNumberGetValue(defNumber, kCFNumberDoubleType, &defDouble))
2839 {
2840 return nullptr;
2841 }
2842
2843 double value = defDouble;
2844 // The position may be over specified. If there are multiple values for a given axis,
2845 // use the last one since that's what css-fonts-4 requires.
2846 for (int j = position.coordinateCount; j --> 0;) {
2847 if (position.coordinates[j].axis == tagLong) {
2848 value = SkTPin(SkScalarToDouble(position.coordinates[j].value),
2849 minDouble, maxDouble);
2850 break;
2851 }
2852 }
2853 SkUniqueCFRef<CFNumberRef> valueNumber(
2854 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
2855 CFDictionaryAddValue(dict.get(), axisName, valueNumber.get());
2856 }
2857 return dict;
2858 }
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> s,const SkFontArguments & args) const2859 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> s,
2860 const SkFontArguments& args) const override {
2861 if (args.getCollectionIndex() != 0) {
2862 return nullptr;
2863 }
2864 SkUniqueCFRef<CGDataProviderRef> provider(SkCreateDataProviderFromStream(s->duplicate()));
2865 if (!provider) {
2866 return nullptr;
2867 }
2868 SkUniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
2869 if (!cg) {
2870 return nullptr;
2871 }
2872
2873 SkUniqueCFRef<CFDictionaryRef> cgVariations = copy_axes(cg.get(), args);
2874 // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was
2875 // created from a data provider does not appear to have any ownership of the underlying
2876 // data. The original CGFontRef must be kept alive until the copy will no longer be used.
2877 SkUniqueCFRef<CGFontRef> cgVariant;
2878 if (cgVariations) {
2879 cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.get()));
2880 } else {
2881 cgVariant.reset(cg.release());
2882 }
2883
2884 SkUniqueCFRef<CTFontRef> ct(
2885 CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, nullptr));
2886 if (!ct) {
2887 return nullptr;
2888 }
2889 return create_from_CTFontRef(std::move(ct), std::move(cg), std::move(s));
2890 }
2891
2892 /** Creates a dictionary suitable for setting the axes on a CGFont. */
copy_axes(CGFontRef cg,SkFontData * fontData)2893 static SkUniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, SkFontData* fontData) {
2894 SkUniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg));
2895 if (!cgAxes) {
2896 return nullptr;
2897 }
2898
2899 CFIndex axisCount = CFArrayGetCount(cgAxes.get());
2900 if (0 == axisCount || axisCount != fontData->getAxisCount()) {
2901 return nullptr;
2902 }
2903
2904 SkUniqueCFRef<CFMutableDictionaryRef> dict(
2905 CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
2906 &kCFTypeDictionaryKeyCallBacks,
2907 &kCFTypeDictionaryValueCallBacks));
2908
2909 for (int i = 0; i < fontData->getAxisCount(); ++i) {
2910 CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes.get(), i);
2911 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
2912 return nullptr;
2913 }
2914 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
2915
2916 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisName);
2917 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
2918 return nullptr;
2919 }
2920
2921 // The variation axes can be set to any value, but cg will effectively pin them.
2922 // Pin them here to normalize.
2923 CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMinValue);
2924 CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMaxValue);
2925 if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
2926 !max || CFGetTypeID(max) != CFNumberGetTypeID())
2927 {
2928 return nullptr;
2929 }
2930 CFNumberRef minNumber = static_cast<CFNumberRef>(min);
2931 CFNumberRef maxNumber = static_cast<CFNumberRef>(max);
2932 double minDouble;
2933 double maxDouble;
2934 if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) ||
2935 !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble))
2936 {
2937 return nullptr;
2938 }
2939 double value = SkTPin(SkFixedToDouble(fontData->getAxis()[i]), minDouble, maxDouble);
2940 SkUniqueCFRef<CFNumberRef> valueNumber(
2941 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
2942 CFDictionaryAddValue(dict.get(), axisName, valueNumber.get());
2943 }
2944 return dict;
2945 }
onMakeFromFontData(std::unique_ptr<SkFontData> fontData) const2946 sk_sp<SkTypeface> onMakeFromFontData(std::unique_ptr<SkFontData> fontData) const override {
2947 if (fontData->getIndex() != 0) {
2948 return nullptr;
2949 }
2950 SkUniqueCFRef<CGDataProviderRef> provider(
2951 SkCreateDataProviderFromStream(fontData->getStream()->duplicate()));
2952 if (!provider) {
2953 return nullptr;
2954 }
2955 SkUniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
2956 if (!cg) {
2957 return nullptr;
2958 }
2959
2960 SkUniqueCFRef<CFDictionaryRef> cgVariations = copy_axes(cg.get(), fontData.get());
2961 // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was
2962 // created from a data provider does not appear to have any ownership of the underlying
2963 // data. The original CGFontRef must be kept alive until the copy will no longer be used.
2964 SkUniqueCFRef<CGFontRef> cgVariant;
2965 if (cgVariations) {
2966 cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.get()));
2967 } else {
2968 cgVariant.reset(cg.release());
2969 }
2970
2971 SkUniqueCFRef<CTFontRef> ct(
2972 CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, nullptr));
2973 if (!ct) {
2974 return nullptr;
2975 }
2976 return create_from_CTFontRef(std::move(ct), std::move(cg), fontData->detachStream());
2977 }
2978
onMakeFromFile(const char path[],int ttcIndex) const2979 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
2980 SkUniqueCFRef<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path));
2981 if (!pr) {
2982 return nullptr;
2983 }
2984 return create_from_dataProvider(std::move(pr), SkFILEStream::Make(path), ttcIndex);
2985 }
2986
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const2987 sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
2988 if (familyName) {
2989 familyName = map_css_names(familyName);
2990 }
2991
2992 sk_sp<SkTypeface> face = create_from_name(familyName, style);
2993 if (face) {
2994 return face;
2995 }
2996
2997 static SkTypeface* gDefaultFace;
2998 static SkOnce lookupDefault;
2999 static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
3000 lookupDefault([]{
3001 gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle()).release();
3002 });
3003 return sk_ref_sp(gDefaultFace);
3004 }
3005 };
3006
3007 ///////////////////////////////////////////////////////////////////////////////
3008
Factory()3009 sk_sp<SkFontMgr> SkFontMgr::Factory() { return sk_make_sp<SkFontMgr_Mac>(); }
3010
3011 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
3012