1 /*
2 * Copyright 2006-2012 The Android Open Source Project
3 * Copyright 2012 Mozilla Foundation
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkDrawable.h"
13 #include "include/core/SkPath.h"
14 #include "include/core/SkPictureRecorder.h"
15 #include "include/effects/SkGradientShader.h"
16 #include "include/pathops/SkPathOps.h"
17 #include "include/private/SkColorData.h"
18 #include "include/private/SkTo.h"
19 #include "src/core/SkFDot6.h"
20 #include "src/ports/SkFontHost_FreeType_common.h"
21
22 #include <utility>
23
24 #include <ft2build.h>
25 #include <freetype/freetype.h>
26 #include <freetype/ftbitmap.h>
27 #ifdef FT_COLOR_H
28 # include <freetype/ftcolor.h>
29 #endif
30 #include <freetype/ftimage.h>
31 #include <freetype/ftoutln.h>
32 #include <freetype/ftsizes.h>
33 // In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
34 #include <freetype/ftsynth.h>
35
36 #ifdef TT_SUPPORT_COLRV1
37 // FT_ClipBox and FT_Get_Color_Glyph_ClipBox introduced VER-2-11-0-18-g47cf8ebf4
38 // FT_COLR_COMPOSITE_PLUS and renumbering introduced VER-2-11-0-21-ge40ae7569
39 // FT_SIZEOF_LONG_LONG introduced VER-2-11-0-31-gffdac8d67
40 // FT_PaintRadialGradient changed size and layout at VER-2-11-0-147-gd3d3ff76d
41 // FT_STATIC_CAST introduced VER-2-11-0-172-g9079c5d91
42 // So undefine TT_SUPPORT_COLRV1 before 2.11.1 but not if FT_STATIC_CAST is defined.
43 #if (((FREETYPE_MAJOR) < 2) || \
44 ((FREETYPE_MAJOR) == 2 && (FREETYPE_MINOR) < 11) || \
45 ((FREETYPE_MAJOR) == 2 && (FREETYPE_MINOR) == 11 && (FREETYPE_PATCH) < 1)) && \
46 !defined(FT_STATIC_CAST)
47 # undef TT_SUPPORT_COLRV1
48 #else
49 # include "src/core/SkScopeExit.h"
50 #endif
51 #endif
52
53 // FT_OUTLINE_OVERLAP was added in FreeType 2.10.3
54 #ifndef FT_OUTLINE_OVERLAP
55 # define FT_OUTLINE_OVERLAP 0x40
56 #endif
57
58 // FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
59 // were introduced in FreeType 2.5.0.
60 // The following may be removed once FreeType 2.5.0 is required to build.
61 #ifndef FT_LOAD_COLOR
62 # define FT_LOAD_COLOR ( 1L << 20 )
63 # define FT_PIXEL_MODE_BGRA 7
64 #endif
65
66 #ifdef SK_DEBUG
SkTraceFtrGetError(int e)67 const char* SkTraceFtrGetError(int e) {
68 switch ((FT_Error)e) {
69 #undef FTERRORS_H_
70 #define FT_ERRORDEF( e, v, s ) case v: return s;
71 #define FT_ERROR_START_LIST
72 #define FT_ERROR_END_LIST
73 #include FT_ERRORS_H
74 #undef FT_ERRORDEF
75 #undef FT_ERROR_START_LIST
76 #undef FT_ERROR_END_LIST
77 default: return "";
78 }
79 }
80 #endif // SK_DEBUG
81
82 #ifdef TT_SUPPORT_COLRV1
operator ==(const FT_OpaquePaint & a,const FT_OpaquePaint & b)83 bool operator==(const FT_OpaquePaint& a, const FT_OpaquePaint& b) {
84 return a.p == b.p && a.insert_root_transform == b.insert_root_transform;
85 }
86 #endif
87
88 namespace {
89
compute_pixel_mode(SkMask::Format format)90 FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
91 switch (format) {
92 case SkMask::kBW_Format:
93 return FT_PIXEL_MODE_MONO;
94 case SkMask::kA8_Format:
95 default:
96 return FT_PIXEL_MODE_GRAY;
97 }
98 }
99
100 ///////////////////////////////////////////////////////////////////////////////
101
packTriple(U8CPU r,U8CPU g,U8CPU b)102 uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) {
103 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
104 r = std::max(r, (U8CPU)0x40);
105 g = std::max(g, (U8CPU)0x40);
106 b = std::max(b, (U8CPU)0x40);
107 #endif
108 return SkPack888ToRGB16(r, g, b);
109 }
110
grayToRGB16(U8CPU gray)111 uint16_t grayToRGB16(U8CPU gray) {
112 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
113 gray = std::max(gray, (U8CPU)0x40);
114 #endif
115 return SkPack888ToRGB16(gray, gray, gray);
116 }
117
bittst(const uint8_t data[],int bitOffset)118 int bittst(const uint8_t data[], int bitOffset) {
119 SkASSERT(bitOffset >= 0);
120 int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7);
121 return lowBit & 1;
122 }
123
124 /**
125 * Copies a FT_Bitmap into an SkMask with the same dimensions.
126 *
127 * FT_PIXEL_MODE_MONO
128 * FT_PIXEL_MODE_GRAY
129 * FT_PIXEL_MODE_LCD
130 * FT_PIXEL_MODE_LCD_V
131 */
132 template<bool APPLY_PREBLEND>
copyFT2LCD16(const FT_Bitmap & bitmap,const SkMask & mask,int lcdIsBGR,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)133 void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR,
134 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB)
135 {
136 SkASSERT(SkMask::kLCD16_Format == mask.fFormat);
137 if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) {
138 SkASSERT(mask.fBounds.width() == static_cast<int>(bitmap.width));
139 }
140 if (FT_PIXEL_MODE_LCD_V != bitmap.pixel_mode) {
141 SkASSERT(mask.fBounds.height() == static_cast<int>(bitmap.rows));
142 }
143
144 const uint8_t* src = bitmap.buffer;
145 uint16_t* dst = reinterpret_cast<uint16_t*>(mask.fImage);
146 const size_t dstRB = mask.fRowBytes;
147
148 const int width = mask.fBounds.width();
149 const int height = mask.fBounds.height();
150
151 switch (bitmap.pixel_mode) {
152 case FT_PIXEL_MODE_MONO:
153 for (int y = height; y --> 0;) {
154 for (int x = 0; x < width; ++x) {
155 dst[x] = -bittst(src, x);
156 }
157 dst = (uint16_t*)((char*)dst + dstRB);
158 src += bitmap.pitch;
159 }
160 break;
161 case FT_PIXEL_MODE_GRAY:
162 for (int y = height; y --> 0;) {
163 for (int x = 0; x < width; ++x) {
164 dst[x] = grayToRGB16(src[x]);
165 }
166 dst = (uint16_t*)((char*)dst + dstRB);
167 src += bitmap.pitch;
168 }
169 break;
170 case FT_PIXEL_MODE_LCD:
171 SkASSERT(3 * mask.fBounds.width() == static_cast<int>(bitmap.width));
172 for (int y = height; y --> 0;) {
173 const uint8_t* triple = src;
174 if (lcdIsBGR) {
175 for (int x = 0; x < width; x++) {
176 dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
177 sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
178 sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
179 triple += 3;
180 }
181 } else {
182 for (int x = 0; x < width; x++) {
183 dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
184 sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
185 sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
186 triple += 3;
187 }
188 }
189 src += bitmap.pitch;
190 dst = (uint16_t*)((char*)dst + dstRB);
191 }
192 break;
193 case FT_PIXEL_MODE_LCD_V:
194 SkASSERT(3 * mask.fBounds.height() == static_cast<int>(bitmap.rows));
195 for (int y = height; y --> 0;) {
196 const uint8_t* srcR = src;
197 const uint8_t* srcG = srcR + bitmap.pitch;
198 const uint8_t* srcB = srcG + bitmap.pitch;
199 if (lcdIsBGR) {
200 using std::swap;
201 swap(srcR, srcB);
202 }
203 for (int x = 0; x < width; x++) {
204 dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
205 sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
206 sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
207 }
208 src += 3 * bitmap.pitch;
209 dst = (uint16_t*)((char*)dst + dstRB);
210 }
211 break;
212 default:
213 SkDEBUGF("FT_Pixel_Mode %d", bitmap.pixel_mode);
214 SkDEBUGFAIL("unsupported FT_Pixel_Mode for LCD16");
215 break;
216 }
217 }
218
219 /**
220 * Copies a FT_Bitmap into an SkMask with the same dimensions.
221 *
222 * Yes, No, Never Requested, Never Produced
223 *
224 * kBW kA8 k3D kARGB32 kLCD16
225 * FT_PIXEL_MODE_MONO Y Y NR N Y
226 * FT_PIXEL_MODE_GRAY N Y NR N Y
227 * FT_PIXEL_MODE_GRAY2 NP NP NR NP NP
228 * FT_PIXEL_MODE_GRAY4 NP NP NR NP NP
229 * FT_PIXEL_MODE_LCD NP NP NR NP NP
230 * FT_PIXEL_MODE_LCD_V NP NP NR NP NP
231 * FT_PIXEL_MODE_BGRA N N NR Y N
232 *
233 * TODO: All of these N need to be Y or otherwise ruled out.
234 */
copyFTBitmap(const FT_Bitmap & srcFTBitmap,SkMask & dstMask)235 void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) {
236 SkASSERTF(dstMask.fBounds.width() == static_cast<int>(srcFTBitmap.width),
237 "dstMask.fBounds.width() = %d\n"
238 "static_cast<int>(srcFTBitmap.width) = %d",
239 dstMask.fBounds.width(),
240 static_cast<int>(srcFTBitmap.width)
241 );
242 SkASSERTF(dstMask.fBounds.height() == static_cast<int>(srcFTBitmap.rows),
243 "dstMask.fBounds.height() = %d\n"
244 "static_cast<int>(srcFTBitmap.rows) = %d",
245 dstMask.fBounds.height(),
246 static_cast<int>(srcFTBitmap.rows)
247 );
248
249 const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
250 const FT_Pixel_Mode srcFormat = static_cast<FT_Pixel_Mode>(srcFTBitmap.pixel_mode);
251 // FT_Bitmap::pitch is an int and allowed to be negative.
252 const int srcPitch = srcFTBitmap.pitch;
253 const size_t srcRowBytes = SkTAbs(srcPitch);
254
255 uint8_t* dst = dstMask.fImage;
256 const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat);
257 const size_t dstRowBytes = dstMask.fRowBytes;
258
259 const size_t width = srcFTBitmap.width;
260 const size_t height = srcFTBitmap.rows;
261
262 if (SkMask::kLCD16_Format == dstFormat) {
263 copyFT2LCD16<false>(srcFTBitmap, dstMask, false, nullptr, nullptr, nullptr);
264 return;
265 }
266
267 if ((FT_PIXEL_MODE_MONO == srcFormat && SkMask::kBW_Format == dstFormat) ||
268 (FT_PIXEL_MODE_GRAY == srcFormat && SkMask::kA8_Format == dstFormat))
269 {
270 size_t commonRowBytes = std::min(srcRowBytes, dstRowBytes);
271 for (size_t y = height; y --> 0;) {
272 memcpy(dst, src, commonRowBytes);
273 src += srcPitch;
274 dst += dstRowBytes;
275 }
276 } else if (FT_PIXEL_MODE_MONO == srcFormat && SkMask::kA8_Format == dstFormat) {
277 for (size_t y = height; y --> 0;) {
278 uint8_t byte = 0;
279 int bits = 0;
280 const uint8_t* src_row = src;
281 uint8_t* dst_row = dst;
282 for (size_t x = width; x --> 0;) {
283 if (0 == bits) {
284 byte = *src_row++;
285 bits = 8;
286 }
287 *dst_row++ = byte & 0x80 ? 0xff : 0x00;
288 bits--;
289 byte <<= 1;
290 }
291 src += srcPitch;
292 dst += dstRowBytes;
293 }
294 } else if (FT_PIXEL_MODE_BGRA == srcFormat && SkMask::kARGB32_Format == dstFormat) {
295 // FT_PIXEL_MODE_BGRA is pre-multiplied.
296 for (size_t y = height; y --> 0;) {
297 const uint8_t* src_row = src;
298 SkPMColor* dst_row = reinterpret_cast<SkPMColor*>(dst);
299 for (size_t x = 0; x < width; ++x) {
300 uint8_t b = *src_row++;
301 uint8_t g = *src_row++;
302 uint8_t r = *src_row++;
303 uint8_t a = *src_row++;
304 *dst_row++ = SkPackARGB32(a, r, g, b);
305 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
306 *(dst_row-1) = SkFourByteInterp256(*(dst_row-1), SK_ColorWHITE, 0x40);
307 #endif
308 }
309 src += srcPitch;
310 dst += dstRowBytes;
311 }
312 } else {
313 SkDEBUGF("FT_Pixel_Mode %d, SkMask::Format %d\n", srcFormat, dstFormat);
314 SkDEBUGFAIL("unsupported combination of FT_Pixel_Mode and SkMask::Format");
315 }
316 }
317
convert_8_to_1(unsigned byte)318 inline int convert_8_to_1(unsigned byte) {
319 SkASSERT(byte <= 0xFF);
320 // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better.
321 return (byte >> 6) != 0;
322 }
323
pack_8_to_1(const uint8_t alpha[8])324 uint8_t pack_8_to_1(const uint8_t alpha[8]) {
325 unsigned bits = 0;
326 for (int i = 0; i < 8; ++i) {
327 bits <<= 1;
328 bits |= convert_8_to_1(alpha[i]);
329 }
330 return SkToU8(bits);
331 }
332
packA8ToA1(const SkMask & mask,const uint8_t * src,size_t srcRB)333 void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
334 const int height = mask.fBounds.height();
335 const int width = mask.fBounds.width();
336 const int octs = width >> 3;
337 const int leftOverBits = width & 7;
338
339 uint8_t* dst = mask.fImage;
340 const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
341 SkASSERT(dstPad >= 0);
342
343 const int srcPad = srcRB - width;
344 SkASSERT(srcPad >= 0);
345
346 for (int y = 0; y < height; ++y) {
347 for (int i = 0; i < octs; ++i) {
348 *dst++ = pack_8_to_1(src);
349 src += 8;
350 }
351 if (leftOverBits > 0) {
352 unsigned bits = 0;
353 int shift = 7;
354 for (int i = 0; i < leftOverBits; ++i, --shift) {
355 bits |= convert_8_to_1(*src++) << shift;
356 }
357 *dst++ = bits;
358 }
359 src += srcPad;
360 dst += dstPad;
361 }
362 }
363
SkMaskFormat_for_SkColorType(SkColorType colorType)364 inline SkMask::Format SkMaskFormat_for_SkColorType(SkColorType colorType) {
365 switch (colorType) {
366 case kAlpha_8_SkColorType:
367 return SkMask::kA8_Format;
368 case kN32_SkColorType:
369 return SkMask::kARGB32_Format;
370 default:
371 SkDEBUGFAIL("unsupported SkBitmap::Config");
372 return SkMask::kA8_Format;
373 }
374 }
375
SkColorType_for_FTPixelMode(FT_Pixel_Mode pixel_mode)376 inline SkColorType SkColorType_for_FTPixelMode(FT_Pixel_Mode pixel_mode) {
377 switch (pixel_mode) {
378 case FT_PIXEL_MODE_MONO:
379 case FT_PIXEL_MODE_GRAY:
380 return kAlpha_8_SkColorType;
381 case FT_PIXEL_MODE_BGRA:
382 return kN32_SkColorType;
383 default:
384 SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
385 return kAlpha_8_SkColorType;
386 }
387 }
388
SkColorType_for_SkMaskFormat(SkMask::Format format)389 inline SkColorType SkColorType_for_SkMaskFormat(SkMask::Format format) {
390 switch (format) {
391 case SkMask::kBW_Format:
392 case SkMask::kA8_Format:
393 case SkMask::kLCD16_Format:
394 return kAlpha_8_SkColorType;
395 case SkMask::kARGB32_Format:
396 return kN32_SkColorType;
397 default:
398 SkDEBUGFAIL("unsupported destination SkBitmap::Config");
399 return kAlpha_8_SkColorType;
400 }
401 }
402
403 // Only build COLRv1 rendering code if FreeType is new enough to have COLRv1
404 // additions. FreeType defines a macro in the ftoption header to tell us whether
405 // it does support these features.
406 #ifdef TT_SUPPORT_COLRV1
407
408 const uint16_t kForegroundColorPaletteIndex = 0xFFFF;
409
410 struct OpaquePaintHasher {
operator ()__anona2dd20a10111::OpaquePaintHasher411 size_t operator()(const FT_OpaquePaint& opaque_paint) {
412 return SkGoodHash()(opaque_paint.p) ^
413 SkGoodHash()(opaque_paint.insert_root_transform);
414 }
415 };
416
417 using VisitedSet = SkTHashSet<FT_OpaquePaint, OpaquePaintHasher>;
418
419 bool generateFacePathCOLRv1(FT_Face face, SkGlyphID glyphID, SkPath* path);
420
SkColrV1AlphaToFloat(uint16_t alpha)421 inline float SkColrV1AlphaToFloat(uint16_t alpha) { return (alpha / float(1 << 14)); }
422
423
ToSkTileMode(FT_PaintExtend extend_mode)424 inline SkTileMode ToSkTileMode(FT_PaintExtend extend_mode) {
425 switch (extend_mode) {
426 case FT_COLR_PAINT_EXTEND_REPEAT:
427 return SkTileMode::kRepeat;
428 case FT_COLR_PAINT_EXTEND_REFLECT:
429 return SkTileMode::kMirror;
430 default:
431 return SkTileMode::kClamp;
432 }
433 }
434
ToSkBlendMode(FT_Composite_Mode composite)435 inline SkBlendMode ToSkBlendMode(FT_Composite_Mode composite) {
436 switch (composite) {
437 case FT_COLR_COMPOSITE_CLEAR:
438 return SkBlendMode::kClear;
439 case FT_COLR_COMPOSITE_SRC:
440 return SkBlendMode::kSrc;
441 case FT_COLR_COMPOSITE_DEST:
442 return SkBlendMode::kDst;
443 case FT_COLR_COMPOSITE_SRC_OVER:
444 return SkBlendMode::kSrcOver;
445 case FT_COLR_COMPOSITE_DEST_OVER:
446 return SkBlendMode::kDstOver;
447 case FT_COLR_COMPOSITE_SRC_IN:
448 return SkBlendMode::kSrcIn;
449 case FT_COLR_COMPOSITE_DEST_IN:
450 return SkBlendMode::kDstIn;
451 case FT_COLR_COMPOSITE_SRC_OUT:
452 return SkBlendMode::kSrcOut;
453 case FT_COLR_COMPOSITE_DEST_OUT:
454 return SkBlendMode::kDstOut;
455 case FT_COLR_COMPOSITE_SRC_ATOP:
456 return SkBlendMode::kSrcATop;
457 case FT_COLR_COMPOSITE_DEST_ATOP:
458 return SkBlendMode::kDstATop;
459 case FT_COLR_COMPOSITE_XOR:
460 return SkBlendMode::kXor;
461 case FT_COLR_COMPOSITE_PLUS:
462 return SkBlendMode::kPlus;
463 case FT_COLR_COMPOSITE_SCREEN:
464 return SkBlendMode::kScreen;
465 case FT_COLR_COMPOSITE_OVERLAY:
466 return SkBlendMode::kOverlay;
467 case FT_COLR_COMPOSITE_DARKEN:
468 return SkBlendMode::kDarken;
469 case FT_COLR_COMPOSITE_LIGHTEN:
470 return SkBlendMode::kLighten;
471 case FT_COLR_COMPOSITE_COLOR_DODGE:
472 return SkBlendMode::kColorDodge;
473 case FT_COLR_COMPOSITE_COLOR_BURN:
474 return SkBlendMode::kColorBurn;
475 case FT_COLR_COMPOSITE_HARD_LIGHT:
476 return SkBlendMode::kHardLight;
477 case FT_COLR_COMPOSITE_SOFT_LIGHT:
478 return SkBlendMode::kSoftLight;
479 case FT_COLR_COMPOSITE_DIFFERENCE:
480 return SkBlendMode::kDifference;
481 case FT_COLR_COMPOSITE_EXCLUSION:
482 return SkBlendMode::kExclusion;
483 case FT_COLR_COMPOSITE_MULTIPLY:
484 return SkBlendMode::kMultiply;
485 case FT_COLR_COMPOSITE_HSL_HUE:
486 return SkBlendMode::kHue;
487 case FT_COLR_COMPOSITE_HSL_SATURATION:
488 return SkBlendMode::kSaturation;
489 case FT_COLR_COMPOSITE_HSL_COLOR:
490 return SkBlendMode::kColor;
491 case FT_COLR_COMPOSITE_HSL_LUMINOSITY:
492 return SkBlendMode::kLuminosity;
493 default:
494 return SkBlendMode::kDst;
495 }
496 }
497
ToSkMatrix(FT_Affine23 affine23)498 inline SkMatrix ToSkMatrix(FT_Affine23 affine23) {
499 // Adjust order to convert from FreeType's FT_Affine23 column major order to SkMatrix row-major
500 // order.
501 return SkMatrix::MakeAll(
502 SkFixedToScalar(affine23.xx), -SkFixedToScalar(affine23.xy), SkFixedToScalar(affine23.dx),
503 -SkFixedToScalar(affine23.yx), SkFixedToScalar(affine23.yy), -SkFixedToScalar(affine23.dy),
504 0, 0, 1);
505 }
506
SkVectorProjection(SkPoint a,SkPoint b)507 inline SkPoint SkVectorProjection(SkPoint a, SkPoint b) {
508 SkScalar length = b.length();
509 if (!length) return SkPoint();
510 SkPoint b_normalized = b;
511 b_normalized.normalize();
512 b_normalized.scale(SkPoint::DotProduct(a, b) / length);
513 return b_normalized;
514 }
515
colrv1_configure_skpaint(FT_Face face,const SkSpan<SkColor> & palette,const SkColor foregroundColor,FT_COLR_Paint colrv1_paint,SkPaint * paint)516 bool colrv1_configure_skpaint(FT_Face face,
517 const SkSpan<SkColor>& palette,
518 const SkColor foregroundColor,
519 FT_COLR_Paint colrv1_paint,
520 SkPaint* paint) {
521 auto fetch_color_stops = [&face, &palette, &foregroundColor](
522 FT_ColorStopIterator& color_stop_iterator,
523 std::vector<SkScalar>& stops,
524 std::vector<SkColor>& colors) -> bool {
525 const FT_UInt num_color_stops = color_stop_iterator.num_color_stops;
526
527 // 5.7.11.2.4 ColorIndex, ColorStop and ColorLine
528 // "Applications shall apply the colorStops in increasing stopOffset order."
529 struct ColorStop {
530 SkScalar stop_pos;
531 SkColor color;
532 };
533 std::vector<ColorStop> sorted_stops;
534 sorted_stops.resize(num_color_stops);
535
536 FT_ColorStop color_stop;
537 while (FT_Get_Colorline_Stops(face, &color_stop, &color_stop_iterator)) {
538 FT_UInt index = color_stop_iterator.current_color_stop - 1;
539 sorted_stops[index].stop_pos = color_stop.stop_offset / float(1 << 14);
540 FT_UInt16& palette_index = color_stop.color.palette_index;
541 if (palette_index == kForegroundColorPaletteIndex) {
542 U8CPU newAlpha = SkColorGetA(foregroundColor) *
543 SkColrV1AlphaToFloat(color_stop.color.alpha);
544 sorted_stops[index].color = SkColorSetA(foregroundColor, newAlpha);
545 } else if (palette_index >= palette.size()) {
546 return false;
547 } else {
548 U8CPU newAlpha = SkColorGetA(palette[palette_index]) *
549 SkColrV1AlphaToFloat(color_stop.color.alpha);
550 sorted_stops[index].color = SkColorSetA(palette[palette_index], newAlpha);
551 }
552 }
553
554 std::stable_sort(
555 sorted_stops.begin(),
556 sorted_stops.end(),
557 [](const ColorStop& a, const ColorStop& b) { return a.stop_pos < b.stop_pos; });
558
559 stops.resize(num_color_stops);
560 colors.resize(num_color_stops);
561 for (size_t i = 0; i < num_color_stops; ++i) {
562 stops[i] = sorted_stops[i].stop_pos;
563 colors[i] = sorted_stops[i].color;
564 }
565 return true;
566 };
567
568 switch (colrv1_paint.format) {
569 case FT_COLR_PAINTFORMAT_SOLID: {
570 FT_PaintSolid solid = colrv1_paint.u.solid;
571
572 // Dont' draw anything with this color if the palette index is out of bounds.
573 SkColor color = SK_ColorTRANSPARENT;
574 if (solid.color.palette_index == kForegroundColorPaletteIndex) {
575 U8CPU newAlpha = SkColorGetA(foregroundColor) *
576 SkColrV1AlphaToFloat(solid.color.alpha);
577 color = SkColorSetA(foregroundColor, newAlpha);
578 } else if (solid.color.palette_index >= palette.size()) {
579 return false;
580 } else {
581 U8CPU newAlpha = SkColorGetA(palette[solid.color.palette_index]) *
582 SkColrV1AlphaToFloat(solid.color.alpha);
583 color = SkColorSetA(palette[solid.color.palette_index], newAlpha);
584 }
585 paint->setShader(nullptr);
586 paint->setColor(color);
587 break;
588 }
589 case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT: {
590 FT_PaintLinearGradient& linear_gradient = colrv1_paint.u.linear_gradient;
591 SkPoint line_positions[2] = {SkPoint::Make(SkFixedToScalar(linear_gradient.p0.x),
592 -SkFixedToScalar(linear_gradient.p0.y)),
593 SkPoint::Make(SkFixedToScalar(linear_gradient.p1.x),
594 -SkFixedToScalar(linear_gradient.p1.y))};
595 SkPoint p0 = line_positions[0];
596 SkPoint p1 = line_positions[1];
597 SkPoint p2 = SkPoint::Make(SkFixedToScalar(linear_gradient.p2.x),
598 -SkFixedToScalar(linear_gradient.p2.y));
599
600 // Do not draw the gradient if p0p1 is parallel to p0p2.
601 if (p1 == p0 || p2 == p0 || !SkPoint::CrossProduct(p1 - p0, p2 - p0)) break;
602
603 // Follow implementation note in nanoemoji:
604 // https://github.com/googlefonts/nanoemoji/blob/0ac6e7bb4d8202db692574d8530a9b643f1b3b3c/src/nanoemoji/svg.py#L188
605 // to compute a new gradient end point P3 as the orthogonal
606 // projection of the vector from p0 to p1 onto a line perpendicular
607 // to line p0p2 and passing through p0.
608 SkVector perpendicular_to_p2_p0 = (p2 - p0);
609 perpendicular_to_p2_p0 = SkPoint::Make(perpendicular_to_p2_p0.y(), -perpendicular_to_p2_p0.x());
610 SkVector p3 = p0 + SkVectorProjection((p1 - p0), perpendicular_to_p2_p0);
611
612 std::vector<SkScalar> stops;
613 std::vector<SkColor> colors;
614
615 if (!fetch_color_stops(linear_gradient.colorline.color_stop_iterator, stops, colors) ||
616 stops.empty()) {
617 return false;
618 }
619
620 if (stops.size() == 1) {
621 paint->setColor(colors[0]);
622 break;
623 }
624
625 // Project/scale points according to stop extrema along p0p3 line,
626 // p3 being the result of the projection above, then scale stops to
627 // to [0, 1] range so that repeat modes work. The Skia linear
628 // gradient shader performs the repeat modes over the 0 to 1 range,
629 // that's why we need to scale the stops to within that range.
630 SkVector p0p3 = p3 - p0;
631 SkVector new_p0_offset = p0p3;
632 new_p0_offset.scale(stops.front());
633 SkVector new_p1_offset = p0p3;
634 new_p1_offset.scale(stops.back());
635
636 line_positions[0] = p0 + new_p0_offset;
637 line_positions[1] = p0 + new_p1_offset;
638
639 SkScalar scale_factor = 1 / (stops.back() - stops.front());
640 SkScalar start_offset = stops.front();
641 for (SkScalar& stop : stops) {
642 stop = (stop - start_offset) * scale_factor;
643 }
644
645 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(
646 line_positions,
647 colors.data(),
648 stops.data(),
649 stops.size(),
650 ToSkTileMode(linear_gradient.colorline.extend)));
651 SkASSERT(shader);
652 // An opaque color is needed to ensure the gradient is not modulated by alpha.
653 paint->setColor(SK_ColorBLACK);
654 paint->setShader(shader);
655
656 break;
657 }
658 case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT: {
659 FT_PaintRadialGradient& radial_gradient = colrv1_paint.u.radial_gradient;
660 SkPoint start = SkPoint::Make(SkFixedToScalar(radial_gradient.c0.x),
661 -SkFixedToScalar(radial_gradient.c0.y));
662 SkScalar radius = SkFixedToScalar(radial_gradient.r0);
663 SkPoint end = SkPoint::Make(SkFixedToScalar(radial_gradient.c1.x),
664 -SkFixedToScalar(radial_gradient.c1.y));
665 SkScalar end_radius = SkFixedToScalar(radial_gradient.r1);
666
667
668 std::vector<SkScalar> stops;
669 std::vector<SkColor> colors;
670 if (!fetch_color_stops(radial_gradient.colorline.color_stop_iterator, stops, colors)) {
671 return false;
672 }
673
674 // An opaque color is needed to ensure the gradient is not modulated by alpha.
675 paint->setColor(SK_ColorBLACK);
676
677 paint->setShader(SkGradientShader::MakeTwoPointConical(
678 start, radius, end, end_radius, colors.data(), stops.data(), stops.size(),
679 ToSkTileMode(radial_gradient.colorline.extend)));
680 break;
681 }
682 case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT: {
683 FT_PaintSweepGradient& sweep_gradient = colrv1_paint.u.sweep_gradient;
684 SkPoint center = SkPoint::Make(SkFixedToScalar(sweep_gradient.center.x),
685 -SkFixedToScalar(sweep_gradient.center.y));
686 SkScalar startAngle = SkFixedToScalar(sweep_gradient.start_angle * 180.0f);
687 SkScalar endAngle = SkFixedToScalar(sweep_gradient.end_angle * 180.0f);
688
689 std::vector<SkScalar> stops;
690 std::vector<SkColor> colors;
691 if (!fetch_color_stops(sweep_gradient.colorline.color_stop_iterator, stops, colors)) {
692 return false;
693 }
694
695 // An opaque color is needed to ensure the gradient is not modulated by alpha.
696 paint->setColor(SK_ColorBLACK);
697
698 // Prepare angles to be within range for the shader.
699 auto clampAngleToRange= [](SkScalar angle) {
700 SkScalar clamped_angle = SkScalarMod(angle, 360.f);
701 if (clamped_angle < 0)
702 return clamped_angle + 360.f;
703 return clamped_angle;
704 };
705 startAngle = clampAngleToRange(startAngle);
706 endAngle = clampAngleToRange(endAngle);
707 /* TODO: Spec clarifications on which side of the gradient is to be
708 * painted, repeat modes, how to handle 0 degrees transition, see
709 * https://github.com/googlefonts/colr-gradients-spec/issues/250 */
710 if (startAngle >= endAngle)
711 endAngle += 360.f;
712
713 // Skia's angles start from the horizontal x-Axis, rotate left 90
714 // degrees and then mirror horizontally to correct for Skia angles
715 // going clockwise, COLR v1 angles going counterclockwise.
716 SkMatrix angle_adjust = SkMatrix::RotateDeg(-90.f, center);
717 angle_adjust.postScale(-1, 1, center.x(), center.y());
718
719 paint->setShader(SkGradientShader::MakeSweep(
720 center.x(), center.y(), colors.data(), stops.data(), stops.size(),
721 SkTileMode::kDecal, startAngle, endAngle, 0, &angle_adjust));
722 break;
723 }
724 default: {
725 SkASSERT(false); /* not reached */
726 }
727 }
728 return true;
729 }
730
colrv1_draw_paint(SkCanvas * canvas,const SkSpan<SkColor> & palette,const SkColor foregroundColor,FT_Face face,FT_COLR_Paint colrv1_paint)731 void colrv1_draw_paint(SkCanvas* canvas,
732 const SkSpan<SkColor>& palette,
733 const SkColor foregroundColor,
734 FT_Face face,
735 FT_COLR_Paint colrv1_paint) {
736 SkPaint paint;
737
738 switch (colrv1_paint.format) {
739 case FT_COLR_PAINTFORMAT_GLYPH: {
740 FT_UInt glyphID = colrv1_paint.u.glyph.glyphID;
741 SkPath path;
742 /* TODO: Currently this call retrieves the path at units_per_em size. If we want to get
743 * correct hinting for the scaled size under the transforms at this point in the color
744 * glyph graph, we need to extract at least the requested glyph width and height and
745 * pass that to the path generation. */
746 if (generateFacePathCOLRv1(face, glyphID, &path)) {
747
748 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
749 SkPaint highlight_paint;
750 highlight_paint.setColor(0x33FF0000);
751 canvas->drawRect(path.getBounds(), highlight_paint);
752 #endif
753 canvas->clipPath(path, true /* doAntiAlias */);
754 }
755 break;
756 }
757 case FT_COLR_PAINTFORMAT_SOLID:
758 case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT:
759 case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT:
760 case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT: {
761 SkPaint colrPaint;
762 if (colrv1_configure_skpaint(
763 face, palette, foregroundColor, colrv1_paint, &colrPaint)) {
764 canvas->drawPaint(colrPaint);
765 }
766 break;
767 }
768 case FT_COLR_PAINTFORMAT_TRANSFORM:
769 case FT_COLR_PAINTFORMAT_TRANSLATE:
770 case FT_COLR_PAINTFORMAT_SCALE:
771 case FT_COLR_PAINTFORMAT_ROTATE:
772 case FT_COLR_PAINTFORMAT_SKEW:
773 SkASSERT(false); // Transforms handled in colrv1_transform.
774 break;
775 default:
776 paint.setShader(nullptr);
777 paint.setColor(SK_ColorCYAN);
778 break;
779 }
780 }
781
colrv1_draw_glyph_with_path(SkCanvas * canvas,const SkSpan<SkColor> & palette,SkColor foregroundColor,FT_Face face,FT_COLR_Paint glyphPaint,FT_COLR_Paint fillPaint)782 void colrv1_draw_glyph_with_path(SkCanvas* canvas, const SkSpan<SkColor>& palette, SkColor foregroundColor, FT_Face face,
783 FT_COLR_Paint glyphPaint, FT_COLR_Paint fillPaint) {
784 SkASSERT(glyphPaint.format == FT_COLR_PAINTFORMAT_GLYPH);
785 SkASSERT(fillPaint.format == FT_COLR_PAINTFORMAT_SOLID ||
786 fillPaint.format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT ||
787 fillPaint.format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT ||
788 fillPaint.format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT);
789
790 SkPaint skiaFillPaint;
791 skiaFillPaint.setAntiAlias(true);
792 if (!colrv1_configure_skpaint(face, palette, foregroundColor, fillPaint, &skiaFillPaint)) {
793 return;
794 }
795
796 FT_UInt glyphID = glyphPaint.u.glyph.glyphID;
797 SkPath path;
798 /* TODO: Currently this call retrieves the path at units_per_em size. If we want to get
799 * correct hinting for the scaled size under the transforms at this point in the color
800 * glyph graph, we need to extract at least the requested glyph width and height and
801 * pass that to the path generation. */
802 if (generateFacePathCOLRv1(face, glyphID, &path)) {
803 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
804 SkPaint highlight_paint;
805 highlight_paint.setColor(0x33FF0000);
806 canvas->drawRect(path.getBounds(), highlight_paint);
807 #endif
808 {
809 canvas->drawPath(path, skiaFillPaint);
810 }
811 }
812 }
813
814
815 /* In drawing mode, concatenates the transforms directly on SkCanvas. In
816 * bounding box calculation mode, no SkCanvas is specified, but we only want to
817 * retrieve the transform from the FreeType paint object. */
colrv1_transform(FT_Face face,FT_COLR_Paint colrv1_paint,SkCanvas * canvas,SkMatrix * out_transform=nullptr)818 void colrv1_transform(FT_Face face,
819 FT_COLR_Paint colrv1_paint,
820 SkCanvas* canvas,
821 SkMatrix* out_transform = nullptr) {
822 SkMatrix transform;
823
824 SkASSERT(canvas || out_transform);
825
826 switch (colrv1_paint.format) {
827 case FT_COLR_PAINTFORMAT_TRANSFORM: {
828 transform = ToSkMatrix(colrv1_paint.u.transform.affine);
829 break;
830 }
831 case FT_COLR_PAINTFORMAT_TRANSLATE: {
832 transform = SkMatrix::Translate(
833 SkFixedToScalar(colrv1_paint.u.translate.dx),
834 -SkFixedToScalar(colrv1_paint.u.translate.dy));
835 break;
836 }
837 case FT_COLR_PAINTFORMAT_SCALE: {
838 transform.setScale(SkFixedToScalar(colrv1_paint.u.scale.scale_x),
839 SkFixedToScalar(colrv1_paint.u.scale.scale_y),
840 SkFixedToScalar(colrv1_paint.u.scale.center_x),
841 -SkFixedToScalar(colrv1_paint.u.scale.center_y));
842 break;
843 }
844 case FT_COLR_PAINTFORMAT_ROTATE: {
845 transform = SkMatrix::RotateDeg(
846 SkFixedToScalar(colrv1_paint.u.rotate.angle) * 180.0f,
847 SkPoint::Make(SkFixedToScalar(colrv1_paint.u.rotate.center_x),
848 -SkFixedToScalar(colrv1_paint.u.rotate.center_y)));
849 break;
850 }
851 case FT_COLR_PAINTFORMAT_SKEW: {
852 // In the PAINTFORMAT_ROTATE implementation, SkMatrix setRotate
853 // snaps to 0 for values very close to 0. Do the same here.
854
855 SkScalar rad_x =
856 SkDegreesToRadians(-SkFixedToFloat(colrv1_paint.u.skew.x_skew_angle) * 180.0f);
857 float tan_x = SkScalarTan(rad_x);
858 tan_x = SkScalarNearlyZero(tan_x) ? 0.0f : tan_x;
859
860 SkScalar rad_y =
861 SkDegreesToRadians(-SkFixedToFloat(colrv1_paint.u.skew.y_skew_angle) * 180.0f);
862 float tan_y = SkScalarTan(rad_y);
863 tan_y = SkScalarNearlyZero(tan_y) ? 0.0f : tan_y;
864
865 transform.setSkew(tan_x,
866 tan_y,
867 SkFixedToScalar(colrv1_paint.u.skew.center_x),
868 -SkFixedToFloat(colrv1_paint.u.skew.center_y));
869 break;
870 }
871 default: {
872 // Only transforms are handled in this function.
873 SkASSERT(false);
874 }
875 }
876 if (canvas) {
877 canvas->concat(transform);
878 }
879 if (out_transform) {
880 *out_transform = transform;
881 }
882 }
883
884 bool colrv1_start_glyph(SkCanvas* canvas,
885 const SkSpan<SkColor>& palette,
886 const SkColor foregroundColor,
887 FT_Face ft_face,
888 uint16_t glyph_id,
889 FT_Color_Root_Transform root_transform,
890 VisitedSet* visited_set);
891
colrv1_traverse_paint(SkCanvas * canvas,const SkSpan<SkColor> & palette,const SkColor foregroundColor,FT_Face face,FT_OpaquePaint opaque_paint,VisitedSet * visited_set)892 bool colrv1_traverse_paint(SkCanvas* canvas,
893 const SkSpan<SkColor>& palette,
894 const SkColor foregroundColor,
895 FT_Face face,
896 FT_OpaquePaint opaque_paint,
897 VisitedSet* visited_set) {
898 // Cycle detection, see section "5.7.11.1.9 Color glyphs as a directed acyclic graph".
899 if (visited_set->contains(opaque_paint)) {
900 return false;
901 }
902
903 visited_set->add(opaque_paint);
904 SK_AT_SCOPE_EXIT(visited_set->remove(opaque_paint));
905
906 FT_COLR_Paint paint;
907 if (!FT_Get_Paint(face, opaque_paint, &paint)) {
908 return false;
909 }
910
911 // Keep track of failures to retrieve the FT_COLR_Paint from FreeType in the
912 // recursion, cancel recursion when a paint retrieval fails.
913 bool traverse_result = true;
914 SkAutoCanvasRestore autoRestore(canvas, true /* do_save */);
915 switch (paint.format) {
916 case FT_COLR_PAINTFORMAT_COLR_LAYERS: {
917 FT_LayerIterator& layer_iterator = paint.u.colr_layers.layer_iterator;
918 FT_OpaquePaint opaque_paint_fetch;
919 opaque_paint_fetch.p = nullptr;
920 while (FT_Get_Paint_Layers(face, &layer_iterator, &opaque_paint_fetch)) {
921 colrv1_traverse_paint(canvas, palette, foregroundColor, face,
922 opaque_paint_fetch, visited_set);
923 }
924 break;
925 }
926 case FT_COLR_PAINTFORMAT_GLYPH:
927 // Special case paint graph leaf situations to improve
928 // performance. These are situations in the graph where a GlyphPaint
929 // is followed by either a solid or a gradient fill. Here we can use
930 // drawPath() + SkPaint directly which is faster than setting a
931 // clipPath() followed by a drawPaint().
932 FT_COLR_Paint fillPaint;
933 if (!FT_Get_Paint(face, paint.u.glyph.paint, &fillPaint)) {
934 return false;
935 }
936 if (fillPaint.format == FT_COLR_PAINTFORMAT_SOLID ||
937 fillPaint.format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT ||
938 fillPaint.format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT ||
939 fillPaint.format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT) {
940 colrv1_draw_glyph_with_path(canvas, palette, foregroundColor,
941 face, paint, fillPaint);
942 } else {
943 colrv1_draw_paint(canvas, palette, foregroundColor, face, paint);
944 traverse_result = colrv1_traverse_paint(canvas, palette,
945 foregroundColor, face,
946 paint.u.glyph.paint,
947 visited_set);
948 }
949 break;
950 case FT_COLR_PAINTFORMAT_COLR_GLYPH:
951 traverse_result = colrv1_start_glyph(canvas, palette, foregroundColor,
952 face, paint.u.colr_glyph.glyphID,
953 FT_COLOR_NO_ROOT_TRANSFORM,
954 visited_set);
955 break;
956 case FT_COLR_PAINTFORMAT_TRANSFORM:
957 colrv1_transform(face, paint, canvas);
958 traverse_result = colrv1_traverse_paint(canvas, palette, foregroundColor,
959 face, paint.u.transform.paint,
960 visited_set);
961 break;
962 case FT_COLR_PAINTFORMAT_TRANSLATE:
963 colrv1_transform(face, paint, canvas);
964 traverse_result = colrv1_traverse_paint(canvas, palette, foregroundColor,
965 face, paint.u.translate.paint,
966 visited_set);
967 break;
968 case FT_COLR_PAINTFORMAT_SCALE:
969 colrv1_transform(face, paint, canvas);
970 traverse_result = colrv1_traverse_paint(canvas, palette, foregroundColor,
971 face, paint.u.scale.paint,
972 visited_set);
973 break;
974 case FT_COLR_PAINTFORMAT_ROTATE:
975 colrv1_transform(face, paint, canvas);
976 traverse_result =
977 colrv1_traverse_paint(canvas, palette, foregroundColor, face,
978 paint.u.rotate.paint, visited_set);
979 break;
980 case FT_COLR_PAINTFORMAT_SKEW:
981 colrv1_transform(face, paint, canvas);
982 traverse_result =
983 colrv1_traverse_paint(canvas, palette, foregroundColor, face,
984 paint.u.skew.paint, visited_set);
985 break;
986 case FT_COLR_PAINTFORMAT_COMPOSITE: {
987 canvas->saveLayer(nullptr, nullptr);
988 traverse_result = colrv1_traverse_paint(
989 canvas, palette, foregroundColor, face,
990 paint.u.composite.backdrop_paint, visited_set);
991 SkPaint blend_mode_paint;
992 blend_mode_paint.setBlendMode(ToSkBlendMode(paint.u.composite.composite_mode));
993 canvas->saveLayer(nullptr, &blend_mode_paint);
994 traverse_result =
995 traverse_result &&
996 colrv1_traverse_paint(
997 canvas, palette, foregroundColor,
998 face, paint.u.composite.source_paint, visited_set);
999 canvas->restore();
1000 canvas->restore();
1001 break;
1002 }
1003 case FT_COLR_PAINTFORMAT_SOLID:
1004 case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT:
1005 case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT:
1006 case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT: {
1007 colrv1_draw_paint(canvas, palette, foregroundColor, face, paint);
1008 break;
1009 }
1010 default:
1011 SkASSERT(false);
1012 break;
1013 }
1014 return traverse_result;
1015 }
1016
GetClipBoxPath(FT_Face ft_face,uint16_t glyph_id,bool untransformed)1017 SkPath GetClipBoxPath(FT_Face ft_face, uint16_t glyph_id, bool untransformed) {
1018 SkPath resultPath;
1019
1020 using DoneFTSize = SkFunctionWrapper<decltype(FT_Done_Size), FT_Done_Size>;
1021 std::unique_ptr<std::remove_pointer_t<FT_Size>, DoneFTSize> unscaledFtSize = nullptr;
1022
1023 FT_Size oldSize = ft_face->size;
1024 FT_Matrix oldTransform;
1025 FT_Vector oldDelta;
1026 FT_Error err = 0;
1027
1028 if (untransformed) {
1029 unscaledFtSize.reset(
1030 [ft_face]() -> FT_Size {
1031 FT_Size size;
1032 FT_Error err = FT_New_Size(ft_face, &size);
1033 if (err != 0) {
1034 SK_TRACEFTR(err,
1035 "FT_New_Size(%s) failed in generateFacePathStaticCOLRv1.",
1036 ft_face->family_name);
1037 return nullptr;
1038 }
1039 return size;
1040 }());
1041 if (!unscaledFtSize) {
1042 return resultPath;
1043 }
1044
1045 err = FT_Activate_Size(unscaledFtSize.get());
1046 if (err != 0) {
1047 return resultPath;
1048 }
1049
1050 err = FT_Set_Char_Size(ft_face, SkIntToFDot6(ft_face->units_per_EM), 0, 0, 0);
1051 if (err != 0) {
1052 return resultPath;
1053 }
1054
1055 FT_Get_Transform(ft_face, &oldTransform, &oldDelta);
1056 FT_Set_Transform(ft_face, nullptr, nullptr);
1057 }
1058
1059 FT_ClipBox colrGlyphClipBox;
1060 if (FT_Get_Color_Glyph_ClipBox(ft_face, glyph_id, &colrGlyphClipBox)) {
1061 resultPath = SkPath::Polygon({{SkFDot6ToScalar(colrGlyphClipBox.bottom_left.x),
1062 -SkFDot6ToScalar(colrGlyphClipBox.bottom_left.y)},
1063 {SkFDot6ToScalar(colrGlyphClipBox.top_left.x),
1064 -SkFDot6ToScalar(colrGlyphClipBox.top_left.y)},
1065 {SkFDot6ToScalar(colrGlyphClipBox.top_right.x),
1066 -SkFDot6ToScalar(colrGlyphClipBox.top_right.y)},
1067 {SkFDot6ToScalar(colrGlyphClipBox.bottom_right.x),
1068 -SkFDot6ToScalar(colrGlyphClipBox.bottom_right.y)}},
1069 true);
1070 }
1071
1072 if (untransformed) {
1073 err = FT_Activate_Size(oldSize);
1074 if (err != 0) {
1075 return resultPath;
1076 }
1077 FT_Set_Transform(ft_face, &oldTransform, &oldDelta);
1078 }
1079
1080 return resultPath;
1081 }
1082
colrv1_start_glyph(SkCanvas * canvas,const SkSpan<SkColor> & palette,const SkColor foregroundColor,FT_Face ft_face,uint16_t glyph_id,FT_Color_Root_Transform root_transform,VisitedSet * visited_set)1083 bool colrv1_start_glyph(SkCanvas* canvas,
1084 const SkSpan<SkColor>& palette,
1085 const SkColor foregroundColor,
1086 FT_Face ft_face,
1087 uint16_t glyph_id,
1088 FT_Color_Root_Transform root_transform,
1089 VisitedSet* visited_set) {
1090 FT_OpaquePaint opaque_paint;
1091 opaque_paint.p = nullptr;
1092 bool has_colrv1_layers = false;
1093 if (FT_Get_Color_Glyph_Paint(ft_face, glyph_id, root_transform, &opaque_paint)) {
1094 has_colrv1_layers = true;
1095
1096 SkPath clipBoxPath =
1097 GetClipBoxPath(ft_face, glyph_id, root_transform == FT_COLOR_NO_ROOT_TRANSFORM);
1098 if (!clipBoxPath.isEmpty()) {
1099 canvas->clipPath(clipBoxPath, true);
1100 }
1101
1102 colrv1_traverse_paint(canvas, palette, foregroundColor,
1103 ft_face, opaque_paint, visited_set);
1104 }
1105 return has_colrv1_layers;
1106 }
1107
1108 bool colrv1_start_glyph_bounds(SkMatrix *ctm,
1109 SkRect* bounds,
1110 FT_Face ft_face,
1111 uint16_t glyph_id,
1112 FT_Color_Root_Transform root_transform,
1113 VisitedSet* visited_set);
1114
colrv1_traverse_paint_bounds(SkMatrix * ctm,SkRect * bounds,FT_Face face,FT_OpaquePaint opaque_paint,VisitedSet * visited_set)1115 bool colrv1_traverse_paint_bounds(SkMatrix* ctm,
1116 SkRect* bounds,
1117 FT_Face face,
1118 FT_OpaquePaint opaque_paint,
1119 VisitedSet* visited_set) {
1120 // Cycle detection, see section "5.7.11.1.9 Color glyphs as a directed acyclic graph".
1121 if (visited_set->contains(opaque_paint)) {
1122 return false;
1123 }
1124
1125 visited_set->add(opaque_paint);
1126 SK_AT_SCOPE_EXIT(visited_set->remove(opaque_paint));
1127
1128 FT_COLR_Paint paint;
1129 if (!FT_Get_Paint(face, opaque_paint, &paint)) {
1130 return false;
1131 }
1132
1133 // Keep track of failures to retrieve the FT_COLR_Paint from FreeType in the
1134 // recursion, cancel recursion when a paint retrieval fails.
1135 bool traverse_result = true;
1136 SkMatrix restore_matrix = *ctm;
1137 SK_AT_SCOPE_EXIT(*ctm = restore_matrix);
1138
1139 switch (paint.format) {
1140 case FT_COLR_PAINTFORMAT_COLR_LAYERS: {
1141 FT_LayerIterator& layer_iterator = paint.u.colr_layers.layer_iterator;
1142 FT_OpaquePaint opaque_paint_fetch;
1143 opaque_paint_fetch.p = nullptr;
1144 while (FT_Get_Paint_Layers(face, &layer_iterator, &opaque_paint_fetch)) {
1145 colrv1_traverse_paint_bounds(ctm, bounds, face, opaque_paint_fetch, visited_set);
1146 }
1147 break;
1148 }
1149 case FT_COLR_PAINTFORMAT_GLYPH: {
1150 FT_UInt glyphID = paint.u.glyph.glyphID;
1151 SkPath path;
1152 if ((traverse_result = generateFacePathCOLRv1(face, glyphID, &path))) {
1153 path.transform(*ctm);
1154 bounds->join(path.getBounds());
1155 }
1156 break;
1157 }
1158 case FT_COLR_PAINTFORMAT_COLR_GLYPH:
1159 traverse_result = colrv1_start_glyph_bounds(ctm, bounds, face,
1160 paint.u.colr_glyph.glyphID,
1161 FT_COLOR_NO_ROOT_TRANSFORM,
1162 visited_set);
1163 break;
1164
1165 case FT_COLR_PAINTFORMAT_TRANSFORM: {
1166 SkMatrix transform_matrix;
1167 colrv1_transform(face, paint, nullptr, &transform_matrix);
1168 ctm->preConcat(transform_matrix);
1169 traverse_result = colrv1_traverse_paint_bounds(
1170 ctm, bounds, face, paint.u.transform.paint, visited_set);
1171 break;
1172 }
1173 case FT_COLR_PAINTFORMAT_TRANSLATE: {
1174 SkMatrix transform_matrix;
1175 colrv1_transform(face, paint, nullptr, &transform_matrix);
1176 ctm->preConcat(transform_matrix);
1177 traverse_result = colrv1_traverse_paint_bounds(
1178 ctm, bounds, face, paint.u.translate.paint, visited_set);
1179 break;
1180 }
1181 case FT_COLR_PAINTFORMAT_SCALE: {
1182 SkMatrix transform_matrix;
1183 colrv1_transform(face, paint, nullptr, &transform_matrix);
1184 ctm->preConcat(transform_matrix);
1185 traverse_result = colrv1_traverse_paint_bounds(
1186 ctm, bounds, face, paint.u.scale.paint, visited_set);
1187 break;
1188 }
1189 case FT_COLR_PAINTFORMAT_ROTATE: {
1190 SkMatrix transform_matrix;
1191 colrv1_transform(face, paint, nullptr, &transform_matrix);
1192 ctm->preConcat(transform_matrix);
1193 traverse_result = colrv1_traverse_paint_bounds(
1194 ctm, bounds, face, paint.u.rotate.paint, visited_set);
1195 break;
1196 }
1197 case FT_COLR_PAINTFORMAT_SKEW: {
1198 SkMatrix transform_matrix;
1199 colrv1_transform(face, paint, nullptr, &transform_matrix);
1200 ctm->preConcat(transform_matrix);
1201 traverse_result = colrv1_traverse_paint_bounds(
1202 ctm, bounds, face, paint.u.skew.paint, visited_set);
1203 break;
1204 }
1205 case FT_COLR_PAINTFORMAT_COMPOSITE: {
1206 traverse_result = colrv1_traverse_paint_bounds(
1207 ctm, bounds, face, paint.u.composite.backdrop_paint, visited_set);
1208 traverse_result = colrv1_traverse_paint_bounds(
1209 ctm, bounds, face, paint.u.composite.source_paint, visited_set);
1210 break;
1211 }
1212 case FT_COLR_PAINTFORMAT_SOLID:
1213 case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT:
1214 case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT:
1215 case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT: {
1216 break;
1217 }
1218 default:
1219 SkASSERT(false);
1220 break;
1221 }
1222 return traverse_result;
1223 }
1224
1225
colrv1_start_glyph_bounds(SkMatrix * ctm,SkRect * bounds,FT_Face ft_face,uint16_t glyph_id,FT_Color_Root_Transform root_transform,VisitedSet * visited_set)1226 bool colrv1_start_glyph_bounds(SkMatrix *ctm,
1227 SkRect* bounds,
1228 FT_Face ft_face,
1229 uint16_t glyph_id,
1230 FT_Color_Root_Transform root_transform,
1231 VisitedSet* visited_set) {
1232 FT_OpaquePaint opaque_paint;
1233 opaque_paint.p = nullptr;
1234 bool has_colrv1_layers = false;
1235 if (FT_Get_Color_Glyph_Paint(ft_face, glyph_id, root_transform, &opaque_paint)) {
1236 has_colrv1_layers = true;
1237 colrv1_traverse_paint_bounds(ctm, bounds, ft_face, opaque_paint, visited_set);
1238 }
1239 return has_colrv1_layers;
1240 }
1241 #endif // TT_SUPPORT_COLRV1
1242
1243 } // namespace
1244
1245 #ifdef FT_COLOR_H
drawColorGlyph(SkCanvas * canvas,FT_Face face,SkSpan<SkColor> palette,const SkGlyph & glyph)1246 bool SkScalerContext_FreeType_Base::drawColorGlyph(SkCanvas* canvas,
1247 FT_Face face,
1248 SkSpan<SkColor> palette,
1249 const SkGlyph& glyph) {
1250 SkPaint paint;
1251 paint.setAntiAlias(true);
1252
1253 // Only attempt to draw a COLRv1 glyph if FreeType is new enough to have the COLRv1 support.
1254 #ifdef TT_SUPPORT_COLRV1
1255 VisitedSet visited_set;
1256 if (colrv1_start_glyph(canvas, palette,
1257 fRec.fForegroundColor,
1258 face, glyph.getGlyphID(),
1259 FT_COLOR_INCLUDE_ROOT_TRANSFORM,
1260 &visited_set))
1261 {
1262 return true;
1263 }
1264 #endif // TT_SUPPORT_COLRV1
1265
1266 // If we didn't have colr v1 layers, try v0 layers.
1267 bool haveLayers = false;
1268 FT_LayerIterator layerIterator;
1269 layerIterator.p = nullptr;
1270 FT_UInt layerGlyphIndex = 0;
1271 FT_UInt layerColorIndex = 0;
1272 while (FT_Get_Color_Glyph_Layer(face, glyph.getGlyphID(), &layerGlyphIndex,
1273 &layerColorIndex, &layerIterator)) {
1274 haveLayers = true;
1275 if (layerColorIndex == 0xFFFF) {
1276 paint.setColor(fRec.fForegroundColor);
1277 } else {
1278 paint.setColor(palette[layerColorIndex]);
1279 }
1280 SkPath path;
1281 if (this->generateFacePath(face, layerGlyphIndex, &path)) {
1282 canvas->drawPath(path, paint);
1283 }
1284 }
1285 return haveLayers;
1286 }
1287 #endif // FT_COLOR_H
1288
generateGlyphImage(FT_Face face,SkSpan<SkColor> customPalette,const SkGlyph & glyph,const SkMatrix & bitmapTransform)1289 void SkScalerContext_FreeType_Base::generateGlyphImage(
1290 FT_Face face,
1291 SkSpan<SkColor> customPalette,
1292 const SkGlyph& glyph,
1293 const SkMatrix& bitmapTransform)
1294 {
1295 const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
1296 const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
1297
1298 switch ( face->glyph->format ) {
1299 case FT_GLYPH_FORMAT_OUTLINE: {
1300 FT_Outline* outline = &face->glyph->outline;
1301
1302 int dx = 0, dy = 0;
1303 if (this->isSubpixel()) {
1304 dx = SkFixedToFDot6(glyph.getSubXFixed());
1305 dy = SkFixedToFDot6(glyph.getSubYFixed());
1306 // negate dy since freetype-y-goes-up and skia-y-goes-down
1307 dy = -dy;
1308 }
1309
1310 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
1311
1312 #ifdef FT_COLOR_H
1313 if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
1314 SkBitmap dstBitmap;
1315 // TODO: mark this as sRGB when the blits will be sRGB.
1316 dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
1317 kN32_SkColorType,
1318 kPremul_SkAlphaType),
1319 glyph.rowBytes());
1320 dstBitmap.setPixels(glyph.fImage);
1321
1322 // Scale unscaledBitmap into dstBitmap.
1323 SkCanvas canvas(dstBitmap);
1324 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
1325 canvas.clear(0x33FF0000);
1326 #else
1327 canvas.clear(SK_ColorTRANSPARENT);
1328 #endif
1329 canvas.translate(-glyph.fLeft, -glyph.fTop);
1330
1331 if (this->isSubpixel()) {
1332 canvas.translate(SkFixedToScalar(glyph.getSubXFixed()),
1333 SkFixedToScalar(glyph.getSubYFixed()));
1334 }
1335
1336 bool haveLayers = this->drawColorGlyph(&canvas, face, customPalette, glyph);
1337
1338 if (!haveLayers) {
1339 SkDebugf("Could not get layers (neither v0, nor v1) from %s fontFace.",
1340 face->family_name);
1341 return;
1342 }
1343 } else
1344 #endif
1345 if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
1346 FT_Outline_Translate(outline, dx, dy);
1347 FT_Error err = FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V :
1348 FT_RENDER_MODE_LCD);
1349 if (err) {
1350 SK_TRACEFTR(err, "Could not render glyph %p.", face->glyph);
1351 return;
1352 }
1353
1354 SkMask mask = glyph.mask();
1355 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
1356 memset(mask.fImage, 0x80, mask.fBounds.height() * mask.fRowBytes);
1357 #endif
1358 FT_GlyphSlotRec& ftGlyph = *face->glyph;
1359
1360 if (!SkIRect::Intersects(mask.fBounds,
1361 SkIRect::MakeXYWH( ftGlyph.bitmap_left,
1362 -ftGlyph.bitmap_top,
1363 ftGlyph.bitmap.width,
1364 ftGlyph.bitmap.rows)))
1365 {
1366 return;
1367 }
1368
1369 // If the FT_Bitmap extent is larger, discard bits of the bitmap outside the mask.
1370 // If the SkMask extent is larger, shrink mask to fit bitmap (clearing discarded).
1371 unsigned char* origBuffer = ftGlyph.bitmap.buffer;
1372 // First align the top left (origin).
1373 if (-ftGlyph.bitmap_top < mask.fBounds.fTop) {
1374 int32_t topDiff = mask.fBounds.fTop - (-ftGlyph.bitmap_top);
1375 ftGlyph.bitmap.buffer += ftGlyph.bitmap.pitch * topDiff;
1376 ftGlyph.bitmap.rows -= topDiff;
1377 ftGlyph.bitmap_top = -mask.fBounds.fTop;
1378 }
1379 if (ftGlyph.bitmap_left < mask.fBounds.fLeft) {
1380 int32_t leftDiff = mask.fBounds.fLeft - ftGlyph.bitmap_left;
1381 ftGlyph.bitmap.buffer += leftDiff;
1382 ftGlyph.bitmap.width -= leftDiff;
1383 ftGlyph.bitmap_left = mask.fBounds.fLeft;
1384 }
1385 if (mask.fBounds.fTop < -ftGlyph.bitmap_top) {
1386 mask.fImage += mask.fRowBytes * (-ftGlyph.bitmap_top - mask.fBounds.fTop);
1387 mask.fBounds.fTop = -ftGlyph.bitmap_top;
1388 }
1389 if (mask.fBounds.fLeft < ftGlyph.bitmap_left) {
1390 mask.fImage += sizeof(uint16_t) * (ftGlyph.bitmap_left - mask.fBounds.fLeft);
1391 mask.fBounds.fLeft = ftGlyph.bitmap_left;
1392 }
1393 // Origins aligned, clean up the width and height.
1394 int ftVertScale = (doVert ? 3 : 1);
1395 int ftHoriScale = (doVert ? 1 : 3);
1396 if (mask.fBounds.height() * ftVertScale < SkToInt(ftGlyph.bitmap.rows)) {
1397 ftGlyph.bitmap.rows = mask.fBounds.height() * ftVertScale;
1398 }
1399 if (mask.fBounds.width() * ftHoriScale < SkToInt(ftGlyph.bitmap.width)) {
1400 ftGlyph.bitmap.width = mask.fBounds.width() * ftHoriScale;
1401 }
1402 if (SkToInt(ftGlyph.bitmap.rows) < mask.fBounds.height() * ftVertScale) {
1403 mask.fBounds.fBottom = mask.fBounds.fTop + ftGlyph.bitmap.rows / ftVertScale;
1404 }
1405 if (SkToInt(ftGlyph.bitmap.width) < mask.fBounds.width() * ftHoriScale) {
1406 mask.fBounds.fRight = mask.fBounds.fLeft + ftGlyph.bitmap.width / ftHoriScale;
1407 }
1408 if (fPreBlend.isApplicable()) {
1409 copyFT2LCD16<true>(ftGlyph.bitmap, mask, doBGR,
1410 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1411 } else {
1412 copyFT2LCD16<false>(ftGlyph.bitmap, mask, doBGR,
1413 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1414 }
1415 // Restore the buffer pointer so FreeType can properly free it.
1416 ftGlyph.bitmap.buffer = origBuffer;
1417 } else {
1418 FT_BBox bbox;
1419 FT_Bitmap target;
1420 FT_Outline_Get_CBox(outline, &bbox);
1421 /*
1422 what we really want to do for subpixel is
1423 offset(dx, dy)
1424 compute_bounds
1425 offset(bbox & !63)
1426 but that is two calls to offset, so we do the following, which
1427 achieves the same thing with only one offset call.
1428 */
1429 FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
1430 dy - ((bbox.yMin + dy) & ~63));
1431
1432 target.width = glyph.fWidth;
1433 target.rows = glyph.fHeight;
1434 target.pitch = glyph.rowBytes();
1435 target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
1436 target.pixel_mode = compute_pixel_mode(glyph.fMaskFormat);
1437 target.num_grays = 256;
1438
1439 FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
1440 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
1441 for (int y = 0; y < glyph.fHeight; ++y) {
1442 for (int x = 0; x < glyph.fWidth; ++x) {
1443 uint8_t& a = ((uint8_t*)glyph.fImage)[(glyph.rowBytes() * y) + x];
1444 a = std::max<uint8_t>(a, 0x20);
1445 }
1446 }
1447 #endif
1448 }
1449 } break;
1450
1451 case FT_GLYPH_FORMAT_BITMAP: {
1452 FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
1453 SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1454
1455 // Assume that the other formats do not exist.
1456 SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
1457 FT_PIXEL_MODE_GRAY == pixel_mode ||
1458 FT_PIXEL_MODE_BGRA == pixel_mode);
1459
1460 // These are the only formats this ScalerContext should request.
1461 SkASSERT(SkMask::kBW_Format == maskFormat ||
1462 SkMask::kA8_Format == maskFormat ||
1463 SkMask::kARGB32_Format == maskFormat ||
1464 SkMask::kLCD16_Format == maskFormat);
1465
1466 // If no scaling needed, directly copy glyph bitmap.
1467 if (bitmapTransform.isIdentity()) {
1468 SkMask dstMask = glyph.mask();
1469 copyFTBitmap(face->glyph->bitmap, dstMask);
1470 break;
1471 }
1472
1473 // Otherwise, scale the bitmap.
1474
1475 // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
1476 SkBitmap unscaledBitmap;
1477 // TODO: mark this as sRGB when the blits will be sRGB.
1478 unscaledBitmap.allocPixels(SkImageInfo::Make(face->glyph->bitmap.width,
1479 face->glyph->bitmap.rows,
1480 SkColorType_for_FTPixelMode(pixel_mode),
1481 kPremul_SkAlphaType));
1482
1483 SkMask unscaledBitmapAlias;
1484 unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels());
1485 unscaledBitmapAlias.fBounds.setWH(unscaledBitmap.width(), unscaledBitmap.height());
1486 unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes();
1487 unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkColorType(unscaledBitmap.colorType());
1488 copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias);
1489
1490 // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
1491 // BW requires an A8 target for resizing, which can then be down sampled.
1492 // LCD should use a 4x A8 target, which will then be down sampled.
1493 // For simplicity, LCD uses A8 and is replicated.
1494 int bitmapRowBytes = 0;
1495 if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
1496 bitmapRowBytes = glyph.rowBytes();
1497 }
1498 SkBitmap dstBitmap;
1499 // TODO: mark this as sRGB when the blits will be sRGB.
1500 dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
1501 SkColorType_for_SkMaskFormat(maskFormat),
1502 kPremul_SkAlphaType),
1503 bitmapRowBytes);
1504 if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
1505 dstBitmap.allocPixels();
1506 } else {
1507 dstBitmap.setPixels(glyph.fImage);
1508 }
1509
1510 // Scale unscaledBitmap into dstBitmap.
1511 SkCanvas canvas(dstBitmap);
1512 #ifdef SK_SHOW_TEXT_BLIT_COVERAGE
1513 canvas.clear(0x33FF0000);
1514 #else
1515 canvas.clear(SK_ColorTRANSPARENT);
1516 #endif
1517 canvas.translate(-glyph.fLeft, -glyph.fTop);
1518 canvas.concat(bitmapTransform);
1519 canvas.translate(face->glyph->bitmap_left, -face->glyph->bitmap_top);
1520
1521 SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kNearest);
1522 canvas.drawImage(unscaledBitmap.asImage().get(), 0, 0, sampling, nullptr);
1523
1524 // If the destination is BW or LCD, convert from A8.
1525 if (SkMask::kBW_Format == maskFormat) {
1526 // Copy the A8 dstBitmap into the A1 glyph.fImage.
1527 SkMask dstMask = glyph.mask();
1528 packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
1529 } else if (SkMask::kLCD16_Format == maskFormat) {
1530 // Copy the A8 dstBitmap into the LCD16 glyph.fImage.
1531 uint8_t* src = dstBitmap.getAddr8(0, 0);
1532 uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
1533 for (int y = dstBitmap.height(); y --> 0;) {
1534 for (int x = 0; x < dstBitmap.width(); ++x) {
1535 dst[x] = grayToRGB16(src[x]);
1536 }
1537 dst = (uint16_t*)((char*)dst + glyph.rowBytes());
1538 src += dstBitmap.rowBytes();
1539 }
1540 }
1541
1542 } break;
1543
1544 default:
1545 SkDEBUGFAIL("unknown glyph format");
1546 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
1547 return;
1548 }
1549
1550 // We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
1551 // it is optional
1552 #if defined(SK_GAMMA_APPLY_TO_A8)
1553 if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
1554 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
1555 unsigned rowBytes = glyph.rowBytes();
1556
1557 for (int y = glyph.fHeight - 1; y >= 0; --y) {
1558 for (int x = glyph.fWidth - 1; x >= 0; --x) {
1559 dst[x] = fPreBlend.fG[dst[x]];
1560 }
1561 dst += rowBytes;
1562 }
1563 }
1564 #endif
1565 }
1566
1567 ///////////////////////////////////////////////////////////////////////////////
1568
1569 namespace {
1570
1571 class SkFTGeometrySink {
1572 SkPath* fPath;
1573 bool fStarted;
1574 FT_Vector fCurrent;
1575
goingTo(const FT_Vector * pt)1576 void goingTo(const FT_Vector* pt) {
1577 if (!fStarted) {
1578 fStarted = true;
1579 fPath->moveTo(SkFDot6ToScalar(fCurrent.x), -SkFDot6ToScalar(fCurrent.y));
1580 }
1581 fCurrent = *pt;
1582 }
1583
currentIsNot(const FT_Vector * pt)1584 bool currentIsNot(const FT_Vector* pt) {
1585 return fCurrent.x != pt->x || fCurrent.y != pt->y;
1586 }
1587
Move(const FT_Vector * pt,void * ctx)1588 static int Move(const FT_Vector* pt, void* ctx) {
1589 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
1590 if (self.fStarted) {
1591 self.fPath->close();
1592 self.fStarted = false;
1593 }
1594 self.fCurrent = *pt;
1595 return 0;
1596 }
1597
Line(const FT_Vector * pt,void * ctx)1598 static int Line(const FT_Vector* pt, void* ctx) {
1599 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
1600 if (self.currentIsNot(pt)) {
1601 self.goingTo(pt);
1602 self.fPath->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
1603 }
1604 return 0;
1605 }
1606
Quad(const FT_Vector * pt0,const FT_Vector * pt1,void * ctx)1607 static int Quad(const FT_Vector* pt0, const FT_Vector* pt1, void* ctx) {
1608 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
1609 if (self.currentIsNot(pt0) || self.currentIsNot(pt1)) {
1610 self.goingTo(pt1);
1611 self.fPath->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
1612 SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y));
1613 }
1614 return 0;
1615 }
1616
Cubic(const FT_Vector * pt0,const FT_Vector * pt1,const FT_Vector * pt2,void * ctx)1617 static int Cubic(const FT_Vector* pt0, const FT_Vector* pt1, const FT_Vector* pt2, void* ctx) {
1618 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
1619 if (self.currentIsNot(pt0) || self.currentIsNot(pt1) || self.currentIsNot(pt2)) {
1620 self.goingTo(pt2);
1621 self.fPath->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
1622 SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y),
1623 SkFDot6ToScalar(pt2->x), -SkFDot6ToScalar(pt2->y));
1624 }
1625 return 0;
1626 }
1627
1628 public:
SkFTGeometrySink(SkPath * path)1629 SkFTGeometrySink(SkPath* path) : fPath{path}, fStarted{false}, fCurrent{0,0} {}
1630
1631 inline static constexpr const FT_Outline_Funcs Funcs{
1632 /*move_to =*/ SkFTGeometrySink::Move,
1633 /*line_to =*/ SkFTGeometrySink::Line,
1634 /*conic_to =*/ SkFTGeometrySink::Quad,
1635 /*cubic_to =*/ SkFTGeometrySink::Cubic,
1636 /*shift = */ 0,
1637 /*delta =*/ 0,
1638 };
1639 };
1640
generateGlyphPathStatic(FT_Face face,SkPath * path)1641 bool generateGlyphPathStatic(FT_Face face, SkPath* path) {
1642 SkFTGeometrySink sink{path};
1643 FT_Error err = FT_Outline_Decompose(&face->glyph->outline, &SkFTGeometrySink::Funcs, &sink);
1644
1645 if (err != 0) {
1646 path->reset();
1647 return false;
1648 }
1649
1650 path->close();
1651 return true;
1652 }
1653
generateFacePathStatic(FT_Face face,SkGlyphID glyphID,SkPath * path)1654 bool generateFacePathStatic(FT_Face face, SkGlyphID glyphID, SkPath* path) {
1655 uint32_t flags = 0; //fLoadGlyphFlags;
1656 flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
1657 flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline)
1658
1659 FT_Error err = FT_Load_Glyph(face, glyphID, flags);
1660 if (err != 0) {
1661 path->reset();
1662 return false;
1663 }
1664
1665 if (!generateGlyphPathStatic(face, path)) {
1666 path->reset();
1667 return false;
1668 }
1669 return true;
1670 }
1671
1672 #ifdef TT_SUPPORT_COLRV1
generateFacePathCOLRv1(FT_Face face,SkGlyphID glyphID,SkPath * path)1673 bool generateFacePathCOLRv1(FT_Face face, SkGlyphID glyphID, SkPath* path) {
1674 uint32_t flags = 0;
1675 flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
1676 flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline)
1677
1678 flags |= FT_LOAD_IGNORE_TRANSFORM;
1679
1680
1681 using DoneFTSize = SkFunctionWrapper<decltype(FT_Done_Size), FT_Done_Size>;
1682 std::unique_ptr<std::remove_pointer_t<FT_Size>, DoneFTSize> unscaledFtSize([face]() -> FT_Size {
1683 FT_Size size;
1684 FT_Error err = FT_New_Size(face, &size);
1685 if (err != 0) {
1686 SK_TRACEFTR(err, "FT_New_Size(%s) failed in generateFacePathStaticCOLRv1.", face->family_name);
1687 return nullptr;
1688 }
1689 return size;
1690 }());
1691
1692 if (!unscaledFtSize) {
1693 return false;
1694 }
1695
1696 FT_Size oldSize = face->size;
1697
1698 auto try_generate_path = [face, &unscaledFtSize, glyphID, flags, path]() {
1699 FT_Error err = 0;
1700
1701 err = FT_Activate_Size(unscaledFtSize.get());
1702 if (err != 0) {
1703 return false;
1704 }
1705
1706 err = FT_Set_Char_Size(face, SkIntToFDot6(face->units_per_EM),
1707 SkIntToFDot6(face->units_per_EM), 72, 72);
1708 if (err != 0) {
1709 return false;
1710 }
1711
1712 err = FT_Load_Glyph(face, glyphID, flags);
1713 if (err != 0) {
1714 path->reset();
1715 return false;
1716 }
1717
1718 if (!generateGlyphPathStatic(face, path)) {
1719 path->reset();
1720 return false;
1721 }
1722
1723 return true;
1724 };
1725
1726 bool path_generation_result = try_generate_path();
1727
1728 FT_Activate_Size(oldSize);
1729
1730 return path_generation_result;
1731 }
1732 #endif
1733
1734 } // namespace
1735
generateGlyphPath(FT_Face face,SkPath * path)1736 bool SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face, SkPath* path) {
1737 if (!generateGlyphPathStatic(face, path)) {
1738 return false;
1739 }
1740 if (face->glyph->outline.flags & FT_OUTLINE_OVERLAP) {
1741 Simplify(*path, path);
1742 }
1743 return true;
1744 }
1745
generateFacePath(FT_Face face,SkGlyphID glyphID,SkPath * path)1746 bool SkScalerContext_FreeType_Base::generateFacePath(FT_Face face,
1747 SkGlyphID glyphID,
1748 SkPath* path) {
1749 return generateFacePathStatic(face, glyphID, path);
1750 }
1751
computeColrV1GlyphBoundingBox(FT_Face face,SkGlyphID glyphID,FT_BBox * boundingBox)1752 bool SkScalerContext_FreeType_Base::computeColrV1GlyphBoundingBox(FT_Face face,
1753 SkGlyphID glyphID,
1754 FT_BBox* boundingBox) {
1755 #ifdef TT_SUPPORT_COLRV1
1756 SkMatrix ctm;
1757 SkRect bounds = SkRect::MakeEmpty();
1758 VisitedSet visited_set;
1759 if (!colrv1_start_glyph_bounds(&ctm, &bounds, face, glyphID,
1760 FT_COLOR_INCLUDE_ROOT_TRANSFORM, &visited_set)) {
1761 return false;
1762 }
1763
1764 /* Convert back to FT_BBox as caller needs it in this format. */
1765 bounds.sort();
1766 boundingBox->xMin = SkScalarToFDot6(bounds.left());
1767 boundingBox->xMax = SkScalarToFDot6(bounds.right());
1768 boundingBox->yMin = SkScalarToFDot6(-bounds.bottom());
1769 boundingBox->yMax = SkScalarToFDot6(-bounds.top());
1770
1771 return true;
1772 #else
1773 SkASSERT(false);
1774 return false;
1775 #endif
1776 }
1777
generateGlyphDrawable(FT_Face face,SkSpan<SkColor> palette,const SkGlyph & glyph)1778 sk_sp<SkDrawable> SkScalerContext_FreeType_Base::generateGlyphDrawable(
1779 FT_Face face, SkSpan<SkColor> palette, const SkGlyph& glyph) {
1780 #ifdef FT_COLOR_H
1781 if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE && glyph.isColor()) {
1782 SkPictureRecorder recorder;
1783 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::Make(glyph.mask().fBounds));
1784 if (!this->drawColorGlyph(recordingCanvas, face, palette, glyph)) {
1785 return nullptr;
1786 }
1787 return recorder.finishRecordingAsDrawable();
1788 }
1789 #endif // FT_COLOR_H
1790 return nullptr;
1791 }
1792