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