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;
__anon4eda7c130602null586 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 // force our checks below to happen
1180 fDoAA = !doAA;
1181 fDoLCD = !doLCD;
1182
1183 CGContextSetTextMatrix(fCG.get(), context.fTransform);
1184 }
1185
1186 if (glyph.isColor()) {
1187 // Set the current color for layers with palette index 0xffff, or non-colored
1188 // glyphs that may be present in a color font.
1189 //
1190 // Per comment in the Windows code at https://searchfox.org/mozilla-central/source/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp#1069-1074:
1191 // > "getLuminanceColor() is kinda sorta what is wanted here, but not really,
1192 // > it will often be the wrong value because it wan't designed for this.
1193 //
1194 // Empirically, in simple testcases it looks like a decent approximation of what
1195 // we need.
1196 SkColor4f color = SkColor4f::FromColor(context.getRec().getLuminanceColor());
1197 CGContextSetRGBFillColor(fCG.get(), color.fR, color.fG, color.fB, 1.0f);
1198 } else {
1199 // Draw black on white to create mask. (Special path exists to speed this up in CG.)
1200 // If light-on-dark is requested, draw white on black.
1201 CGContextSetGrayFillColor(fCG.get(), lightOnDark ? 1.0f : 0.0f, 1.0f);
1202 }
1203
1204 if (fDoAA != doAA) {
1205 CGContextSetShouldAntialias(fCG.get(), doAA);
1206 fDoAA = doAA;
1207 }
1208 if (fDoLCD != doLCD) {
1209 CGContextSetShouldSmoothFonts(fCG.get(), doLCD);
1210 fDoLCD = doLCD;
1211 }
1212
1213 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
1214 // skip rows based on the glyph's height
1215 image += (fSize.fHeight - glyph.height()) * fSize.fWidth;
1216
1217 // Erase to white (or transparent black if it's a color glyph, to not composite against white).
1218 // For light-on-dark, instead erase to black.
1219 uint32_t bgColor = (!glyph.isColor()) ? (lightOnDark ? 0xFF000000 : 0xFFFFFFFF) : 0x00000000;
1220 sk_memset_rect32(image, bgColor, glyph.width(), glyph.height(), rowBytes);
1221
1222 float subX = 0;
1223 float subY = 0;
1224 if (context.fDoSubPosition) {
1225 subX = SkFixedToFloat(glyph.getSubXFixed());
1226 subY = SkFixedToFloat(glyph.getSubYFixed());
1227 }
1228
1229 CGPoint point = CGPointMake(-glyph.left() + subX, glyph.top() + glyph.height() - subY);
1230 // Prior to 10.10, CTFontDrawGlyphs acted like CGContextShowGlyphsAtPositions and took
1231 // 'positions' which are in text space. The glyph location (in device space) must be
1232 // mapped into text space, so that CG can convert it back into device space.
1233 // In 10.10.1, this is handled directly in CTFontDrawGlyphs.
1234 //
1235 // However, in 10.10.2 color glyphs no longer rotate based on the font transform.
1236 // So always make the font transform identity and place the transform on the context.
1237 point = CGPointApplyAffineTransform(point, context.fInvTransform);
1238
1239 CTFontDrawGlyphs(context.fCTFont.get(), &glyphID, &point, 1, fCG.get());
1240
1241 SkASSERT(rowBytesPtr);
1242 *rowBytesPtr = rowBytes;
1243 return image;
1244 }
1245
generateGlyphCount(void)1246 unsigned SkScalerContext_Mac::generateGlyphCount(void) {
1247 return fGlyphCount;
1248 }
1249
generateAdvance(SkGlyph * glyph)1250 bool SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
1251 return false;
1252 }
1253
generateMetrics(SkGlyph * glyph)1254 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
1255 glyph->fMaskFormat = fRec.fMaskFormat;
1256
1257 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID();
1258 glyph->zeroMetrics();
1259
1260 // The following block produces cgAdvance in CG units (pixels, y up).
1261 CGSize cgAdvance;
1262 CTFontGetAdvancesForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal,
1263 &cgGlyph, &cgAdvance, 1);
1264 cgAdvance = CGSizeApplyAffineTransform(cgAdvance, fTransform);
1265 glyph->fAdvanceX = CGToFloat(cgAdvance.width);
1266 glyph->fAdvanceY = -CGToFloat(cgAdvance.height);
1267
1268 // The following produces skBounds in SkGlyph units (pixels, y down),
1269 // or returns early if skBounds would be empty.
1270 SkRect skBounds;
1271
1272 // Glyphs are always drawn from the horizontal origin. The caller must manually use the result
1273 // of CTFontGetVerticalTranslationsForGlyphs to calculate where to draw the glyph for vertical
1274 // glyphs. As a result, always get the horizontal bounds of a glyph and translate it if the
1275 // glyph is vertical. This avoids any diagreement between the various means of retrieving
1276 // vertical metrics.
1277 {
1278 // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up).
1279 CGRect cgBounds;
1280 CTFontGetBoundingRectsForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal,
1281 &cgGlyph, &cgBounds, 1);
1282 cgBounds = CGRectApplyAffineTransform(cgBounds, fTransform);
1283
1284 // BUG?
1285 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when
1286 // it should be empty. So, if we see a zero-advance, we check if it has an
1287 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance
1288 // is rare, so we won't incur a big performance cost for this extra check.
1289 // Avoid trying to create a path from a color font due to crashing on 10.9.
1290 if (0 == cgAdvance.width && 0 == cgAdvance.height &&
1291 SkMask::kARGB32_Format != glyph->fMaskFormat) {
1292 SkUniqueCFRef<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph,nullptr));
1293 if (!path || CGPathIsEmpty(path.get())) {
1294 return;
1295 }
1296 }
1297
1298 if (CGRectIsEmpty_inline(cgBounds)) {
1299 return;
1300 }
1301
1302 // Convert cgBounds to SkGlyph units (pixels, y down).
1303 skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height,
1304 cgBounds.size.width, cgBounds.size.height);
1305 }
1306
1307 // Currently the bounds are based on being rendered at (0,0).
1308 // The top left must not move, since that is the base from which subpixel positioning is offset.
1309 if (fDoSubPosition) {
1310 skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed());
1311 skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed());
1312 }
1313
1314 // We're trying to pack left and top into int16_t,
1315 // and width and height into uint16_t, after outsetting by 1.
1316 if (!SkRect::MakeXYWH(-32767, -32767, 65535, 65535).contains(skBounds)) {
1317 return;
1318 }
1319
1320 SkIRect skIBounds;
1321 skBounds.roundOut(&skIBounds);
1322 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing.
1323 // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset
1324 // is not currently known, as CG dilates the outlines by some percentage.
1325 // Note that if this context is A8 and not back-forming from LCD, there is no need to outset.
1326 skIBounds.outset(1, 1);
1327 glyph->fLeft = SkToS16(skIBounds.fLeft);
1328 glyph->fTop = SkToS16(skIBounds.fTop);
1329 glyph->fWidth = SkToU16(skIBounds.width());
1330 glyph->fHeight = SkToU16(skIBounds.height());
1331 }
1332
1333 #include "include/private/SkColorData.h"
1334
sk_pow2_table(size_t i)1335 static constexpr uint8_t sk_pow2_table(size_t i) {
1336 return SkToU8(((i * i + 128) / 255));
1337 }
1338
1339 /**
1340 * This will invert the gamma applied by CoreGraphics, so we can get linear
1341 * values.
1342 *
1343 * CoreGraphics obscurely defaults to 2.0 as the subpixel coverage gamma value.
1344 * The color space used does not appear to affect this choice.
1345 */
1346 static constexpr auto gLinearCoverageFromCGLCDValue = SkMakeArray<256>(sk_pow2_table);
1347
cgpixels_to_bits(uint8_t dst[],const CGRGBPixel src[],int count)1348 static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
1349 while (count > 0) {
1350 uint8_t mask = 0;
1351 for (int i = 7; i >= 0; --i) {
1352 mask |= ((CGRGBPixel_getAlpha(*src++) >> 7) ^ 0x1) << i;
1353 if (0 == --count) {
1354 break;
1355 }
1356 }
1357 *dst++ = mask;
1358 }
1359 }
1360
1361 template<bool APPLY_PREBLEND>
rgb_to_a8(CGRGBPixel rgb,const uint8_t * table8)1362 static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) {
1363 U8CPU r = 0xFF - ((rgb >> 16) & 0xFF);
1364 U8CPU g = 0xFF - ((rgb >> 8) & 0xFF);
1365 U8CPU b = 0xFF - ((rgb >> 0) & 0xFF);
1366 U8CPU lum = sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1367 #if SK_SHOW_TEXT_BLIT_COVERAGE
1368 lum = SkTMax(lum, (U8CPU)0x30);
1369 #endif
1370 return lum;
1371 }
1372
1373 template<bool APPLY_PREBLEND>
RGBToA8(const CGRGBPixel * SK_RESTRICT cgPixels,size_t cgRowBytes,const SkGlyph & glyph,const uint8_t * table8)1374 void SkScalerContext_Mac::RGBToA8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes,
1375 const SkGlyph& glyph, const uint8_t* table8) {
1376 const int width = glyph.fWidth;
1377 size_t dstRB = glyph.rowBytes();
1378 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
1379
1380 for (int y = 0; y < glyph.fHeight; y++) {
1381 for (int i = 0; i < width; ++i) {
1382 dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8);
1383 }
1384 cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes);
1385 dst = SkTAddOffset<uint8_t>(dst, dstRB);
1386 }
1387 }
1388
1389 template<bool APPLY_PREBLEND>
RGBToLcd16(CGRGBPixel rgb,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1390 uint16_t SkScalerContext_Mac::RGBToLcd16(CGRGBPixel rgb, const uint8_t* tableR,
1391 const uint8_t* tableG,
1392 const uint8_t* tableB) {
1393 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 16) & 0xFF), tableR);
1394 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 8) & 0xFF), tableG);
1395 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 0) & 0xFF), tableB);
1396 #if SK_SHOW_TEXT_BLIT_COVERAGE
1397 r = SkTMax(r, (U8CPU)0x30);
1398 g = SkTMax(g, (U8CPU)0x30);
1399 b = SkTMax(b, (U8CPU)0x30);
1400 #endif
1401 return SkPack888ToRGB16(r, g, b);
1402 }
1403
1404 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)1405 void SkScalerContext_Mac::RGBToLcd16(const CGRGBPixel* SK_RESTRICT cgPixels,
1406 size_t cgRowBytes,
1407 const SkGlyph& glyph,
1408 const uint8_t* tableR,
1409 const uint8_t* tableG,
1410 const uint8_t* tableB) {
1411 const int width = glyph.fWidth;
1412 size_t dstRB = glyph.rowBytes();
1413 uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage;
1414
1415 for (int y = 0; y < glyph.fHeight; y++) {
1416 for (int i = 0; i < width; i++) {
1417 dst[i] = RGBToLcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB);
1418 }
1419 cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes);
1420 dst = SkTAddOffset<uint16_t>(dst, dstRB);
1421 }
1422 }
1423
cgpixels_to_pmcolor(CGRGBPixel rgb)1424 static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb) {
1425 U8CPU a = (rgb >> 24) & 0xFF;
1426 U8CPU r = (rgb >> 16) & 0xFF;
1427 U8CPU g = (rgb >> 8) & 0xFF;
1428 U8CPU b = (rgb >> 0) & 0xFF;
1429 #if SK_SHOW_TEXT_BLIT_COVERAGE
1430 a = SkTMax(a, (U8CPU)0x30);
1431 #endif
1432 return SkPackARGB32(a, r, g, b);
1433 }
1434
generateImage(const SkGlyph & glyph)1435 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
1436 CGGlyph cgGlyph = SkTo<CGGlyph>(glyph.getGlyphID());
1437
1438 // FIXME: lcd smoothed un-hinted rasterization unsupported.
1439 bool requestSmooth = fRec.getHinting() != SkFontHinting::kNone;
1440 bool lightOnDark = (fRec.fFlags & SkScalerContext::kLightOnDark_Flag) != 0;
1441
1442 // Draw the glyph
1443 size_t cgRowBytes;
1444 CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, requestSmooth, lightOnDark);
1445 if (cgPixels == nullptr) {
1446 return;
1447 }
1448
1449 // Fix the glyph
1450 if ((glyph.fMaskFormat == SkMask::kLCD16_Format) ||
1451 (glyph.fMaskFormat == SkMask::kA8_Format
1452 && requestSmooth
1453 && smooth_behavior() != SmoothBehavior::none))
1454 {
1455 const uint8_t* linear = gLinearCoverageFromCGLCDValue.data();
1456
1457 //Note that the following cannot really be integrated into the
1458 //pre-blend, since we may not be applying the pre-blend; when we aren't
1459 //applying the pre-blend it means that a filter wants linear anyway.
1460 //Other code may also be applying the pre-blend, so we'd need another
1461 //one with this and one without.
1462 CGRGBPixel* addr = cgPixels;
1463 for (int y = 0; y < glyph.fHeight; ++y) {
1464 for (int x = 0; x < glyph.fWidth; ++x) {
1465 int r = linear[(addr[x] >> 16) & 0xFF];
1466 int g = linear[(addr[x] >> 8) & 0xFF];
1467 int b = linear[(addr[x] >> 0) & 0xFF];
1468 // If light-on-dark was requested, the mask is drawn inverted.
1469 if (lightOnDark) {
1470 r = 255 - r;
1471 g = 255 - g;
1472 b = 255 - b;
1473 }
1474 addr[x] = (r << 16) | (g << 8) | b;
1475 }
1476 addr = SkTAddOffset<CGRGBPixel>(addr, cgRowBytes);
1477 }
1478 }
1479
1480 // Convert glyph to mask
1481 switch (glyph.fMaskFormat) {
1482 case SkMask::kLCD16_Format: {
1483 if (fPreBlend.isApplicable()) {
1484 RGBToLcd16<true>(cgPixels, cgRowBytes, glyph,
1485 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1486 } else {
1487 RGBToLcd16<false>(cgPixels, cgRowBytes, glyph,
1488 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1489 }
1490 } break;
1491 case SkMask::kA8_Format: {
1492 if (fPreBlend.isApplicable()) {
1493 RGBToA8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1494 } else {
1495 RGBToA8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
1496 }
1497 } break;
1498 case SkMask::kBW_Format: {
1499 const int width = glyph.fWidth;
1500 size_t dstRB = glyph.rowBytes();
1501 uint8_t* dst = (uint8_t*)glyph.fImage;
1502 for (int y = 0; y < glyph.fHeight; y++) {
1503 cgpixels_to_bits(dst, cgPixels, width);
1504 cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes);
1505 dst = SkTAddOffset<uint8_t>(dst, dstRB);
1506 }
1507 } break;
1508 case SkMask::kARGB32_Format: {
1509 const int width = glyph.fWidth;
1510 size_t dstRB = glyph.rowBytes();
1511 SkPMColor* dst = (SkPMColor*)glyph.fImage;
1512 for (int y = 0; y < glyph.fHeight; y++) {
1513 for (int x = 0; x < width; ++x) {
1514 dst[x] = cgpixels_to_pmcolor(cgPixels[x]);
1515 }
1516 cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes);
1517 dst = SkTAddOffset<SkPMColor>(dst, dstRB);
1518 }
1519 } break;
1520 default:
1521 SkDEBUGFAIL("unexpected mask format");
1522 break;
1523 }
1524 }
1525
1526 /*
1527 * Our subpixel resolution is only 2 bits in each direction, so a scale of 4
1528 * seems sufficient, and possibly even correct, to allow the hinted outline
1529 * to be subpixel positioned.
1530 */
1531 #define kScaleForSubPixelPositionHinting (4.0f)
1532
generatePath(SkGlyphID glyph,SkPath * path)1533 bool SkScalerContext_Mac::generatePath(SkGlyphID glyph, SkPath* path) {
1534 SkScalar scaleX = SK_Scalar1;
1535 SkScalar scaleY = SK_Scalar1;
1536
1537 CGAffineTransform xform = fTransform;
1538 /*
1539 * For subpixel positioning, we want to return an unhinted outline, so it
1540 * can be positioned nicely at fractional offsets. However, we special-case
1541 * if the baseline of the (horizontal) text is axis-aligned. In those cases
1542 * we want to retain hinting in the direction orthogonal to the baseline.
1543 * e.g. for horizontal baseline, we want to retain hinting in Y.
1544 * The way we remove hinting is to scale the font by some value (4) in that
1545 * direction, ask for the path, and then scale the path back down.
1546 */
1547 if (fDoSubPosition) {
1548 // start out by assuming that we want no hining in X and Y
1549 scaleX = scaleY = kScaleForSubPixelPositionHinting;
1550 // now see if we need to restore hinting for axis-aligned baselines
1551 switch (this->computeAxisAlignmentForHText()) {
1552 case kX_SkAxisAlignment:
1553 scaleY = SK_Scalar1; // want hinting in the Y direction
1554 break;
1555 case kY_SkAxisAlignment:
1556 scaleX = SK_Scalar1; // want hinting in the X direction
1557 break;
1558 default:
1559 break;
1560 }
1561
1562 CGAffineTransform scale(CGAffineTransformMakeScale(ScalarToCG(scaleX), ScalarToCG(scaleY)));
1563 xform = CGAffineTransformConcat(fTransform, scale);
1564 }
1565
1566 CGGlyph cgGlyph = SkTo<CGGlyph>(glyph);
1567 SkUniqueCFRef<CGPathRef> cgPath(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph, &xform));
1568
1569 path->reset();
1570 if (!cgPath) {
1571 return false;
1572 }
1573
1574 CGPathApply(cgPath.get(), path, SkScalerContext_Mac::CTPathElement);
1575 if (fDoSubPosition) {
1576 SkMatrix m;
1577 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY));
1578 path->transform(m);
1579 }
1580 return true;
1581 }
1582
generateFontMetrics(SkFontMetrics * metrics)1583 void SkScalerContext_Mac::generateFontMetrics(SkFontMetrics* metrics) {
1584 if (nullptr == metrics) {
1585 return;
1586 }
1587
1588 CGRect theBounds = CTFontGetBoundingBox(fCTFont.get());
1589
1590 metrics->fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds));
1591 metrics->fAscent = CGToScalar(-CTFontGetAscent(fCTFont.get()));
1592 metrics->fDescent = CGToScalar( CTFontGetDescent(fCTFont.get()));
1593 metrics->fBottom = CGToScalar(-CGRectGetMinY_inline(theBounds));
1594 metrics->fLeading = CGToScalar( CTFontGetLeading(fCTFont.get()));
1595 metrics->fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds));
1596 metrics->fXMin = CGToScalar( CGRectGetMinX_inline(theBounds));
1597 metrics->fXMax = CGToScalar( CGRectGetMaxX_inline(theBounds));
1598 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
1599 metrics->fXHeight = CGToScalar( CTFontGetXHeight(fCTFont.get()));
1600 metrics->fCapHeight = CGToScalar( CTFontGetCapHeight(fCTFont.get()));
1601 metrics->fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont.get()));
1602 metrics->fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont.get()));
1603
1604 metrics->fFlags = 0;
1605 metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag;
1606 metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag;
1607
1608 // See https://bugs.chromium.org/p/skia/issues/detail?id=6203
1609 // At least on 10.12.3 with memory based fonts the x-height is always 0.6666 of the ascent and
1610 // the cap-height is always 0.8888 of the ascent. It appears that the values from the 'OS/2'
1611 // table are read, but then overwritten if the font is not a system font. As a result, if there
1612 // is a valid 'OS/2' table available use the values from the table if they aren't too strange.
1613 struct OS2HeightMetrics {
1614 SK_OT_SHORT sxHeight;
1615 SK_OT_SHORT sCapHeight;
1616 } heights;
1617 size_t bytesRead = this->getTypeface()->getTableData(
1618 SkTEndian_SwapBE32(SkOTTableOS2::TAG), offsetof(SkOTTableOS2, version.v2.sxHeight),
1619 sizeof(heights), &heights);
1620 if (bytesRead == sizeof(heights)) {
1621 // 'fontSize' is correct because the entire resolved size is set by the constructor.
1622 CGFloat fontSize = CTFontGetSize(this->fCTFont.get());
1623 unsigned upem = CTFontGetUnitsPerEm(this->fCTFont.get());
1624 unsigned maxSaneHeight = upem * 2;
1625 uint16_t xHeight = SkEndian_SwapBE16(heights.sxHeight);
1626 if (xHeight && xHeight < maxSaneHeight) {
1627 metrics->fXHeight = CGToScalar(xHeight * fontSize / upem);
1628 }
1629 uint16_t capHeight = SkEndian_SwapBE16(heights.sCapHeight);
1630 if (capHeight && capHeight < maxSaneHeight) {
1631 metrics->fCapHeight = CGToScalar(capHeight * fontSize / upem);
1632 }
1633 }
1634 }
1635
CTPathElement(void * info,const CGPathElement * element)1636 void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) {
1637 SkPath* skPath = (SkPath*)info;
1638
1639 // Process the path element
1640 switch (element->type) {
1641 case kCGPathElementMoveToPoint:
1642 skPath->moveTo(element->points[0].x, -element->points[0].y);
1643 break;
1644
1645 case kCGPathElementAddLineToPoint:
1646 skPath->lineTo(element->points[0].x, -element->points[0].y);
1647 break;
1648
1649 case kCGPathElementAddQuadCurveToPoint:
1650 skPath->quadTo(element->points[0].x, -element->points[0].y,
1651 element->points[1].x, -element->points[1].y);
1652 break;
1653
1654 case kCGPathElementAddCurveToPoint:
1655 skPath->cubicTo(element->points[0].x, -element->points[0].y,
1656 element->points[1].x, -element->points[1].y,
1657 element->points[2].x, -element->points[2].y);
1658 break;
1659
1660 case kCGPathElementCloseSubpath:
1661 skPath->close();
1662 break;
1663
1664 default:
1665 SkDEBUGFAIL("Unknown path element!");
1666 break;
1667 }
1668 }
1669
1670
1671 ///////////////////////////////////////////////////////////////////////////////
1672
1673 // Returns nullptr on failure
1674 // Call must still manage its ownership of provider
create_from_dataProvider(SkUniqueCFRef<CGDataProviderRef> provider,std::unique_ptr<SkStreamAsset> providedData,int ttcIndex)1675 static sk_sp<SkTypeface> create_from_dataProvider(SkUniqueCFRef<CGDataProviderRef> provider,
1676 std::unique_ptr<SkStreamAsset> providedData,
1677 int ttcIndex) {
1678 if (ttcIndex != 0) {
1679 return nullptr;
1680 }
1681 SkUniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
1682 if (!cg) {
1683 return nullptr;
1684 }
1685 SkUniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg.get(), 0, nullptr, nullptr));
1686 if (!ct) {
1687 return nullptr;
1688 }
1689 return create_from_CTFontRef(std::move(ct), nullptr, std::move(providedData));
1690 }
1691
1692 // Web fonts added to the CTFont registry do not return their character set.
1693 // Iterate through the font in this case. The existing caller caches the result,
1694 // so the performance impact isn't too bad.
populate_glyph_to_unicode_slow(CTFontRef ctFont,CFIndex glyphCount,SkUnichar * out)1695 static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
1696 SkUnichar* out) {
1697 sk_bzero(out, glyphCount * sizeof(SkUnichar));
1698 UniChar unichar = 0;
1699 while (glyphCount > 0) {
1700 CGGlyph glyph;
1701 if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
1702 if (out[glyph] == 0) {
1703 out[glyph] = unichar;
1704 --glyphCount;
1705 }
1706 }
1707 if (++unichar == 0) {
1708 break;
1709 }
1710 }
1711 }
1712
1713 static constexpr uint16_t kPlaneSize = 1 << 13;
1714
get_plane_glyph_map(const uint8_t * bits,CTFontRef ctFont,CFIndex glyphCount,SkUnichar * glyphToUnicode,uint8_t planeIndex)1715 static void get_plane_glyph_map(const uint8_t* bits,
1716 CTFontRef ctFont,
1717 CFIndex glyphCount,
1718 SkUnichar* glyphToUnicode,
1719 uint8_t planeIndex) {
1720 SkUnichar planeOrigin = (SkUnichar)planeIndex << 16; // top half of codepoint.
1721 for (uint16_t i = 0; i < kPlaneSize; i++) {
1722 uint8_t mask = bits[i];
1723 if (!mask) {
1724 continue;
1725 }
1726 for (uint8_t j = 0; j < 8; j++) {
1727 if (0 == (mask & ((uint8_t)1 << j))) {
1728 continue;
1729 }
1730 uint16_t planeOffset = (i << 3) | j;
1731 SkUnichar codepoint = planeOrigin | (SkUnichar)planeOffset;
1732 uint16_t utf16[2] = {planeOffset, 0};
1733 size_t count = 1;
1734 if (planeOrigin != 0) {
1735 count = SkUTF::ToUTF16(codepoint, utf16);
1736 }
1737 CGGlyph glyphs[2] = {0, 0};
1738 if (CTFontGetGlyphsForCharacters(ctFont, utf16, glyphs, count)) {
1739 SkASSERT(glyphs[1] == 0);
1740 SkASSERT(glyphs[0] < glyphCount);
1741 // CTFontCopyCharacterSet and CTFontGetGlyphsForCharacters seem to add 'support'
1742 // for characters 0x9, 0xA, and 0xD mapping them to the glyph for character 0x20?
1743 // Prefer mappings to codepoints at or above 0x20.
1744 if (glyphToUnicode[glyphs[0]] < 0x20) {
1745 glyphToUnicode[glyphs[0]] = codepoint;
1746 }
1747 }
1748 }
1749 }
1750 }
1751 // Construct Glyph to Unicode table.
populate_glyph_to_unicode(CTFontRef ctFont,CFIndex glyphCount,SkUnichar * glyphToUnicode)1752 static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
1753 SkUnichar* glyphToUnicode) {
1754 sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount);
1755 SkUniqueCFRef<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
1756 if (!charSet) {
1757 populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
1758 return;
1759 }
1760
1761 SkUniqueCFRef<CFDataRef> bitmap(
1762 CFCharacterSetCreateBitmapRepresentation(nullptr, charSet.get()));
1763 if (!bitmap) {
1764 return;
1765 }
1766 CFIndex dataLength = CFDataGetLength(bitmap.get());
1767 if (!dataLength) {
1768 return;
1769 }
1770 SkASSERT(dataLength >= kPlaneSize);
1771 const UInt8* bits = CFDataGetBytePtr(bitmap.get());
1772
1773 get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, 0);
1774 /*
1775 A CFData object that specifies the bitmap representation of the Unicode
1776 character points the for the new character set. The bitmap representation could
1777 contain all the Unicode character range starting from BMP to Plane 16. The
1778 first 8KiB (8192 bytes) of the data represent the BMP range. The BMP range 8KiB
1779 can be followed by zero to sixteen 8KiB bitmaps, each prepended with the plane
1780 index byte. For example, the bitmap representing the BMP and Plane 2 has the
1781 size of 16385 bytes (8KiB for BMP, 1 byte index, and a 8KiB bitmap for Plane
1782 2). The plane index byte, in this case, contains the integer value two.
1783 */
1784
1785 if (dataLength <= kPlaneSize) {
1786 return;
1787 }
1788 int extraPlaneCount = (dataLength - kPlaneSize) / (1 + kPlaneSize);
1789 SkASSERT(dataLength == kPlaneSize + extraPlaneCount * (1 + kPlaneSize));
1790 while (extraPlaneCount-- > 0) {
1791 bits += kPlaneSize;
1792 uint8_t planeIndex = *bits++;
1793 SkASSERT(planeIndex >= 1);
1794 SkASSERT(planeIndex <= 16);
1795 get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, planeIndex);
1796 }
1797 }
1798
1799 /** Assumes src and dst are not nullptr. */
CFStringToSkString(CFStringRef src,SkString * dst)1800 static void CFStringToSkString(CFStringRef src, SkString* dst) {
1801 // Reserve enough room for the worst-case string,
1802 // plus 1 byte for the trailing null.
1803 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src),
1804 kCFStringEncodingUTF8) + 1;
1805 dst->resize(length);
1806 CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8);
1807 // Resize to the actual UTF-8 length used, stripping the null character.
1808 dst->resize(strlen(dst->c_str()));
1809 }
1810
getGlyphToUnicodeMap(SkUnichar * dstArray) const1811 void SkTypeface_Mac::getGlyphToUnicodeMap(SkUnichar* dstArray) const {
1812 SkUniqueCFRef<CTFontRef> ctFont =
1813 ctfont_create_exact_copy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()), nullptr);
1814 CFIndex glyphCount = CTFontGetGlyphCount(ctFont.get());
1815 populate_glyph_to_unicode(ctFont.get(), glyphCount, dstArray);
1816 }
1817
onGetAdvancedMetrics() const1818 std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_Mac::onGetAdvancedMetrics() const {
1819
1820 SkUniqueCFRef<CTFontRef> ctFont =
1821 ctfont_create_exact_copy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()), nullptr);
1822
1823 std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics);
1824
1825 {
1826 SkUniqueCFRef<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont.get()));
1827 if (fontName.get()) {
1828 CFStringToSkString(fontName.get(), &info->fPostScriptName);
1829 info->fFontName = info->fPostScriptName;
1830 }
1831 }
1832
1833 // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when
1834 // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always
1835 // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and
1836 // CGFontCopyVariations here until support for 10.10 and earlier is removed.
1837 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont.get(), nullptr));
1838 if (cgFont) {
1839 SkUniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get()));
1840 if (cgAxes && CFArrayGetCount(cgAxes.get()) > 0) {
1841 info->fFlags |= SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag;
1842 }
1843 }
1844
1845 SkOTTableOS2_V4::Type fsType;
1846 if (sizeof(fsType) == this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG),
1847 offsetof(SkOTTableOS2_V4, fsType),
1848 sizeof(fsType),
1849 &fsType)) {
1850 SkOTUtils::SetAdvancedTypefaceFlags(fsType, info.get());
1851 }
1852
1853 // If it's not a truetype font, mark it as 'other'. Assume that TrueType
1854 // fonts always have both glyf and loca tables. At the least, this is what
1855 // sfntly needs to subset the font. CTFontCopyAttribute() does not always
1856 // succeed in determining this directly.
1857 if (!this->getTableSize('glyf') || !this->getTableSize('loca')) {
1858 return info;
1859 }
1860
1861 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1862 CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get());
1863 if (symbolicTraits & kCTFontMonoSpaceTrait) {
1864 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1865 }
1866 if (symbolicTraits & kCTFontItalicTrait) {
1867 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1868 }
1869 CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
1870 if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
1871 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1872 } else if (stylisticClass & kCTFontScriptsClass) {
1873 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1874 }
1875 info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont.get());
1876 info->fAscent = (int16_t) CTFontGetAscent(ctFont.get());
1877 info->fDescent = (int16_t) CTFontGetDescent(ctFont.get());
1878 info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont.get());
1879 CGRect bbox = CTFontGetBoundingBox(ctFont.get());
1880
1881 SkRect r;
1882 r.setLTRB(CGToScalar(CGRectGetMinX_inline(bbox)), // Left
1883 CGToScalar(CGRectGetMaxY_inline(bbox)), // Top
1884 CGToScalar(CGRectGetMaxX_inline(bbox)), // Right
1885 CGToScalar(CGRectGetMinY_inline(bbox))); // Bottom
1886
1887 r.roundOut(&(info->fBBox));
1888
1889 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1890 // This probably isn't very good with an italic font.
1891 int16_t min_width = SHRT_MAX;
1892 info->fStemV = 0;
1893 static const UniChar stem_chars[] = {'i', 'I', '!', '1'};
1894 const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]);
1895 CGGlyph glyphs[count];
1896 CGRect boundingRects[count];
1897 if (CTFontGetGlyphsForCharacters(ctFont.get(), stem_chars, glyphs, count)) {
1898 CTFontGetBoundingRectsForGlyphs(ctFont.get(), kCTFontOrientationHorizontal,
1899 glyphs, boundingRects, count);
1900 for (size_t i = 0; i < count; i++) {
1901 int16_t width = (int16_t) boundingRects[i].size.width;
1902 if (width > 0 && width < min_width) {
1903 min_width = width;
1904 info->fStemV = min_width;
1905 }
1906 }
1907 }
1908 return info;
1909 }
1910
1911 ///////////////////////////////////////////////////////////////////////////////
1912
get_font_type_tag(CTFontRef ctFont)1913 static SK_SFNT_ULONG get_font_type_tag(CTFontRef ctFont) {
1914 SkUniqueCFRef<CFNumberRef> fontFormatRef(
1915 static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
1916 if (!fontFormatRef) {
1917 return 0;
1918 }
1919
1920 SInt32 fontFormatValue;
1921 if (!CFNumberGetValue(fontFormatRef.get(), kCFNumberSInt32Type, &fontFormatValue)) {
1922 return 0;
1923 }
1924
1925 switch (fontFormatValue) {
1926 case kCTFontFormatOpenTypePostScript:
1927 return SkSFNTHeader::fontType_OpenTypeCFF::TAG;
1928 case kCTFontFormatOpenTypeTrueType:
1929 return SkSFNTHeader::fontType_WindowsTrueType::TAG;
1930 case kCTFontFormatTrueType:
1931 return SkSFNTHeader::fontType_MacTrueType::TAG;
1932 case kCTFontFormatPostScript:
1933 return SkSFNTHeader::fontType_PostScript::TAG;
1934 case kCTFontFormatBitmap:
1935 return SkSFNTHeader::fontType_MacTrueType::TAG;
1936 case kCTFontFormatUnrecognized:
1937 default:
1938 return 0;
1939 }
1940 }
1941
onOpenStream(int * ttcIndex) const1942 std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
1943 *ttcIndex = 0;
1944
1945 fInitStream([this]{
1946 if (fStream) {
1947 return;
1948 }
1949
1950 SK_SFNT_ULONG fontType = get_font_type_tag(fFontRef.get());
1951
1952 // get table tags
1953 int numTables = this->countTables();
1954 SkTDArray<SkFontTableTag> tableTags;
1955 tableTags.setCount(numTables);
1956 this->getTableTags(tableTags.begin());
1957
1958 // CT seems to be unreliable in being able to obtain the type,
1959 // even if all we want is the first four bytes of the font resource.
1960 // Just the presence of the FontForge 'FFTM' table seems to throw it off.
1961 if (fontType == 0) {
1962 fontType = SkSFNTHeader::fontType_WindowsTrueType::TAG;
1963
1964 // see https://skbug.com/7630#c7
1965 bool couldBeCFF = false;
1966 constexpr SkFontTableTag CFFTag = SkSetFourByteTag('C', 'F', 'F', ' ');
1967 constexpr SkFontTableTag CFF2Tag = SkSetFourByteTag('C', 'F', 'F', '2');
1968 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1969 if (CFFTag == tableTags[tableIndex] || CFF2Tag == tableTags[tableIndex]) {
1970 couldBeCFF = true;
1971 }
1972 }
1973 if (couldBeCFF) {
1974 fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG;
1975 }
1976 }
1977
1978 // Sometimes CoreGraphics incorrectly thinks a font is kCTFontFormatPostScript.
1979 // It is exceedingly unlikely that this is the case, so double check
1980 // (see https://crbug.com/809763 ).
1981 if (fontType == SkSFNTHeader::fontType_PostScript::TAG) {
1982 // see if there are any required 'typ1' tables (see Adobe Technical Note #5180)
1983 bool couldBeTyp1 = false;
1984 constexpr SkFontTableTag TYPE1Tag = SkSetFourByteTag('T', 'Y', 'P', '1');
1985 constexpr SkFontTableTag CIDTag = SkSetFourByteTag('C', 'I', 'D', ' ');
1986 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1987 if (TYPE1Tag == tableTags[tableIndex] || CIDTag == tableTags[tableIndex]) {
1988 couldBeTyp1 = true;
1989 }
1990 }
1991 if (!couldBeTyp1) {
1992 fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG;
1993 }
1994 }
1995
1996 // get the table sizes and accumulate the total size of the font
1997 SkTDArray<size_t> tableSizes;
1998 size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
1999 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
2000 size_t tableSize = this->getTableSize(tableTags[tableIndex]);
2001 totalSize += (tableSize + 3) & ~3;
2002 *tableSizes.append() = tableSize;
2003 }
2004
2005 // reserve memory for stream, and zero it (tables must be zero padded)
2006 fStream.reset(new SkMemoryStream(totalSize));
2007 char* dataStart = (char*)fStream->getMemoryBase();
2008 sk_bzero(dataStart, totalSize);
2009 char* dataPtr = dataStart;
2010
2011 // compute font header entries
2012 uint16_t entrySelector = 0;
2013 uint16_t searchRange = 1;
2014 while (searchRange < numTables >> 1) {
2015 entrySelector++;
2016 searchRange <<= 1;
2017 }
2018 searchRange <<= 4;
2019 uint16_t rangeShift = (numTables << 4) - searchRange;
2020
2021 // write font header
2022 SkSFNTHeader* header = (SkSFNTHeader*)dataPtr;
2023 header->fontType = fontType;
2024 header->numTables = SkEndian_SwapBE16(numTables);
2025 header->searchRange = SkEndian_SwapBE16(searchRange);
2026 header->entrySelector = SkEndian_SwapBE16(entrySelector);
2027 header->rangeShift = SkEndian_SwapBE16(rangeShift);
2028 dataPtr += sizeof(SkSFNTHeader);
2029
2030 // write tables
2031 SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr;
2032 dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
2033 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
2034 size_t tableSize = tableSizes[tableIndex];
2035 this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
2036 entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]);
2037 entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr,
2038 tableSize));
2039 entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart));
2040 entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize));
2041
2042 dataPtr += (tableSize + 3) & ~3;
2043 ++entry;
2044 }
2045 });
2046 return fStream->duplicate();
2047 }
2048
2049 struct NonDefaultAxesContext {
2050 SkFixed* axisValue;
2051 CFArrayRef cgAxes;
2052 };
set_non_default_axes(CFTypeRef key,CFTypeRef value,void * context)2053 static void set_non_default_axes(CFTypeRef key, CFTypeRef value, void* context) {
2054 NonDefaultAxesContext* self = static_cast<NonDefaultAxesContext*>(context);
2055
2056 if (CFGetTypeID(key) != CFStringGetTypeID() || CFGetTypeID(value) != CFNumberGetTypeID()) {
2057 return;
2058 }
2059
2060 // The key is a CFString which is a string from the 'name' table.
2061 // Search the cgAxes for an axis with this name, and use its index to store the value.
2062 CFIndex keyIndex = -1;
2063 CFStringRef keyString = static_cast<CFStringRef>(key);
2064 for (CFIndex i = 0; i < CFArrayGetCount(self->cgAxes); ++i) {
2065 CFTypeRef cgAxis = CFArrayGetValueAtIndex(self->cgAxes, i);
2066 if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) {
2067 continue;
2068 }
2069
2070 CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis);
2071 CFTypeRef cgAxisName = CFDictionaryGetValue(cgAxisDict, kCGFontVariationAxisName);
2072 if (!cgAxisName || CFGetTypeID(cgAxisName) != CFStringGetTypeID()) {
2073 continue;
2074 }
2075 CFStringRef cgAxisNameString = static_cast<CFStringRef>(cgAxisName);
2076 if (CFStringCompare(keyString, cgAxisNameString, 0) == kCFCompareEqualTo) {
2077 keyIndex = i;
2078 break;
2079 }
2080 }
2081 if (keyIndex == -1) {
2082 return;
2083 }
2084
2085 CFNumberRef valueNumber = static_cast<CFNumberRef>(value);
2086 double valueDouble;
2087 if (!CFNumberGetValue(valueNumber, kCFNumberDoubleType, &valueDouble) ||
2088 valueDouble < SkFixedToDouble(SK_FixedMin) || SkFixedToDouble(SK_FixedMax) < valueDouble)
2089 {
2090 return;
2091 }
2092 self->axisValue[keyIndex] = SkDoubleToFixed(valueDouble);
2093 }
get_variations(CTFontRef ctFont,CFIndex * cgAxisCount,SkAutoSTMalloc<4,SkFixed> * axisValues)2094 static bool get_variations(CTFontRef ctFont, CFIndex* cgAxisCount,
2095 SkAutoSTMalloc<4, SkFixed>* axisValues)
2096 {
2097 // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when
2098 // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always
2099 // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and
2100 // CGFontCopyVariations here until support for 10.10 and earlier is removed.
2101 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr));
2102 if (!cgFont) {
2103 return false;
2104 }
2105
2106 SkUniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get()));
2107 // If a font has no variations CGFontCopyVariations returns nullptr (instead of an empty dict).
2108 if (!cgVariations) {
2109 return false;
2110 }
2111
2112 SkUniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get()));
2113 if (!cgAxes) {
2114 return false;
2115 }
2116 *cgAxisCount = CFArrayGetCount(cgAxes.get());
2117 axisValues->reset(*cgAxisCount);
2118
2119 // Set all of the axes to their default values.
2120 // Fail if any default value cannot be determined.
2121 for (CFIndex i = 0; i < *cgAxisCount; ++i) {
2122 CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes.get(), i);
2123 if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) {
2124 return false;
2125 }
2126
2127 CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis);
2128 CFTypeRef axisDefaultValue = CFDictionaryGetValue(cgAxisDict,
2129 kCGFontVariationAxisDefaultValue);
2130 if (!axisDefaultValue || CFGetTypeID(axisDefaultValue) != CFNumberGetTypeID()) {
2131 return false;
2132 }
2133 CFNumberRef axisDefaultValueNumber = static_cast<CFNumberRef>(axisDefaultValue);
2134 double axisDefaultValueDouble;
2135 if (!CFNumberGetValue(axisDefaultValueNumber, kCFNumberDoubleType, &axisDefaultValueDouble))
2136 {
2137 return false;
2138 }
2139 if (axisDefaultValueDouble < SkFixedToDouble(SK_FixedMin) ||
2140 SkFixedToDouble(SK_FixedMax) < axisDefaultValueDouble)
2141 {
2142 return false;
2143 }
2144 (*axisValues)[(int)i] = SkDoubleToFixed(axisDefaultValueDouble);
2145 }
2146
2147 // Override the default values with the given font's stated axis values.
2148 NonDefaultAxesContext c = { axisValues->get(), cgAxes.get() };
2149 CFDictionaryApplyFunction(cgVariations.get(), set_non_default_axes, &c);
2150
2151 return true;
2152 }
onMakeFontData() const2153 std::unique_ptr<SkFontData> SkTypeface_Mac::onMakeFontData() const {
2154 int index;
2155 std::unique_ptr<SkStreamAsset> stream(this->onOpenStream(&index));
2156
2157 CFIndex cgAxisCount;
2158 SkAutoSTMalloc<4, SkFixed> axisValues;
2159 if (get_variations(fFontRef.get(), &cgAxisCount, &axisValues)) {
2160 return skstd::make_unique<SkFontData>(std::move(stream), index,
2161 axisValues.get(), cgAxisCount);
2162 }
2163 return skstd::make_unique<SkFontData>(std::move(stream), index, nullptr, 0);
2164 }
2165
2166 /** Creates a CT variation dictionary {tag, value} from a CG variation dictionary {name, value}. */
ct_variation_from_cg_variation(CFDictionaryRef cgVariations,CFArrayRef ctAxes)2167 static SkUniqueCFRef<CFDictionaryRef> ct_variation_from_cg_variation(CFDictionaryRef cgVariations,
2168 CFArrayRef ctAxes) {
2169
2170 SkUniqueCFRef<CFMutableDictionaryRef> ctVariations(
2171 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2172 &kCFTypeDictionaryKeyCallBacks,
2173 &kCFTypeDictionaryValueCallBacks));
2174
2175 CFIndex axisCount = CFArrayGetCount(ctAxes);
2176 for (CFIndex i = 0; i < axisCount; ++i) {
2177 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes, i);
2178 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
2179 return nullptr;
2180 }
2181 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
2182
2183 // The assumption is that values produced by kCTFontVariationAxisNameKey and
2184 // kCGFontVariationAxisName will always be equal.
2185 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey);
2186 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
2187 return nullptr;
2188 }
2189
2190 CFTypeRef axisValue = CFDictionaryGetValue(cgVariations, axisName);
2191 if (!axisValue || CFGetTypeID(axisValue) != CFNumberGetTypeID()) {
2192 return nullptr;
2193 }
2194
2195 CFTypeRef axisTag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
2196 if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) {
2197 return nullptr;
2198 }
2199
2200 CFDictionaryAddValue(ctVariations.get(), axisTag, axisValue);
2201 }
2202 return ctVariations;
2203 }
2204
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount) const2205 int SkTypeface_Mac::onGetVariationDesignPosition(
2206 SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
2207 {
2208 // The CGFont variation data does not contain the tag.
2209
2210 // CTFontCopyVariationAxes returns nullptr for CGFontCreateWithDataProvider fonts with
2211 // macOS 10.10 and iOS 9 or earlier. When this happens, there is no API to provide the tag.
2212 SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get()));
2213 if (!ctAxes) {
2214 return -1;
2215 }
2216 CFIndex axisCount = CFArrayGetCount(ctAxes.get());
2217 if (!coordinates || coordinateCount < axisCount) {
2218 return axisCount;
2219 }
2220
2221 // This call always returns nullptr on 10.11 and under for CGFontCreateWithDataProvider fonts.
2222 // When this happens, try converting the CG variation to a CT variation.
2223 // On 10.12 and later, this only returns non-default variations.
2224 SkUniqueCFRef<CFDictionaryRef> ctVariations(CTFontCopyVariation(fFontRef.get()));
2225 if (!ctVariations) {
2226 // When 10.11 and earlier are no longer supported, the following code can be replaced with
2227 // return -1 and ct_variation_from_cg_variation can be removed.
2228 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr));
2229 if (!cgFont) {
2230 return -1;
2231 }
2232 SkUniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get()));
2233 if (!cgVariations) {
2234 return -1;
2235 }
2236 ctVariations = ct_variation_from_cg_variation(cgVariations.get(), ctAxes.get());
2237 if (!ctVariations) {
2238 return -1;
2239 }
2240 }
2241
2242 for (int i = 0; i < axisCount; ++i) {
2243 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
2244 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
2245 return -1;
2246 }
2247 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
2248
2249 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
2250 if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
2251 return -1;
2252 }
2253 CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
2254 int64_t tagLong;
2255 if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
2256 return -1;
2257 }
2258 coordinates[i].axis = tagLong;
2259
2260 CGFloat variationCGFloat;
2261 CFTypeRef variationValue = CFDictionaryGetValue(ctVariations.get(), tagNumber);
2262 if (variationValue) {
2263 if (CFGetTypeID(variationValue) != CFNumberGetTypeID()) {
2264 return -1;
2265 }
2266 CFNumberRef variationNumber = static_cast<CFNumberRef>(variationValue);
2267 if (!CFNumberGetValue(variationNumber, kCFNumberCGFloatType, &variationCGFloat)) {
2268 return -1;
2269 }
2270 } else {
2271 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
2272 if (!def || CFGetTypeID(def) != CFNumberGetTypeID()) {
2273 return -1;
2274 }
2275 CFNumberRef defNumber = static_cast<CFNumberRef>(def);
2276 if (!CFNumberGetValue(defNumber, kCFNumberCGFloatType, &variationCGFloat)) {
2277 return -1;
2278 }
2279 }
2280 coordinates[i].value = CGToScalar(variationCGFloat);
2281
2282 }
2283 return axisCount;
2284 }
2285
2286 ///////////////////////////////////////////////////////////////////////////////
2287 ///////////////////////////////////////////////////////////////////////////////
2288
onGetUPEM() const2289 int SkTypeface_Mac::onGetUPEM() const {
2290 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr));
2291 return CGFontGetUnitsPerEm(cgFont.get());
2292 }
2293
onCreateFamilyNameIterator() const2294 SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const {
2295 sk_sp<SkTypeface::LocalizedStrings> nameIter =
2296 SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this);
2297 if (!nameIter) {
2298 CFStringRef cfLanguageRaw;
2299 SkUniqueCFRef<CFStringRef> cfFamilyName(
2300 CTFontCopyLocalizedName(fFontRef.get(), kCTFontFamilyNameKey, &cfLanguageRaw));
2301 SkUniqueCFRef<CFStringRef> cfLanguage(cfLanguageRaw);
2302
2303 SkString skLanguage;
2304 SkString skFamilyName;
2305 if (cfLanguage) {
2306 CFStringToSkString(cfLanguage.get(), &skLanguage);
2307 } else {
2308 skLanguage = "und"; //undetermined
2309 }
2310 if (cfFamilyName) {
2311 CFStringToSkString(cfFamilyName.get(), &skFamilyName);
2312 }
2313
2314 nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(skFamilyName, skLanguage);
2315 }
2316 return nameIter.release();
2317 }
2318
onGetTableTags(SkFontTableTag tags[]) const2319 int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const {
2320 SkUniqueCFRef<CFArrayRef> cfArray(
2321 CTFontCopyAvailableTables(fFontRef.get(), kCTFontTableOptionNoOptions));
2322 if (!cfArray) {
2323 return 0;
2324 }
2325 int count = SkToInt(CFArrayGetCount(cfArray.get()));
2326 if (tags) {
2327 for (int i = 0; i < count; ++i) {
2328 uintptr_t fontTag = reinterpret_cast<uintptr_t>(
2329 CFArrayGetValueAtIndex(cfArray.get(), i));
2330 tags[i] = static_cast<SkFontTableTag>(fontTag);
2331 }
2332 }
2333 return count;
2334 }
2335
2336 // If, as is the case with web fonts, the CTFont data isn't available,
2337 // the CGFont data may work. While the CGFont may always provide the
2338 // right result, leave the CTFont code path to minimize disruption.
copy_table_from_font(CTFontRef ctFont,SkFontTableTag tag)2339 static SkUniqueCFRef<CFDataRef> copy_table_from_font(CTFontRef ctFont, SkFontTableTag tag) {
2340 SkUniqueCFRef<CFDataRef> data(CTFontCopyTable(ctFont, (CTFontTableTag) tag,
2341 kCTFontTableOptionNoOptions));
2342 if (!data) {
2343 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr));
2344 data.reset(CGFontCopyTableForTag(cgFont.get(), tag));
2345 }
2346 return data;
2347 }
2348
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * dstData) const2349 size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset,
2350 size_t length, void* dstData) const {
2351 SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
2352 if (!srcData) {
2353 return 0;
2354 }
2355
2356 size_t srcSize = CFDataGetLength(srcData.get());
2357 if (offset >= srcSize) {
2358 return 0;
2359 }
2360 if (length > srcSize - offset) {
2361 length = srcSize - offset;
2362 }
2363 if (dstData) {
2364 memcpy(dstData, CFDataGetBytePtr(srcData.get()) + offset, length);
2365 }
2366 return length;
2367 }
2368
onCopyTableData(SkFontTableTag tag) const2369 sk_sp<SkData> SkTypeface_Mac::onCopyTableData(SkFontTableTag tag) const {
2370 SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
2371 if (!srcData) {
2372 return nullptr;
2373 }
2374 const UInt8* data = CFDataGetBytePtr(srcData.get());
2375 CFIndex length = CFDataGetLength(srcData.get());
2376 return SkData::MakeWithProc(data, length,
2377 [](const void*, void* ctx) {
2378 CFRelease((CFDataRef)ctx);
2379 }, (void*)srcData.release());
2380 }
2381
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const2382 SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkScalerContextEffects& effects,
2383 const SkDescriptor* desc) const {
2384 return new SkScalerContext_Mac(sk_ref_sp(const_cast<SkTypeface_Mac*>(this)), effects, desc);
2385 }
2386
onFilterRec(SkScalerContextRec * rec) const2387 void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const {
2388 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
2389 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
2390 {
2391 rec->fMaskFormat = SkMask::kA8_Format;
2392 // Render the glyphs as close as possible to what was requested.
2393 // The above turns off subpixel rendering, but the user requested it.
2394 // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks.
2395 // See comments below for more details.
2396 rec->setHinting(SkFontHinting::kNormal);
2397 }
2398
2399 unsigned flagsWeDontSupport = SkScalerContext::kForceAutohinting_Flag |
2400 SkScalerContext::kLCD_BGROrder_Flag |
2401 SkScalerContext::kLCD_Vertical_Flag;
2402
2403 rec->fFlags &= ~flagsWeDontSupport;
2404
2405 const SmoothBehavior smoothBehavior = smooth_behavior();
2406
2407 // Only two levels of hinting are supported.
2408 // kNo_Hinting means avoid CoreGraphics outline dilation (smoothing).
2409 // kNormal_Hinting means CoreGraphics outline dilation (smoothing) is allowed.
2410 if (rec->getHinting() != SkFontHinting::kNone) {
2411 rec->setHinting(SkFontHinting::kNormal);
2412 }
2413 // If smoothing has no effect, don't request it.
2414 if (smoothBehavior == SmoothBehavior::none) {
2415 rec->setHinting(SkFontHinting::kNone);
2416 }
2417
2418 // FIXME: lcd smoothed un-hinted rasterization unsupported.
2419 // Tracked by http://code.google.com/p/skia/issues/detail?id=915 .
2420 // There is no current means to honor a request for unhinted lcd,
2421 // so arbitrarilly ignore the hinting request and honor lcd.
2422
2423 // Hinting and smoothing should be orthogonal, but currently they are not.
2424 // CoreGraphics has no API to influence hinting. However, its lcd smoothed
2425 // output is drawn from auto-dilated outlines (the amount of which is
2426 // determined by AppleFontSmoothing). Its regular anti-aliased output is
2427 // drawn from un-dilated outlines.
2428
2429 // The behavior of Skia is as follows:
2430 // [AA][no-hint]: generate AA using CoreGraphic's AA output.
2431 // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single
2432 // channel. This matches [LCD][yes-hint] in weight.
2433 // [LCD][no-hint]: curently unable to honor, and must pick which to respect.
2434 // Currenly side with LCD, effectively ignoring the hinting setting.
2435 // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output.
2436 if (rec->fMaskFormat == SkMask::kLCD16_Format) {
2437 if (smoothBehavior == SmoothBehavior::subpixel) {
2438 //CoreGraphics creates 555 masks for smoothed text anyway.
2439 rec->fMaskFormat = SkMask::kLCD16_Format;
2440 rec->setHinting(SkFontHinting::kNormal);
2441 } else {
2442 rec->fMaskFormat = SkMask::kA8_Format;
2443 if (smoothBehavior != SmoothBehavior::none) {
2444 rec->setHinting(SkFontHinting::kNormal);
2445 }
2446 }
2447 }
2448
2449 // CoreText provides no information as to whether a glyph will be color or not.
2450 // Fonts may mix outlines and bitmaps, so information is needed on a glyph by glyph basis.
2451 // If a font contains an 'sbix' table, consider it to be a color font, and disable lcd.
2452 if (fHasColorGlyphs) {
2453 rec->fMaskFormat = SkMask::kARGB32_Format;
2454 }
2455
2456 // Smoothing will be used if the format is either LCD or if there is hinting.
2457 // In those cases, we need to choose the proper dilation mask based on the color.
2458 if (rec->fMaskFormat == SkMask::kLCD16_Format ||
2459 (rec->fMaskFormat == SkMask::kA8_Format && rec->getHinting() != SkFontHinting::kNone)) {
2460 SkColor color = rec->getLuminanceColor();
2461 int r = SkColorGetR(color);
2462 int g = SkColorGetG(color);
2463 int b = SkColorGetB(color);
2464 // Choose whether to draw using a light-on-dark mask based on observed
2465 // color/luminance thresholds that CoreText uses.
2466 if (r >= 85 && g >= 85 && b >= 85 && r + g + b >= 2 * 255) {
2467 rec->fFlags |= SkScalerContext::kLightOnDark_Flag;
2468 }
2469 }
2470
2471 // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8.
2472 // All other masks can use regular gamma.
2473 if (SkMask::kA8_Format == rec->fMaskFormat && SkFontHinting::kNone == rec->getHinting()) {
2474 #ifndef SK_GAMMA_APPLY_TO_A8
2475 // SRGBTODO: Is this correct? Do we want contrast boost?
2476 rec->ignorePreBlend();
2477 #endif
2478 } else {
2479 #ifndef SK_IGNORE_MAC_BLENDING_MATCH_FIX
2480 SkColor color = rec->getLuminanceColor();
2481 if (smoothBehavior == SmoothBehavior::some) {
2482 // CoreGraphics smoothed text without subpixel coverage blitting goes from a gamma of
2483 // 2.0 for black foreground to a gamma of 1.0 for white foreground. Emulate this
2484 // through the mask gamma by reducing the color values to 1/2.
2485 color = SkColorSetRGB(SkColorGetR(color) * 1/2,
2486 SkColorGetG(color) * 1/2,
2487 SkColorGetB(color) * 1/2);
2488 } else if (smoothBehavior == SmoothBehavior::subpixel) {
2489 // CoreGraphics smoothed text with subpixel coverage blitting goes from a gamma of
2490 // 2.0 for black foreground to a gamma of ~1.4? for white foreground. Emulate this
2491 // through the mask gamma by reducing the color values to 3/4.
2492 color = SkColorSetRGB(SkColorGetR(color) * 3/4,
2493 SkColorGetG(color) * 3/4,
2494 SkColorGetB(color) * 3/4);
2495 }
2496 rec->setLuminanceColor(color);
2497 #endif
2498 // CoreGraphics dialates smoothed text to provide contrast.
2499 rec->setContrast(0);
2500 }
2501 }
2502
2503 /** Takes ownership of the CFStringRef. */
get_str(CFStringRef ref,SkString * str)2504 static const char* get_str(CFStringRef ref, SkString* str) {
2505 if (nullptr == ref) {
2506 return nullptr;
2507 }
2508 CFStringToSkString(ref, str);
2509 CFRelease(ref);
2510 return str->c_str();
2511 }
2512
onGetFamilyName(SkString * familyName) const2513 void SkTypeface_Mac::onGetFamilyName(SkString* familyName) const {
2514 get_str(CTFontCopyFamilyName(fFontRef.get()), familyName);
2515 }
2516
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocalStream) const2517 void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc,
2518 bool* isLocalStream) const {
2519 SkString tmpStr;
2520
2521 desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef.get()), &tmpStr));
2522 desc->setFullName(get_str(CTFontCopyFullName(fFontRef.get()), &tmpStr));
2523 desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef.get()), &tmpStr));
2524 desc->setStyle(this->fontStyle());
2525 *isLocalStream = fIsFromStream;
2526 }
2527
onCharsToGlyphs(const SkUnichar uni[],int count,SkGlyphID glyphs[]) const2528 void SkTypeface_Mac::onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const {
2529 // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points:
2530 // When a surrogate pair is detected, the glyph index used is the index of the high surrogate.
2531 // It is documented that if a mapping is unavailable, the glyph will be set to 0.
2532
2533 SkAutoSTMalloc<1024, UniChar> charStorage;
2534 const UniChar* src; // UniChar is a UTF-16 16-bit code unit.
2535 int srcCount;
2536 const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(uni);
2537 UniChar* utf16 = charStorage.reset(2 * count);
2538 src = utf16;
2539 for (int i = 0; i < count; ++i) {
2540 utf16 += SkUTF::ToUTF16(utf32[i], utf16);
2541 }
2542 srcCount = SkToInt(utf16 - src);
2543
2544 // If there are any non-bmp code points, the provided 'glyphs' storage will be inadequate.
2545 SkAutoSTMalloc<1024, uint16_t> glyphStorage;
2546 uint16_t* macGlyphs = glyphs;
2547 if (srcCount > count) {
2548 macGlyphs = glyphStorage.reset(srcCount);
2549 }
2550
2551 CTFontGetGlyphsForCharacters(fFontRef.get(), src, macGlyphs, srcCount);
2552
2553 // If there were any non-bmp, then copy and compact.
2554 // If all are bmp, 'glyphs' already contains the compact glyphs.
2555 // If some are non-bmp, copy and compact into 'glyphs'.
2556 if (srcCount > count) {
2557 SkASSERT(glyphs != macGlyphs);
2558 int extra = 0;
2559 for (int i = 0; i < count; ++i) {
2560 glyphs[i] = macGlyphs[i + extra];
2561 if (SkUTF16_IsLeadingSurrogate(src[i + extra])) {
2562 ++extra;
2563 }
2564 }
2565 } else {
2566 SkASSERT(glyphs == macGlyphs);
2567 }
2568 }
2569
onCountGlyphs() const2570 int SkTypeface_Mac::onCountGlyphs() const {
2571 return SkToInt(CTFontGetGlyphCount(fFontRef.get()));
2572 }
2573
2574 ///////////////////////////////////////////////////////////////////////////////
2575 ///////////////////////////////////////////////////////////////////////////////
2576
find_desc_str(CTFontDescriptorRef desc,CFStringRef name,SkString * value)2577 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) {
2578 SkUniqueCFRef<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name));
2579 if (!ref) {
2580 return false;
2581 }
2582 CFStringToSkString(ref.get(), value);
2583 return true;
2584 }
2585
2586 #include "include/core/SkFontMgr.h"
2587
sqr(int value)2588 static inline int sqr(int value) {
2589 SkASSERT(SkAbs32(value) < 0x7FFF); // check for overflow
2590 return value * value;
2591 }
2592
2593 // We normalize each axis (weight, width, italic) to be base-900
compute_metric(const SkFontStyle & a,const SkFontStyle & b)2594 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) {
2595 return sqr(a.weight() - b.weight()) +
2596 sqr((a.width() - b.width()) * 100) +
2597 sqr((a.slant() != b.slant()) * 900);
2598 }
2599
2600 class SkFontStyleSet_Mac : public SkFontStyleSet {
2601 public:
SkFontStyleSet_Mac(CTFontDescriptorRef desc)2602 SkFontStyleSet_Mac(CTFontDescriptorRef desc)
2603 : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, nullptr))
2604 , fCount(0)
2605 {
2606 if (!fArray) {
2607 fArray.reset(CFArrayCreate(nullptr, nullptr, 0, nullptr));
2608 }
2609 fCount = SkToInt(CFArrayGetCount(fArray.get()));
2610 }
2611
count()2612 int count() override {
2613 return fCount;
2614 }
2615
getStyle(int index,SkFontStyle * style,SkString * name)2616 void getStyle(int index, SkFontStyle* style, SkString* name) override {
2617 SkASSERT((unsigned)index < (unsigned)fCount);
2618 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
2619 if (style) {
2620 *style = fontstyle_from_descriptor(desc, false);
2621 }
2622 if (name) {
2623 if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) {
2624 name->reset();
2625 }
2626 }
2627 }
2628
createTypeface(int index)2629 SkTypeface* createTypeface(int index) override {
2630 SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray.get()));
2631 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index);
2632
2633 return create_from_desc(desc).release();
2634 }
2635
matchStyle(const SkFontStyle & pattern)2636 SkTypeface* matchStyle(const SkFontStyle& pattern) override {
2637 if (0 == fCount) {
2638 return nullptr;
2639 }
2640 return create_from_desc(findMatchingDesc(pattern)).release();
2641 }
2642
2643 private:
2644 SkUniqueCFRef<CFArrayRef> fArray;
2645 int fCount;
2646
findMatchingDesc(const SkFontStyle & pattern) const2647 CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const {
2648 int bestMetric = SK_MaxS32;
2649 CTFontDescriptorRef bestDesc = nullptr;
2650
2651 for (int i = 0; i < fCount; ++i) {
2652 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), i);
2653 int metric = compute_metric(pattern, fontstyle_from_descriptor(desc, false));
2654 if (0 == metric) {
2655 return desc;
2656 }
2657 if (metric < bestMetric) {
2658 bestMetric = metric;
2659 bestDesc = desc;
2660 }
2661 }
2662 SkASSERT(bestDesc);
2663 return bestDesc;
2664 }
2665 };
2666
2667 class SkFontMgr_Mac : public SkFontMgr {
2668 SkUniqueCFRef<CFArrayRef> fNames;
2669 int fCount;
2670
getFamilyNameAt(int index) const2671 CFStringRef getFamilyNameAt(int index) const {
2672 SkASSERT((unsigned)index < (unsigned)fCount);
2673 return (CFStringRef)CFArrayGetValueAtIndex(fNames.get(), index);
2674 }
2675
CreateSet(CFStringRef cfFamilyName)2676 static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) {
2677 SkUniqueCFRef<CFMutableDictionaryRef> cfAttr(
2678 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2679 &kCFTypeDictionaryKeyCallBacks,
2680 &kCFTypeDictionaryValueCallBacks));
2681
2682 CFDictionaryAddValue(cfAttr.get(), kCTFontFamilyNameAttribute, cfFamilyName);
2683
2684 SkUniqueCFRef<CTFontDescriptorRef> desc(
2685 CTFontDescriptorCreateWithAttributes(cfAttr.get()));
2686 return new SkFontStyleSet_Mac(desc.get());
2687 }
2688
2689 /** CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we
2690 * provide a wrapper here that will return an empty array if need be.
2691 */
CopyAvailableFontFamilyNames()2692 static SkUniqueCFRef<CFArrayRef> CopyAvailableFontFamilyNames() {
2693 #ifdef SK_BUILD_FOR_IOS
2694 return SkUniqueCFRef<CFArrayRef>(CFArrayCreate(nullptr, nullptr, 0, nullptr));
2695 #else
2696 return SkUniqueCFRef<CFArrayRef>(CTFontManagerCopyAvailableFontFamilyNames());
2697 #endif
2698 }
2699
2700 public:
SkFontMgr_Mac()2701 SkFontMgr_Mac()
2702 : fNames(CopyAvailableFontFamilyNames())
2703 , fCount(fNames ? SkToInt(CFArrayGetCount(fNames.get())) : 0) {}
2704
2705 protected:
onCountFamilies() const2706 int onCountFamilies() const override {
2707 return fCount;
2708 }
2709
onGetFamilyName(int index,SkString * familyName) const2710 void onGetFamilyName(int index, SkString* familyName) const override {
2711 if ((unsigned)index < (unsigned)fCount) {
2712 CFStringToSkString(this->getFamilyNameAt(index), familyName);
2713 } else {
2714 familyName->reset();
2715 }
2716 }
2717
onCreateStyleSet(int index) const2718 SkFontStyleSet* onCreateStyleSet(int index) const override {
2719 if ((unsigned)index >= (unsigned)fCount) {
2720 return nullptr;
2721 }
2722 return CreateSet(this->getFamilyNameAt(index));
2723 }
2724
onMatchFamily(const char familyName[]) const2725 SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
2726 if (!familyName) {
2727 return nullptr;
2728 }
2729 SkUniqueCFRef<CFStringRef> cfName = make_CFString(familyName);
2730 return CreateSet(cfName.get());
2731 }
2732
onMatchFamilyStyle(const char familyName[],const SkFontStyle & style) const2733 SkTypeface* onMatchFamilyStyle(const char familyName[],
2734 const SkFontStyle& style) const override {
2735 SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
2736 return create_from_desc(desc.get()).release();
2737 }
2738
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const2739 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
2740 const SkFontStyle& style,
2741 const char* bcp47[], int bcp47Count,
2742 SkUnichar character) const override {
2743 SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style);
2744 SkUniqueCFRef<CTFontRef> familyFont(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
2745
2746 // kCFStringEncodingUTF32 is BE unless there is a BOM.
2747 // Since there is no machine endian option, explicitly state machine endian.
2748 #ifdef SK_CPU_LENDIAN
2749 constexpr CFStringEncoding encoding = kCFStringEncodingUTF32LE;
2750 #else
2751 constexpr CFStringEncoding encoding = kCFStringEncodingUTF32BE;
2752 #endif
2753 SkUniqueCFRef<CFStringRef> string(CFStringCreateWithBytes(
2754 kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(&character), sizeof(character),
2755 encoding, false));
2756 CFRange range = CFRangeMake(0, CFStringGetLength(string.get())); // in UniChar units.
2757 SkUniqueCFRef<CTFontRef> fallbackFont(
2758 CTFontCreateForString(familyFont.get(), string.get(), range));
2759 return create_from_CTFontRef(std::move(fallbackFont), nullptr, nullptr).release();
2760 }
2761
onMatchFaceStyle(const SkTypeface * familyMember,const SkFontStyle &) const2762 SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2763 const SkFontStyle&) const override {
2764 return nullptr;
2765 }
2766
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const2767 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
2768 SkUniqueCFRef<CGDataProviderRef> pr(SkCreateDataProviderFromData(data));
2769 if (!pr) {
2770 return nullptr;
2771 }
2772 return create_from_dataProvider(std::move(pr), SkMemoryStream::Make(std::move(data)),
2773 ttcIndex);
2774 }
2775
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const2776 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
2777 int ttcIndex) const override {
2778 SkUniqueCFRef<CGDataProviderRef> pr(SkCreateDataProviderFromStream(stream->duplicate()));
2779 if (!pr) {
2780 return nullptr;
2781 }
2782 return create_from_dataProvider(std::move(pr), std::move(stream), ttcIndex);
2783 }
2784
2785 /** Creates a dictionary suitable for setting the axes on a CGFont. */
copy_axes(CGFontRef cg,const SkFontArguments & args)2786 static SkUniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, const SkFontArguments& args) {
2787 // The CGFont variation data is keyed by name, but lacks the tag.
2788 // The CTFont variation data is keyed by tag, and also has the name.
2789 // We would like to work with CTFont variations, but creating a CTFont font with
2790 // CTFont variation dictionary runs into bugs. So use the CTFont variation data
2791 // to match names to tags to create the appropriate CGFont.
2792 SkUniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr));
2793 // CTFontCopyVariationAxes returns nullptr for CGFontCreateWithDataProvider fonts with
2794 // macOS 10.10 and iOS 9 or earlier. When this happens, there is no API to provide the tag.
2795 SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct.get()));
2796 if (!ctAxes) {
2797 return nullptr;
2798 }
2799 CFIndex axisCount = CFArrayGetCount(ctAxes.get());
2800
2801 const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
2802
2803 SkUniqueCFRef<CFMutableDictionaryRef> dict(
2804 CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
2805 &kCFTypeDictionaryKeyCallBacks,
2806 &kCFTypeDictionaryValueCallBacks));
2807
2808 for (int i = 0; i < axisCount; ++i) {
2809 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
2810 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
2811 return nullptr;
2812 }
2813 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
2814
2815 // The assumption is that values produced by kCTFontVariationAxisNameKey and
2816 // kCGFontVariationAxisName will always be equal.
2817 // If they are ever not, seach the project history for "get_tag_for_name".
2818 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey);
2819 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
2820 return nullptr;
2821 }
2822
2823 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
2824 if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
2825 return nullptr;
2826 }
2827 CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
2828 int64_t tagLong;
2829 if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
2830 return nullptr;
2831 }
2832
2833 // The variation axes can be set to any value, but cg will effectively pin them.
2834 // Pin them here to normalize.
2835 CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
2836 CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
2837 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
2838 if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
2839 !max || CFGetTypeID(max) != CFNumberGetTypeID() ||
2840 !def || CFGetTypeID(def) != CFNumberGetTypeID())
2841 {
2842 return nullptr;
2843 }
2844 CFNumberRef minNumber = static_cast<CFNumberRef>(min);
2845 CFNumberRef maxNumber = static_cast<CFNumberRef>(max);
2846 CFNumberRef defNumber = static_cast<CFNumberRef>(def);
2847 double minDouble;
2848 double maxDouble;
2849 double defDouble;
2850 if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) ||
2851 !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble) ||
2852 !CFNumberGetValue(defNumber, kCFNumberDoubleType, &defDouble))
2853 {
2854 return nullptr;
2855 }
2856
2857 double value = defDouble;
2858 // The position may be over specified. If there are multiple values for a given axis,
2859 // use the last one since that's what css-fonts-4 requires.
2860 for (int j = position.coordinateCount; j --> 0;) {
2861 if (position.coordinates[j].axis == tagLong) {
2862 value = SkTPin(SkScalarToDouble(position.coordinates[j].value),
2863 minDouble, maxDouble);
2864 break;
2865 }
2866 }
2867 SkUniqueCFRef<CFNumberRef> valueNumber(
2868 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
2869 CFDictionaryAddValue(dict.get(), axisName, valueNumber.get());
2870 }
2871 return dict;
2872 }
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> s,const SkFontArguments & args) const2873 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> s,
2874 const SkFontArguments& args) const override {
2875 if (args.getCollectionIndex() != 0) {
2876 return nullptr;
2877 }
2878 SkUniqueCFRef<CGDataProviderRef> provider(SkCreateDataProviderFromStream(s->duplicate()));
2879 if (!provider) {
2880 return nullptr;
2881 }
2882 SkUniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
2883 if (!cg) {
2884 return nullptr;
2885 }
2886
2887 SkUniqueCFRef<CFDictionaryRef> cgVariations = copy_axes(cg.get(), args);
2888 // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was
2889 // created from a data provider does not appear to have any ownership of the underlying
2890 // data. The original CGFontRef must be kept alive until the copy will no longer be used.
2891 SkUniqueCFRef<CGFontRef> cgVariant;
2892 if (cgVariations) {
2893 cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.get()));
2894 } else {
2895 cgVariant.reset(cg.release());
2896 }
2897
2898 SkUniqueCFRef<CTFontRef> ct(
2899 CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, nullptr));
2900 if (!ct) {
2901 return nullptr;
2902 }
2903 return create_from_CTFontRef(std::move(ct), std::move(cg), std::move(s));
2904 }
2905
2906 /** Creates a dictionary suitable for setting the axes on a CGFont. */
copy_axes(CGFontRef cg,SkFontData * fontData)2907 static SkUniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, SkFontData* fontData) {
2908 SkUniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg));
2909 if (!cgAxes) {
2910 return nullptr;
2911 }
2912
2913 CFIndex axisCount = CFArrayGetCount(cgAxes.get());
2914 if (0 == axisCount || axisCount != fontData->getAxisCount()) {
2915 return nullptr;
2916 }
2917
2918 SkUniqueCFRef<CFMutableDictionaryRef> dict(
2919 CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
2920 &kCFTypeDictionaryKeyCallBacks,
2921 &kCFTypeDictionaryValueCallBacks));
2922
2923 for (int i = 0; i < fontData->getAxisCount(); ++i) {
2924 CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes.get(), i);
2925 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
2926 return nullptr;
2927 }
2928 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
2929
2930 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisName);
2931 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
2932 return nullptr;
2933 }
2934
2935 // The variation axes can be set to any value, but cg will effectively pin them.
2936 // Pin them here to normalize.
2937 CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMinValue);
2938 CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMaxValue);
2939 if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
2940 !max || CFGetTypeID(max) != CFNumberGetTypeID())
2941 {
2942 return nullptr;
2943 }
2944 CFNumberRef minNumber = static_cast<CFNumberRef>(min);
2945 CFNumberRef maxNumber = static_cast<CFNumberRef>(max);
2946 double minDouble;
2947 double maxDouble;
2948 if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) ||
2949 !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble))
2950 {
2951 return nullptr;
2952 }
2953 double value = SkTPin(SkFixedToDouble(fontData->getAxis()[i]), minDouble, maxDouble);
2954 SkUniqueCFRef<CFNumberRef> valueNumber(
2955 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
2956 CFDictionaryAddValue(dict.get(), axisName, valueNumber.get());
2957 }
2958 return dict;
2959 }
onMakeFromFontData(std::unique_ptr<SkFontData> fontData) const2960 sk_sp<SkTypeface> onMakeFromFontData(std::unique_ptr<SkFontData> fontData) const override {
2961 if (fontData->getIndex() != 0) {
2962 return nullptr;
2963 }
2964 SkUniqueCFRef<CGDataProviderRef> provider(
2965 SkCreateDataProviderFromStream(fontData->getStream()->duplicate()));
2966 if (!provider) {
2967 return nullptr;
2968 }
2969 SkUniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
2970 if (!cg) {
2971 return nullptr;
2972 }
2973
2974 SkUniqueCFRef<CFDictionaryRef> cgVariations = copy_axes(cg.get(), fontData.get());
2975 // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was
2976 // created from a data provider does not appear to have any ownership of the underlying
2977 // data. The original CGFontRef must be kept alive until the copy will no longer be used.
2978 SkUniqueCFRef<CGFontRef> cgVariant;
2979 if (cgVariations) {
2980 cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.get()));
2981 } else {
2982 cgVariant.reset(cg.release());
2983 }
2984
2985 SkUniqueCFRef<CTFontRef> ct(
2986 CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, nullptr));
2987 if (!ct) {
2988 return nullptr;
2989 }
2990 return create_from_CTFontRef(std::move(ct), std::move(cg), fontData->detachStream());
2991 }
2992
onMakeFromFile(const char path[],int ttcIndex) const2993 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
2994 SkUniqueCFRef<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path));
2995 if (!pr) {
2996 return nullptr;
2997 }
2998 return create_from_dataProvider(std::move(pr), SkFILEStream::Make(path), ttcIndex);
2999 }
3000
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const3001 sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
3002 if (familyName) {
3003 familyName = map_css_names(familyName);
3004 }
3005
3006 sk_sp<SkTypeface> face = create_from_name(familyName, style);
3007 if (face) {
3008 return face;
3009 }
3010
3011 static SkTypeface* gDefaultFace;
3012 static SkOnce lookupDefault;
3013 static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
3014 lookupDefault([]{
3015 gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle()).release();
3016 });
3017 return sk_ref_sp(gDefaultFace);
3018 }
3019 };
3020
3021 ///////////////////////////////////////////////////////////////////////////////
3022
Factory()3023 sk_sp<SkFontMgr> SkFontMgr::Factory() { return sk_make_sp<SkFontMgr_Mac>(); }
3024
3025 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
3026