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/SkGraphics.h"
14 #include "include/core/SkOpenTypeSVGDecoder.h"
15 #include "include/core/SkPath.h"
16 #include "include/effects/SkGradientShader.h"
17 #include "include/pathops/SkPathOps.h"
18 #include "include/private/SkColorData.h"
19 #include "include/private/base/SkTo.h"
20 #include "src/core/SkFDot6.h"
21 #include "src/core/SkSwizzlePriv.h"
22 #include "src/ports/SkFontHost_FreeType_common.h"
23
24 #include <algorithm>
25 #include <utility>
26
27 #include <ft2build.h>
28 #include <freetype/freetype.h>
29 #include <freetype/ftbitmap.h>
30 #ifdef FT_COLOR_H
31 # include <freetype/ftcolor.h>
32 #endif
33 #include <freetype/ftimage.h>
34 #include <freetype/ftoutln.h>
35 #include <freetype/ftsizes.h>
36 // In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
37 #include <freetype/ftsynth.h>
38
39 namespace {
40 [[maybe_unused]] static inline const constexpr bool kSkShowTextBlitCoverage = false;
41 }
42
43 #if defined(FT_CONFIG_OPTION_SVG)
44 # include <freetype/otsvg.h>
45 #endif
46
47 #ifdef TT_SUPPORT_COLRV1
48 // FT_ClipBox and FT_Get_Color_Glyph_ClipBox introduced VER-2-11-0-18-g47cf8ebf4
49 // FT_COLR_COMPOSITE_PLUS and renumbering introduced VER-2-11-0-21-ge40ae7569
50 // FT_SIZEOF_LONG_LONG introduced VER-2-11-0-31-gffdac8d67
51 // FT_PaintRadialGradient changed size and layout at VER-2-11-0-147-gd3d3ff76d
52 // FT_STATIC_CAST introduced VER-2-11-0-172-g9079c5d91
53 // So undefine TT_SUPPORT_COLRV1 before 2.11.1 but not if FT_STATIC_CAST is defined.
54 #if (((FREETYPE_MAJOR) < 2) || \
55 ((FREETYPE_MAJOR) == 2 && (FREETYPE_MINOR) < 11) || \
56 ((FREETYPE_MAJOR) == 2 && (FREETYPE_MINOR) == 11 && (FREETYPE_PATCH) < 1)) && \
57 !defined(FT_STATIC_CAST)
58 # undef TT_SUPPORT_COLRV1
59 #else
60 # include "src/base/SkScopeExit.h"
61 #endif
62 #endif
63
64 // FT_OUTLINE_OVERLAP was added in FreeType 2.10.3
65 #ifndef FT_OUTLINE_OVERLAP
66 # define FT_OUTLINE_OVERLAP 0x40
67 #endif
68
69 // FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
70 // were introduced in FreeType 2.5.0.
71 // The following may be removed once FreeType 2.5.0 is required to build.
72 #ifndef FT_LOAD_COLOR
73 # define FT_LOAD_COLOR ( 1L << 20 )
74 # define FT_PIXEL_MODE_BGRA 7
75 #endif
76
77 #ifdef SK_DEBUG
SkTraceFtrGetError(int e)78 const char* SkTraceFtrGetError(int e) {
79 switch ((FT_Error)e) {
80 #undef FTERRORS_H_
81 #define FT_ERRORDEF( e, v, s ) case v: return s;
82 #define FT_ERROR_START_LIST
83 #define FT_ERROR_END_LIST
84 #include FT_ERRORS_H
85 #undef FT_ERRORDEF
86 #undef FT_ERROR_START_LIST
87 #undef FT_ERROR_END_LIST
88 default: return "";
89 }
90 }
91 #endif // SK_DEBUG
92
93 #ifdef TT_SUPPORT_COLRV1
operator ==(const FT_OpaquePaint & a,const FT_OpaquePaint & b)94 bool operator==(const FT_OpaquePaint& a, const FT_OpaquePaint& b) {
95 return a.p == b.p && a.insert_root_transform == b.insert_root_transform;
96 }
97
98 // The stop_offset field is being upgraded to a larger representation in FreeType, and changed from
99 // 2.14 to 16.16. Adjust the shift factor depending on size type.
100 static_assert(sizeof(FT_Fixed) != sizeof(FT_F2Dot14));
101 constexpr float kColorStopShift =
102 sizeof(FT_ColorStop::stop_offset) == sizeof(FT_F2Dot14) ? 1 << 14 : 1 << 16;
103 #endif
104
105 namespace {
106 using SkUniqueFTSize = std::unique_ptr<FT_SizeRec, SkFunctionObject<FT_Done_Size>>;
107
compute_pixel_mode(SkMask::Format format)108 FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
109 switch (format) {
110 case SkMask::kBW_Format:
111 return FT_PIXEL_MODE_MONO;
112 case SkMask::kA8_Format:
113 default:
114 return FT_PIXEL_MODE_GRAY;
115 }
116 }
117
118 ///////////////////////////////////////////////////////////////////////////////
119
packTriple(U8CPU r,U8CPU g,U8CPU b)120 uint16_t packTriple(U8CPU r, U8CPU g, U8CPU b) {
121 if constexpr (kSkShowTextBlitCoverage) {
122 r = std::max(r, (U8CPU)0x40);
123 g = std::max(g, (U8CPU)0x40);
124 b = std::max(b, (U8CPU)0x40);
125 }
126 return SkPack888ToRGB16(r, g, b);
127 }
128
grayToRGB16(U8CPU gray)129 uint16_t grayToRGB16(U8CPU gray) {
130 if constexpr (kSkShowTextBlitCoverage) {
131 gray = std::max(gray, (U8CPU)0x40);
132 }
133 return SkPack888ToRGB16(gray, gray, gray);
134 }
135
bittst(const uint8_t data[],int bitOffset)136 int bittst(const uint8_t data[], int bitOffset) {
137 SkASSERT(bitOffset >= 0);
138 int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7);
139 return lowBit & 1;
140 }
141
142 /**
143 * Copies a FT_Bitmap into an SkMask with the same dimensions.
144 *
145 * FT_PIXEL_MODE_MONO
146 * FT_PIXEL_MODE_GRAY
147 * FT_PIXEL_MODE_LCD
148 * FT_PIXEL_MODE_LCD_V
149 */
150 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)151 void copyFT2LCD16(const FT_Bitmap& bitmap, const SkMask& mask, int lcdIsBGR,
152 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB)
153 {
154 SkASSERT(SkMask::kLCD16_Format == mask.fFormat);
155 if (FT_PIXEL_MODE_LCD != bitmap.pixel_mode) {
156 SkASSERT(mask.fBounds.width() == static_cast<int>(bitmap.width));
157 }
158 if (FT_PIXEL_MODE_LCD_V != bitmap.pixel_mode) {
159 SkASSERT(mask.fBounds.height() == static_cast<int>(bitmap.rows));
160 }
161
162 const uint8_t* src = bitmap.buffer;
163 uint16_t* dst = reinterpret_cast<uint16_t*>(mask.fImage);
164 const size_t dstRB = mask.fRowBytes;
165
166 const int width = mask.fBounds.width();
167 const int height = mask.fBounds.height();
168
169 switch (bitmap.pixel_mode) {
170 case FT_PIXEL_MODE_MONO:
171 for (int y = height; y --> 0;) {
172 for (int x = 0; x < width; ++x) {
173 dst[x] = -bittst(src, x);
174 }
175 dst = (uint16_t*)((char*)dst + dstRB);
176 src += bitmap.pitch;
177 }
178 break;
179 case FT_PIXEL_MODE_GRAY:
180 for (int y = height; y --> 0;) {
181 for (int x = 0; x < width; ++x) {
182 dst[x] = grayToRGB16(src[x]);
183 }
184 dst = (uint16_t*)((char*)dst + dstRB);
185 src += bitmap.pitch;
186 }
187 break;
188 case FT_PIXEL_MODE_LCD:
189 SkASSERT(3 * mask.fBounds.width() == static_cast<int>(bitmap.width));
190 for (int y = height; y --> 0;) {
191 const uint8_t* triple = src;
192 if (lcdIsBGR) {
193 for (int x = 0; x < width; x++) {
194 dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
195 sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
196 sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
197 triple += 3;
198 }
199 } else {
200 for (int x = 0; x < width; x++) {
201 dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
202 sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
203 sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
204 triple += 3;
205 }
206 }
207 src += bitmap.pitch;
208 dst = (uint16_t*)((char*)dst + dstRB);
209 }
210 break;
211 case FT_PIXEL_MODE_LCD_V:
212 SkASSERT(3 * mask.fBounds.height() == static_cast<int>(bitmap.rows));
213 for (int y = height; y --> 0;) {
214 const uint8_t* srcR = src;
215 const uint8_t* srcG = srcR + bitmap.pitch;
216 const uint8_t* srcB = srcG + bitmap.pitch;
217 if (lcdIsBGR) {
218 using std::swap;
219 swap(srcR, srcB);
220 }
221 for (int x = 0; x < width; x++) {
222 dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
223 sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
224 sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
225 }
226 src += 3 * bitmap.pitch;
227 dst = (uint16_t*)((char*)dst + dstRB);
228 }
229 break;
230 default:
231 SkDEBUGF("FT_Pixel_Mode %d", bitmap.pixel_mode);
232 SkDEBUGFAIL("unsupported FT_Pixel_Mode for LCD16");
233 break;
234 }
235 }
236
237 /**
238 * Copies a FT_Bitmap into an SkMask with the same dimensions.
239 *
240 * Yes, No, Never Requested, Never Produced
241 *
242 * kBW kA8 k3D kARGB32 kLCD16
243 * FT_PIXEL_MODE_MONO Y Y NR N Y
244 * FT_PIXEL_MODE_GRAY N Y NR N Y
245 * FT_PIXEL_MODE_GRAY2 NP NP NR NP NP
246 * FT_PIXEL_MODE_GRAY4 NP NP NR NP NP
247 * FT_PIXEL_MODE_LCD NP NP NR NP NP
248 * FT_PIXEL_MODE_LCD_V NP NP NR NP NP
249 * FT_PIXEL_MODE_BGRA N N NR Y N
250 *
251 * TODO: All of these N need to be Y or otherwise ruled out.
252 */
copyFTBitmap(const FT_Bitmap & srcFTBitmap,SkMask & dstMask)253 void copyFTBitmap(const FT_Bitmap& srcFTBitmap, SkMask& dstMask) {
254 SkASSERTF(dstMask.fBounds.width() == static_cast<int>(srcFTBitmap.width),
255 "dstMask.fBounds.width() = %d\n"
256 "static_cast<int>(srcFTBitmap.width) = %d",
257 dstMask.fBounds.width(),
258 static_cast<int>(srcFTBitmap.width)
259 );
260 SkASSERTF(dstMask.fBounds.height() == static_cast<int>(srcFTBitmap.rows),
261 "dstMask.fBounds.height() = %d\n"
262 "static_cast<int>(srcFTBitmap.rows) = %d",
263 dstMask.fBounds.height(),
264 static_cast<int>(srcFTBitmap.rows)
265 );
266
267 const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
268 const FT_Pixel_Mode srcFormat = static_cast<FT_Pixel_Mode>(srcFTBitmap.pixel_mode);
269 // FT_Bitmap::pitch is an int and allowed to be negative.
270 const int srcPitch = srcFTBitmap.pitch;
271 const size_t srcRowBytes = SkTAbs(srcPitch);
272
273 uint8_t* dst = dstMask.fImage;
274 const SkMask::Format dstFormat = static_cast<SkMask::Format>(dstMask.fFormat);
275 const size_t dstRowBytes = dstMask.fRowBytes;
276
277 const size_t width = srcFTBitmap.width;
278 const size_t height = srcFTBitmap.rows;
279
280 if (SkMask::kLCD16_Format == dstFormat) {
281 copyFT2LCD16<false>(srcFTBitmap, dstMask, false, nullptr, nullptr, nullptr);
282 return;
283 }
284
285 if ((FT_PIXEL_MODE_MONO == srcFormat && SkMask::kBW_Format == dstFormat) ||
286 (FT_PIXEL_MODE_GRAY == srcFormat && SkMask::kA8_Format == dstFormat))
287 {
288 size_t commonRowBytes = std::min(srcRowBytes, dstRowBytes);
289 for (size_t y = height; y --> 0;) {
290 memcpy(dst, src, commonRowBytes);
291 src += srcPitch;
292 dst += dstRowBytes;
293 }
294 } else if (FT_PIXEL_MODE_MONO == srcFormat && SkMask::kA8_Format == dstFormat) {
295 for (size_t y = height; y --> 0;) {
296 uint8_t byte = 0;
297 int bits = 0;
298 const uint8_t* src_row = src;
299 uint8_t* dst_row = dst;
300 for (size_t x = width; x --> 0;) {
301 if (0 == bits) {
302 byte = *src_row++;
303 bits = 8;
304 }
305 *dst_row++ = byte & 0x80 ? 0xff : 0x00;
306 bits--;
307 byte <<= 1;
308 }
309 src += srcPitch;
310 dst += dstRowBytes;
311 }
312 } else if (FT_PIXEL_MODE_BGRA == srcFormat && SkMask::kARGB32_Format == dstFormat) {
313 // FT_PIXEL_MODE_BGRA is pre-multiplied.
314 for (size_t y = height; y --> 0;) {
315 const uint8_t* src_row = src;
316 SkPMColor* dst_row = reinterpret_cast<SkPMColor*>(dst);
317 for (size_t x = 0; x < width; ++x) {
318 uint8_t b = *src_row++;
319 uint8_t g = *src_row++;
320 uint8_t r = *src_row++;
321 uint8_t a = *src_row++;
322 *dst_row++ = SkPackARGB32(a, r, g, b);
323 if constexpr (kSkShowTextBlitCoverage) {
324 *(dst_row-1) = SkFourByteInterp256(*(dst_row-1), SK_ColorWHITE, 0x40);
325 }
326 }
327 src += srcPitch;
328 dst += dstRowBytes;
329 }
330 } else {
331 SkDEBUGF("FT_Pixel_Mode %d, SkMask::Format %d\n", srcFormat, dstFormat);
332 SkDEBUGFAIL("unsupported combination of FT_Pixel_Mode and SkMask::Format");
333 }
334 }
335
convert_8_to_1(unsigned byte)336 inline int convert_8_to_1(unsigned byte) {
337 SkASSERT(byte <= 0xFF);
338 // Arbitrary decision that making the cutoff at 1/4 instead of 1/2 in general looks better.
339 return (byte >> 6) != 0;
340 }
341
pack_8_to_1(const uint8_t alpha[8])342 uint8_t pack_8_to_1(const uint8_t alpha[8]) {
343 unsigned bits = 0;
344 for (int i = 0; i < 8; ++i) {
345 bits <<= 1;
346 bits |= convert_8_to_1(alpha[i]);
347 }
348 return SkToU8(bits);
349 }
350
packA8ToA1(const SkMask & mask,const uint8_t * src,size_t srcRB)351 void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
352 const int height = mask.fBounds.height();
353 const int width = mask.fBounds.width();
354 const int octs = width >> 3;
355 const int leftOverBits = width & 7;
356
357 uint8_t* dst = mask.fImage;
358 const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
359 SkASSERT(dstPad >= 0);
360
361 const int srcPad = srcRB - width;
362 SkASSERT(srcPad >= 0);
363
364 for (int y = 0; y < height; ++y) {
365 for (int i = 0; i < octs; ++i) {
366 *dst++ = pack_8_to_1(src);
367 src += 8;
368 }
369 if (leftOverBits > 0) {
370 unsigned bits = 0;
371 int shift = 7;
372 for (int i = 0; i < leftOverBits; ++i, --shift) {
373 bits |= convert_8_to_1(*src++) << shift;
374 }
375 *dst++ = bits;
376 }
377 src += srcPad;
378 dst += dstPad;
379 }
380 }
381
SkMaskFormat_for_SkColorType(SkColorType colorType)382 inline SkMask::Format SkMaskFormat_for_SkColorType(SkColorType colorType) {
383 switch (colorType) {
384 case kAlpha_8_SkColorType:
385 return SkMask::kA8_Format;
386 case kN32_SkColorType:
387 return SkMask::kARGB32_Format;
388 default:
389 SkDEBUGFAIL("unsupported SkBitmap::Config");
390 return SkMask::kA8_Format;
391 }
392 }
393
SkColorType_for_FTPixelMode(FT_Pixel_Mode pixel_mode)394 inline SkColorType SkColorType_for_FTPixelMode(FT_Pixel_Mode pixel_mode) {
395 switch (pixel_mode) {
396 case FT_PIXEL_MODE_MONO:
397 case FT_PIXEL_MODE_GRAY:
398 return kAlpha_8_SkColorType;
399 case FT_PIXEL_MODE_BGRA:
400 return kN32_SkColorType;
401 default:
402 SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
403 return kAlpha_8_SkColorType;
404 }
405 }
406
SkColorType_for_SkMaskFormat(SkMask::Format format)407 inline SkColorType SkColorType_for_SkMaskFormat(SkMask::Format format) {
408 switch (format) {
409 case SkMask::kBW_Format:
410 case SkMask::kA8_Format:
411 case SkMask::kLCD16_Format:
412 return kAlpha_8_SkColorType;
413 case SkMask::kARGB32_Format:
414 return kN32_SkColorType;
415 default:
416 SkDEBUGFAIL("unsupported destination SkBitmap::Config");
417 return kAlpha_8_SkColorType;
418 }
419 }
420
421 // Only build COLRv1 rendering code if FreeType is new enough to have COLRv1
422 // additions. FreeType defines a macro in the ftoption header to tell us whether
423 // it does support these features.
424 #ifdef TT_SUPPORT_COLRV1
425
426 const uint16_t kForegroundColorPaletteIndex = 0xFFFF;
427
428 // This linear interpolation is used for calculating a truncated color line in special edge cases.
429 // This interpolation needs to be kept in sync with what the gradient shader would normally do when
430 // truncating and drawing color lines. When drawing into N32 surfaces, this is expected to be true.
431 // If that changes, or if we support other color spaces in CPAL tables at some point, this needs to
432 // be looked at.
lerpSkColor(SkColor c0,SkColor c1,float t)433 SkColor lerpSkColor(SkColor c0, SkColor c1, float t) {
434 // Due to the floating point calculation in the caller, when interpolating between very narrow
435 // stops, we may get values outside the interpolation range, guard against these.
436 if (t < 0) {
437 return c0;
438 }
439 if (t > 1) {
440 return c1;
441 }
442 const auto c0_4f = Sk4f_fromL32(c0), c1_4f = Sk4f_fromL32(c1),
443 c_4f = c0_4f + (c1_4f - c0_4f) * t;
444
445 return Sk4f_toL32(c_4f);
446 }
447
448 enum TruncateStops {
449 TruncateStart,
450 TruncateEnd
451 };
452
453 // Truncate a vector of color stops at a previously computed stop position and insert at that
454 // position the color interpolated between the surrounding stops.
truncateToStopInterpolating(SkScalar zeroRadiusStop,std::vector<SkColor> & colors,std::vector<SkScalar> & stops,TruncateStops truncateStops)455 void truncateToStopInterpolating(SkScalar zeroRadiusStop,
456 std::vector<SkColor>& colors,
457 std::vector<SkScalar>& stops,
458 TruncateStops truncateStops) {
459 if (stops.size() <= 1u ||
460 zeroRadiusStop < *stops.begin() || *(stops.end() - 1) < zeroRadiusStop)
461 {
462 return;
463 }
464
465 size_t afterIndex = (truncateStops == TruncateStart)
466 ? std::lower_bound(stops.begin(), stops.end(), zeroRadiusStop) - stops.begin()
467 : std::upper_bound(stops.begin(), stops.end(), zeroRadiusStop) - stops.begin();
468
469 const float t = (zeroRadiusStop - stops[afterIndex - 1]) /
470 (stops[afterIndex] - stops[afterIndex - 1]);
471 SkColor lerpColor = lerpSkColor(colors[afterIndex - 1], colors[afterIndex], t);
472
473 if (truncateStops == TruncateStart) {
474 stops.erase(stops.begin(), stops.begin() + afterIndex);
475 colors.erase(colors.begin(), colors.begin() + afterIndex);
476 stops.insert(stops.begin(), 0);
477 colors.insert(colors.begin(), lerpColor);
478 } else {
479 stops.erase(stops.begin() + afterIndex, stops.end());
480 colors.erase(colors.begin() + afterIndex, colors.end());
481 stops.insert(stops.end(), 1);
482 colors.insert(colors.end(), lerpColor);
483 }
484 }
485
486 struct OpaquePaintHasher {
operator ()__anon3de92cba0211::OpaquePaintHasher487 size_t operator()(const FT_OpaquePaint& opaquePaint) {
488 return SkGoodHash()(opaquePaint.p) ^
489 SkGoodHash()(opaquePaint.insert_root_transform);
490 }
491 };
492
493 using VisitedSet = SkTHashSet<FT_OpaquePaint, OpaquePaintHasher>;
494
495 bool generateFacePathCOLRv1(FT_Face face, SkGlyphID glyphID, SkPath* path);
496
SkColrV1AlphaToFloat(uint16_t alpha)497 inline float SkColrV1AlphaToFloat(uint16_t alpha) { return (alpha / float(1 << 14)); }
498
499
ToSkTileMode(FT_PaintExtend extendMode)500 inline SkTileMode ToSkTileMode(FT_PaintExtend extendMode) {
501 switch (extendMode) {
502 case FT_COLR_PAINT_EXTEND_REPEAT:
503 return SkTileMode::kRepeat;
504 case FT_COLR_PAINT_EXTEND_REFLECT:
505 return SkTileMode::kMirror;
506 default:
507 return SkTileMode::kClamp;
508 }
509 }
510
ToSkBlendMode(FT_Composite_Mode compositeMode)511 inline SkBlendMode ToSkBlendMode(FT_Composite_Mode compositeMode) {
512 switch (compositeMode) {
513 case FT_COLR_COMPOSITE_CLEAR:
514 return SkBlendMode::kClear;
515 case FT_COLR_COMPOSITE_SRC:
516 return SkBlendMode::kSrc;
517 case FT_COLR_COMPOSITE_DEST:
518 return SkBlendMode::kDst;
519 case FT_COLR_COMPOSITE_SRC_OVER:
520 return SkBlendMode::kSrcOver;
521 case FT_COLR_COMPOSITE_DEST_OVER:
522 return SkBlendMode::kDstOver;
523 case FT_COLR_COMPOSITE_SRC_IN:
524 return SkBlendMode::kSrcIn;
525 case FT_COLR_COMPOSITE_DEST_IN:
526 return SkBlendMode::kDstIn;
527 case FT_COLR_COMPOSITE_SRC_OUT:
528 return SkBlendMode::kSrcOut;
529 case FT_COLR_COMPOSITE_DEST_OUT:
530 return SkBlendMode::kDstOut;
531 case FT_COLR_COMPOSITE_SRC_ATOP:
532 return SkBlendMode::kSrcATop;
533 case FT_COLR_COMPOSITE_DEST_ATOP:
534 return SkBlendMode::kDstATop;
535 case FT_COLR_COMPOSITE_XOR:
536 return SkBlendMode::kXor;
537 case FT_COLR_COMPOSITE_PLUS:
538 return SkBlendMode::kPlus;
539 case FT_COLR_COMPOSITE_SCREEN:
540 return SkBlendMode::kScreen;
541 case FT_COLR_COMPOSITE_OVERLAY:
542 return SkBlendMode::kOverlay;
543 case FT_COLR_COMPOSITE_DARKEN:
544 return SkBlendMode::kDarken;
545 case FT_COLR_COMPOSITE_LIGHTEN:
546 return SkBlendMode::kLighten;
547 case FT_COLR_COMPOSITE_COLOR_DODGE:
548 return SkBlendMode::kColorDodge;
549 case FT_COLR_COMPOSITE_COLOR_BURN:
550 return SkBlendMode::kColorBurn;
551 case FT_COLR_COMPOSITE_HARD_LIGHT:
552 return SkBlendMode::kHardLight;
553 case FT_COLR_COMPOSITE_SOFT_LIGHT:
554 return SkBlendMode::kSoftLight;
555 case FT_COLR_COMPOSITE_DIFFERENCE:
556 return SkBlendMode::kDifference;
557 case FT_COLR_COMPOSITE_EXCLUSION:
558 return SkBlendMode::kExclusion;
559 case FT_COLR_COMPOSITE_MULTIPLY:
560 return SkBlendMode::kMultiply;
561 case FT_COLR_COMPOSITE_HSL_HUE:
562 return SkBlendMode::kHue;
563 case FT_COLR_COMPOSITE_HSL_SATURATION:
564 return SkBlendMode::kSaturation;
565 case FT_COLR_COMPOSITE_HSL_COLOR:
566 return SkBlendMode::kColor;
567 case FT_COLR_COMPOSITE_HSL_LUMINOSITY:
568 return SkBlendMode::kLuminosity;
569 default:
570 return SkBlendMode::kDst;
571 }
572 }
573
ToSkMatrix(FT_Affine23 affine23)574 inline SkMatrix ToSkMatrix(FT_Affine23 affine23) {
575 // Convert from FreeType's FT_Affine23 column major order to SkMatrix row-major order.
576 return SkMatrix::MakeAll(
577 SkFixedToScalar(affine23.xx), -SkFixedToScalar(affine23.xy), SkFixedToScalar(affine23.dx),
578 -SkFixedToScalar(affine23.yx), SkFixedToScalar(affine23.yy), -SkFixedToScalar(affine23.dy),
579 0, 0, 1);
580 }
581
SkVectorProjection(SkPoint a,SkPoint b)582 inline SkPoint SkVectorProjection(SkPoint a, SkPoint b) {
583 SkScalar length = b.length();
584 if (!length) {
585 return SkPoint();
586 }
587 SkPoint bNormalized = b;
588 bNormalized.normalize();
589 bNormalized.scale(SkPoint::DotProduct(a, b) / length);
590 return bNormalized;
591 }
592
colrv1_configure_skpaint(FT_Face face,const SkSpan<SkColor> & palette,const SkColor foregroundColor,const FT_COLR_Paint & colrPaint,SkPaint * paint)593 bool colrv1_configure_skpaint(FT_Face face,
594 const SkSpan<SkColor>& palette,
595 const SkColor foregroundColor,
596 const FT_COLR_Paint& colrPaint,
597 SkPaint* paint) {
598 auto fetchColorStops = [&face, &palette, &foregroundColor](
599 const FT_ColorStopIterator& colorStopIterator,
600 std::vector<SkScalar>& stops,
601 std::vector<SkColor>& colors) -> bool {
602 const FT_UInt colorStopCount = colorStopIterator.num_color_stops;
603 if (colorStopCount == 0) {
604 return false;
605 }
606
607 // 5.7.11.2.4 ColorIndex, ColorStop and ColorLine
608 // "Applications shall apply the colorStops in increasing stopOffset order."
609 struct ColorStop {
610 SkScalar pos;
611 SkColor color;
612 };
613 std::vector<ColorStop> colorStopsSorted;
614 colorStopsSorted.resize(colorStopCount);
615
616 FT_ColorStop color_stop;
617 FT_ColorStopIterator mutable_color_stop_iterator = colorStopIterator;
618 while (FT_Get_Colorline_Stops(face, &color_stop, &mutable_color_stop_iterator)) {
619 FT_UInt index = mutable_color_stop_iterator.current_color_stop - 1;
620 colorStopsSorted[index].pos = color_stop.stop_offset / kColorStopShift;
621 FT_UInt16& palette_index = color_stop.color.palette_index;
622 if (palette_index == kForegroundColorPaletteIndex) {
623 U8CPU newAlpha = SkColorGetA(foregroundColor) *
624 SkColrV1AlphaToFloat(color_stop.color.alpha);
625 colorStopsSorted[index].color = SkColorSetA(foregroundColor, newAlpha);
626 } else if (palette_index >= palette.size()) {
627 return false;
628 } else {
629 U8CPU newAlpha = SkColorGetA(palette[palette_index]) *
630 SkColrV1AlphaToFloat(color_stop.color.alpha);
631 colorStopsSorted[index].color = SkColorSetA(palette[palette_index], newAlpha);
632 }
633 }
634
635 std::stable_sort(colorStopsSorted.begin(), colorStopsSorted.end(),
636 [](const ColorStop& a, const ColorStop& b) { return a.pos < b.pos; });
637
638 stops.resize(colorStopCount);
639 colors.resize(colorStopCount);
640 for (size_t i = 0; i < colorStopCount; ++i) {
641 stops[i] = colorStopsSorted[i].pos;
642 colors[i] = colorStopsSorted[i].color;
643 }
644 return true;
645 };
646
647 switch (colrPaint.format) {
648 case FT_COLR_PAINTFORMAT_SOLID: {
649 FT_PaintSolid solid = colrPaint.u.solid;
650
651 // Dont' draw anything with this color if the palette index is out of bounds.
652 SkColor color = SK_ColorTRANSPARENT;
653 if (solid.color.palette_index == kForegroundColorPaletteIndex) {
654 U8CPU newAlpha = SkColorGetA(foregroundColor) *
655 SkColrV1AlphaToFloat(solid.color.alpha);
656 color = SkColorSetA(foregroundColor, newAlpha);
657 } else if (solid.color.palette_index >= palette.size()) {
658 return false;
659 } else {
660 U8CPU newAlpha = SkColorGetA(palette[solid.color.palette_index]) *
661 SkColrV1AlphaToFloat(solid.color.alpha);
662 color = SkColorSetA(palette[solid.color.palette_index], newAlpha);
663 }
664 paint->setShader(nullptr);
665 paint->setColor(color);
666 return true;
667 }
668 case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT: {
669 const FT_PaintLinearGradient& linearGradient = colrPaint.u.linear_gradient;
670 std::vector<SkScalar> stops;
671 std::vector<SkColor> colors;
672
673 if (!fetchColorStops(linearGradient.colorline.color_stop_iterator, stops, colors)) {
674 return false;
675 }
676
677 if (stops.size() == 1) {
678 paint->setColor(colors[0]);
679 return true;
680 }
681
682 SkPoint linePositions[2] = {SkPoint::Make( SkFixedToScalar(linearGradient.p0.x),
683 -SkFixedToScalar(linearGradient.p0.y)),
684 SkPoint::Make( SkFixedToScalar(linearGradient.p1.x),
685 -SkFixedToScalar(linearGradient.p1.y))};
686 SkPoint p0 = linePositions[0];
687 SkPoint p1 = linePositions[1];
688 SkPoint p2 = SkPoint::Make( SkFixedToScalar(linearGradient.p2.x),
689 -SkFixedToScalar(linearGradient.p2.y));
690
691 // If p0p1 or p0p2 are degenerate probably nothing should be drawn.
692 // If p0p1 and p0p2 are parallel then one side is the first color and the other side is
693 // the last color, depending on the direction.
694 // For now, just use the first color.
695 if (p1 == p0 || p2 == p0 || !SkPoint::CrossProduct(p1 - p0, p2 - p0)) {
696 paint->setColor(colors[0]);
697 return true;
698 }
699
700 // Follow implementation note in nanoemoji:
701 // https://github.com/googlefonts/nanoemoji/blob/0ac6e7bb4d8202db692574d8530a9b643f1b3b3c/src/nanoemoji/svg.py#L188
702 // to compute a new gradient end point P3 as the orthogonal
703 // projection of the vector from p0 to p1 onto a line perpendicular
704 // to line p0p2 and passing through p0.
705 SkVector perpendicularToP2P0 = (p2 - p0);
706 perpendicularToP2P0 = SkPoint::Make( perpendicularToP2P0.y(),
707 -perpendicularToP2P0.x());
708 SkVector p3 = p0 + SkVectorProjection((p1 - p0), perpendicularToP2P0);
709 linePositions[1] = p3;
710
711 // Project/scale points according to stop extrema along p0p3 line,
712 // p3 being the result of the projection above, then scale stops to
713 // to [0, 1] range so that repeat modes work. The Skia linear
714 // gradient shader performs the repeat modes over the 0 to 1 range,
715 // that's why we need to scale the stops to within that range.
716 SkTileMode tileMode = ToSkTileMode(linearGradient.colorline.extend);
717 SkScalar colorStopRange = stops.back() - stops.front();
718 // If the color stops are all at the same offset position, repeat and reflect modes
719 // become meaningless.
720 if (colorStopRange == 0.f) {
721 if (tileMode != SkTileMode::kClamp) {
722 paint->setColor(SK_ColorTRANSPARENT);
723 return true;
724 } else {
725 // Insert duplicated fake color stop in pad case at +1.0f to enable the projection
726 // of circles for an originally 0-length color stop range. Adding this stop will
727 // paint the equivalent gradient, because: All font specified color stops are in the
728 // same spot, mode is pad, so everything before this spot is painted with the first
729 // color, everything after this spot is painted with the last color. Not adding this
730 // stop will skip the projection and result in specifying non-normalized color stops
731 // to the shader.
732 stops.push_back(*(stops.end() - 1) + 1.0f);
733 colors.push_back(*(colors.end()-1));
734 colorStopRange = 1.0f;
735 }
736 }
737 SkASSERT(colorStopRange != 0.f);
738
739 // If the colorStopRange is 0 at this point, the default behavior of the shader is to
740 // clamp to 1 color stops that are above 1, clamp to 0 for color stops that are below 0,
741 // and repeat the outer color stops at 0 and 1 if the color stops are inside the
742 // range. That will result in the correct rendering.
743 if ((colorStopRange != 1 || stops.front() != 0.f)) {
744 SkVector p0p3 = p3 - p0;
745 SkVector p0Offset = p0p3;
746 p0Offset.scale(stops.front());
747 SkVector p1Offset = p0p3;
748 p1Offset.scale(stops.back());
749
750 linePositions[0] = p0 + p0Offset;
751 linePositions[1] = p0 + p1Offset;
752
753 SkScalar scaleFactor = 1 / colorStopRange;
754 SkScalar startOffset = stops.front();
755 for (SkScalar& stop : stops) {
756 stop = (stop - startOffset) * scaleFactor;
757 }
758 }
759
760 sk_sp<SkShader> shader(SkGradientShader::MakeLinear(
761 linePositions,
762 colors.data(), stops.data(), stops.size(),
763 tileMode));
764 SkASSERT(shader);
765 // An opaque color is needed to ensure the gradient is not modulated by alpha.
766 paint->setColor(SK_ColorBLACK);
767 paint->setShader(shader);
768 return true;
769 }
770 case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT: {
771 const FT_PaintRadialGradient& radialGradient = colrPaint.u.radial_gradient;
772 SkPoint start = SkPoint::Make( SkFixedToScalar(radialGradient.c0.x),
773 -SkFixedToScalar(radialGradient.c0.y));
774 SkScalar startRadius = SkFixedToScalar(radialGradient.r0);
775 SkPoint end = SkPoint::Make( SkFixedToScalar(radialGradient.c1.x),
776 -SkFixedToScalar(radialGradient.c1.y));
777 SkScalar endRadius = SkFixedToScalar(radialGradient.r1);
778
779
780 std::vector<SkScalar> stops;
781 std::vector<SkColor> colors;
782 if (!fetchColorStops(radialGradient.colorline.color_stop_iterator, stops, colors)) {
783 return false;
784 }
785
786 if (stops.size() == 1) {
787 paint->setColor(colors[0]);
788 return true;
789 }
790
791 SkScalar colorStopRange = stops.back() - stops.front();
792 SkTileMode tileMode = ToSkTileMode(radialGradient.colorline.extend);
793
794 if (colorStopRange == 0.f) {
795 if (tileMode != SkTileMode::kClamp) {
796 paint->setColor(SK_ColorTRANSPARENT);
797 return true;
798 } else {
799 // Insert duplicated fake color stop in pad case at +1.0f to enable the projection
800 // of circles for an originally 0-length color stop range. Adding this stop will
801 // paint the equivalent gradient, because: All font specified color stops are in the
802 // same spot, mode is pad, so everything before this spot is painted with the first
803 // color, everything after this spot is painted with the last color. Not adding this
804 // stop will skip the projection and result in specifying non-normalized color stops
805 // to the shader.
806 stops.push_back(*(stops.end() - 1) + 1.0f);
807 colors.push_back(*(colors.end()-1));
808 colorStopRange = 1.0f;
809 }
810 }
811 SkASSERT(colorStopRange != 0.f);
812
813 // If the colorStopRange is 0 at this point, the default behavior of the shader is to
814 // clamp to 1 color stops that are above 1, clamp to 0 for color stops that are below 0,
815 // and repeat the outer color stops at 0 and 1 if the color stops are inside the
816 // range. That will result in the correct rendering.
817 if (colorStopRange != 1 || stops.front() != 0.f) {
818 // For the Skia two-point caonical shader to understand the
819 // COLRv1 color stops we need to scale stops to 0 to 1 range and
820 // interpolate new centers and radii. Otherwise the shader
821 // clamps stops outside the range to 0 and 1 (larger interval)
822 // or repeats the outer stops at 0 and 1 if the (smaller
823 // interval).
824 SkVector startToEnd = end - start;
825 SkScalar radiusDiff = endRadius - startRadius;
826 SkScalar scaleFactor = 1 / colorStopRange;
827 SkScalar stopsStartOffset = stops.front();
828
829 SkVector startOffset = startToEnd;
830 startOffset.scale(stops.front());
831 SkVector endOffset = startToEnd;
832 endOffset.scale(stops.back());
833
834 // The order of the following computations is important in order to avoid
835 // overwriting start or startRadius before the second reassignment.
836 end = start + endOffset;
837 start = start + startOffset;
838 endRadius = startRadius + radiusDiff * stops.back();
839 startRadius = startRadius + radiusDiff * stops.front();
840
841 for (auto& stop : stops) {
842 stop = (stop - stopsStartOffset) * scaleFactor;
843 }
844 }
845
846 // For negative radii, interpolation is needed to prepare parameters suitable
847 // for invoking the shader. Implementation below as resolution discussed in
848 // https://github.com/googlefonts/colr-gradients-spec/issues/367.
849 // Truncate to manually interpolated color for tile mode clamp, otherwise
850 // calculate positive projected circles.
851 if (startRadius < 0 || endRadius < 0) {
852 if (startRadius == endRadius && startRadius < 0) {
853 paint->setColor(SK_ColorTRANSPARENT);
854 return true;
855 }
856
857 if (tileMode == SkTileMode::kClamp) {
858 SkVector startToEnd = end - start;
859 SkScalar radiusDiff = endRadius - startRadius;
860 SkScalar zeroRadiusStop = 0.f;
861 TruncateStops truncateSide = TruncateStart;
862 if (startRadius < 0) {
863 truncateSide = TruncateStart;
864
865 // Compute color stop position where radius is = 0. After the scaling
866 // of stop positions to the normal 0,1 range that we have done above,
867 // the size of the radius as a function of the color stops is: r(x) = r0
868 // + x*(r1-r0) Solving this function for r(x) = 0, we get: x = -r0 /
869 // (r1-r0)
870 zeroRadiusStop = -startRadius / (endRadius - startRadius);
871 startRadius = 0.f;
872 SkVector startEndDiff = end - start;
873 startEndDiff.scale(zeroRadiusStop);
874 start = start + startEndDiff;
875 }
876
877 if (endRadius < 0) {
878 truncateSide = TruncateEnd;
879 zeroRadiusStop = -startRadius / (endRadius - startRadius);
880 endRadius = 0.f;
881 SkVector startEndDiff = end - start;
882 startEndDiff.scale(1 - zeroRadiusStop);
883 end = end - startEndDiff;
884 }
885
886 if (!(startRadius == 0 && endRadius == 0)) {
887 truncateToStopInterpolating(
888 zeroRadiusStop, colors, stops, truncateSide);
889 } else {
890 // If both radii have become negative and where clamped to 0, we need to
891 // produce a single color cone, otherwise the shader colors the whole
892 // plane in a single color when two radii are specified as 0.
893 if (radiusDiff > 0) {
894 end = start + startToEnd;
895 endRadius = radiusDiff;
896 colors.erase(colors.begin(), colors.end() - 1);
897 stops.erase(stops.begin(), stops.end() - 1);
898 } else {
899 start -= startToEnd;
900 startRadius = -radiusDiff;
901 colors.erase(colors.begin() + 1, colors.end());
902 stops.erase(stops.begin() + 1, stops.end());
903 }
904 }
905 } else {
906 if (startRadius < 0 || endRadius < 0) {
907 auto roundIntegerMultiple = [](SkScalar factorZeroCrossing,
908 SkTileMode tileMode) {
909 int roundedMultiple = factorZeroCrossing > 0
910 ? ceilf(factorZeroCrossing)
911 : floorf(factorZeroCrossing) - 1;
912 if (tileMode == SkTileMode::kMirror && roundedMultiple % 2 != 0) {
913 roundedMultiple += roundedMultiple < 0 ? -1 : 1;
914 }
915 return roundedMultiple;
916 };
917
918 SkVector startToEnd = end - start;
919 SkScalar radiusDiff = endRadius - startRadius;
920 SkScalar factorZeroCrossing = (startRadius / (startRadius - endRadius));
921 bool inRange = 0.f <= factorZeroCrossing && factorZeroCrossing <= 1.0f;
922 SkScalar direction = inRange && radiusDiff < 0 ? -1.0f : 1.0f;
923 SkScalar circleProjectionFactor =
924 roundIntegerMultiple(factorZeroCrossing * direction, tileMode);
925 startToEnd.scale(circleProjectionFactor);
926 startRadius += circleProjectionFactor * radiusDiff;
927 endRadius += circleProjectionFactor * radiusDiff;
928 start += startToEnd;
929 end += startToEnd;
930 }
931 }
932 }
933
934 // An opaque color is needed to ensure the gradient is not modulated by alpha.
935 paint->setColor(SK_ColorBLACK);
936
937 paint->setShader(SkGradientShader::MakeTwoPointConical(
938 start, startRadius, end, endRadius, colors.data(), stops.data(), stops.size(),
939 tileMode));
940 return true;
941 }
942 case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT: {
943 const FT_PaintSweepGradient& sweepGradient = colrPaint.u.sweep_gradient;
944 SkPoint center = SkPoint::Make( SkFixedToScalar(sweepGradient.center.x),
945 -SkFixedToScalar(sweepGradient.center.y));
946
947
948 SkScalar startAngle = SkFixedToScalar(sweepGradient.start_angle * 180.0f);
949 SkScalar endAngle = SkFixedToScalar(sweepGradient.end_angle * 180.0f);
950 // OpenType 1.9.1 adds a shift to the angle to ease specification of a 0 to 360
951 // degree sweep.
952 startAngle += 180.0f;
953 endAngle += 180.0f;
954
955 std::vector<SkScalar> stops;
956 std::vector<SkColor> colors;
957 if (!fetchColorStops(sweepGradient.colorline.color_stop_iterator, stops, colors)) {
958 return false;
959 }
960
961 if (stops.size() == 1) {
962 paint->setColor(colors[0]);
963 return true;
964 }
965
966 // An opaque color is needed to ensure the gradient is not modulated by alpha.
967 paint->setColor(SK_ColorBLACK);
968
969 // New (Var)SweepGradient implementation compliant with OpenType 1.9.1 from here.
970
971 // The shader expects stops from 0 to 1, so we need to account for
972 // minimum and maximum stop positions being different from 0 and
973 // 1. We do that by scaling minimum and maximum stop positions to
974 // the 0 to 1 interval and scaling the angles inverse proportionally.
975
976 // 1) Scale angles to their equivalent positions if stops were from 0 to 1.
977
978 SkScalar sectorAngle = endAngle - startAngle;
979 SkTileMode tileMode = ToSkTileMode(sweepGradient.colorline.extend);
980 if (sectorAngle == 0 && tileMode != SkTileMode::kClamp) {
981 // "If the ColorLine's extend mode is reflect or repeat and start and end angle
982 // are equal, nothing is drawn.".
983 paint->setColor(SK_ColorTRANSPARENT);
984 return true;
985 }
986
987
988 SkScalar startAngleScaled = startAngle + sectorAngle * stops.front();
989 SkScalar endAngleScaled = startAngle + sectorAngle * stops.back();
990
991 // 2) Scale stops accordingly to 0 to 1 range.
992 SkScalar scaleFactor = 1 / (stops.back() - stops.front());
993 SkScalar startOffset = stops.front();
994
995 for (SkScalar& stop : stops) {
996 stop = (stop - startOffset) * scaleFactor;
997 }
998
999 /* https://docs.microsoft.com/en-us/typography/opentype/spec/colr#sweep-gradients
1000 * "The angles are expressed in counter-clockwise degrees from
1001 * the direction of the positive x-axis on the design
1002 * grid. [...] The color line progresses from the start angle
1003 * to the end angle in the counter-clockwise direction;" -
1004 * convert angles and stops from counter-clockwise to clockwise
1005 * for the shader if the gradient is not already reversed due to
1006 * start angle being larger than end angle. */
1007 startAngleScaled = 360.f - startAngleScaled;
1008 endAngleScaled = 360.f - endAngleScaled;
1009 if (startAngleScaled > endAngleScaled) {
1010 std::swap(startAngleScaled, endAngleScaled);
1011 std::reverse(stops.begin(), stops.end());
1012 std::reverse(colors.begin(), colors.end());
1013 for (auto& stop : stops) {
1014 stop = 1.0f - stop;
1015 }
1016 }
1017
1018 paint->setShader(SkGradientShader::MakeSweep(center.x(), center.y(),
1019 colors.data(),
1020 stops.data(), stops.size(),
1021 tileMode,
1022 startAngleScaled,
1023 endAngleScaled,
1024 0, nullptr));
1025 return true;
1026 }
1027 default: {
1028 SkASSERT(false);
1029 return false;
1030 }
1031 }
1032 SkUNREACHABLE;
1033 }
1034
colrv1_draw_paint(SkCanvas * canvas,const SkSpan<SkColor> & palette,const SkColor foregroundColor,FT_Face face,const FT_COLR_Paint & colrPaint)1035 bool colrv1_draw_paint(SkCanvas* canvas,
1036 const SkSpan<SkColor>& palette,
1037 const SkColor foregroundColor,
1038 FT_Face face,
1039 const FT_COLR_Paint& colrPaint) {
1040 switch (colrPaint.format) {
1041 case FT_COLR_PAINTFORMAT_GLYPH: {
1042 FT_UInt glyphID = colrPaint.u.glyph.glyphID;
1043 SkPath path;
1044 /* TODO: Currently this call retrieves the path at units_per_em size. If we want to get
1045 * correct hinting for the scaled size under the transforms at this point in the color
1046 * glyph graph, we need to extract at least the requested glyph width and height and
1047 * pass that to the path generation. */
1048 if (!generateFacePathCOLRv1(face, glyphID, &path)) {
1049 return false;
1050 }
1051 if constexpr (kSkShowTextBlitCoverage) {
1052 SkPaint highlight_paint;
1053 highlight_paint.setColor(0x33FF0000);
1054 canvas->drawRect(path.getBounds(), highlight_paint);
1055 }
1056 canvas->clipPath(path, true /* doAntiAlias */);
1057 return true;
1058 }
1059 case FT_COLR_PAINTFORMAT_SOLID:
1060 case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT:
1061 case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT:
1062 case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT: {
1063 SkPaint skPaint;
1064 if (!colrv1_configure_skpaint(face, palette, foregroundColor, colrPaint, &skPaint)) {
1065 return false;
1066 }
1067 canvas->drawPaint(skPaint);
1068 return true;
1069 }
1070 case FT_COLR_PAINTFORMAT_TRANSFORM:
1071 case FT_COLR_PAINTFORMAT_TRANSLATE:
1072 case FT_COLR_PAINTFORMAT_SCALE:
1073 case FT_COLR_PAINTFORMAT_ROTATE:
1074 case FT_COLR_PAINTFORMAT_SKEW:
1075 [[fallthrough]]; // Transforms handled in colrv1_transform.
1076 default:
1077 SkASSERT(false);
1078 return false;
1079 }
1080 SkUNREACHABLE;
1081 }
1082
colrv1_draw_glyph_with_path(SkCanvas * canvas,const SkSpan<SkColor> & palette,SkColor foregroundColor,FT_Face face,const FT_COLR_Paint & glyphPaint,const FT_COLR_Paint & fillPaint)1083 bool colrv1_draw_glyph_with_path(SkCanvas* canvas,
1084 const SkSpan<SkColor>& palette, SkColor foregroundColor,
1085 FT_Face face,
1086 const FT_COLR_Paint& glyphPaint, const FT_COLR_Paint& fillPaint) {
1087 SkASSERT(glyphPaint.format == FT_COLR_PAINTFORMAT_GLYPH);
1088 SkASSERT(fillPaint.format == FT_COLR_PAINTFORMAT_SOLID ||
1089 fillPaint.format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT ||
1090 fillPaint.format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT ||
1091 fillPaint.format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT);
1092
1093 SkPaint skiaFillPaint;
1094 skiaFillPaint.setAntiAlias(true);
1095 if (!colrv1_configure_skpaint(face, palette, foregroundColor, fillPaint, &skiaFillPaint)) {
1096 return false;
1097 }
1098
1099 FT_UInt glyphID = glyphPaint.u.glyph.glyphID;
1100 SkPath path;
1101 /* TODO: Currently this call retrieves the path at units_per_em size. If we want to get
1102 * correct hinting for the scaled size under the transforms at this point in the color
1103 * glyph graph, we need to extract at least the requested glyph width and height and
1104 * pass that to the path generation. */
1105 if (!generateFacePathCOLRv1(face, glyphID, &path)) {
1106 return false;
1107 }
1108 if constexpr (kSkShowTextBlitCoverage) {
1109 SkPaint highlightPaint;
1110 highlightPaint.setColor(0x33FF0000);
1111 canvas->drawRect(path.getBounds(), highlightPaint);
1112 }
1113 canvas->drawPath(path, skiaFillPaint);
1114 return true;
1115 }
1116
1117
1118 /* In drawing mode, concatenates the transforms directly on SkCanvas. In
1119 * bounding box calculation mode, no SkCanvas is specified, but we only want to
1120 * retrieve the transform from the FreeType paint object. */
colrv1_transform(FT_Face face,const FT_COLR_Paint & colrPaint,SkCanvas * canvas,SkMatrix * outTransform=nullptr)1121 void colrv1_transform(FT_Face face,
1122 const FT_COLR_Paint& colrPaint,
1123 SkCanvas* canvas,
1124 SkMatrix* outTransform = nullptr) {
1125 SkMatrix transform;
1126
1127 SkASSERT(canvas || outTransform);
1128
1129 switch (colrPaint.format) {
1130 case FT_COLR_PAINTFORMAT_TRANSFORM: {
1131 transform = ToSkMatrix(colrPaint.u.transform.affine);
1132 break;
1133 }
1134 case FT_COLR_PAINTFORMAT_TRANSLATE: {
1135 transform = SkMatrix::Translate( SkFixedToScalar(colrPaint.u.translate.dx),
1136 -SkFixedToScalar(colrPaint.u.translate.dy));
1137 break;
1138 }
1139 case FT_COLR_PAINTFORMAT_SCALE: {
1140 transform.setScale( SkFixedToScalar(colrPaint.u.scale.scale_x),
1141 SkFixedToScalar(colrPaint.u.scale.scale_y),
1142 SkFixedToScalar(colrPaint.u.scale.center_x),
1143 -SkFixedToScalar(colrPaint.u.scale.center_y));
1144 break;
1145 }
1146 case FT_COLR_PAINTFORMAT_ROTATE: {
1147 // COLRv1 angles are counter-clockwise, compare
1148 // https://docs.microsoft.com/en-us/typography/opentype/spec/colr#formats-24-to-27-paintrotate-paintvarrotate-paintrotatearoundcenter-paintvarrotatearoundcenter
1149 transform = SkMatrix::RotateDeg(
1150 -SkFixedToScalar(colrPaint.u.rotate.angle) * 180.0f,
1151 SkPoint::Make( SkFixedToScalar(colrPaint.u.rotate.center_x),
1152 -SkFixedToScalar(colrPaint.u.rotate.center_y)));
1153 break;
1154 }
1155 case FT_COLR_PAINTFORMAT_SKEW: {
1156 // In the PAINTFORMAT_ROTATE implementation, SkMatrix setRotate
1157 // snaps to 0 for values very close to 0. Do the same here.
1158
1159 SkScalar xDeg = SkFixedToScalar(colrPaint.u.skew.x_skew_angle) * 180.0f;
1160 SkScalar xRad = SkDegreesToRadians(xDeg);
1161 SkScalar xTan = SkScalarTan(xRad);
1162 xTan = SkScalarNearlyZero(xTan) ? 0.0f : xTan;
1163
1164 SkScalar yDeg = SkFixedToScalar(colrPaint.u.skew.y_skew_angle) * 180.0f;
1165 // Negate y_skew_angle due to Skia's y-down coordinate system to achieve
1166 // counter-clockwise skew along the y-axis.
1167 SkScalar yRad = SkDegreesToRadians(-yDeg);
1168 SkScalar yTan = SkScalarTan(yRad);
1169 yTan = SkScalarNearlyZero(yTan) ? 0.0f : yTan;
1170
1171 transform.setSkew(xTan, yTan,
1172 SkFixedToScalar(colrPaint.u.skew.center_x),
1173 -SkFixedToScalar(colrPaint.u.skew.center_y));
1174 break;
1175 }
1176 default: {
1177 SkASSERT(false); // Only transforms are handled in this function.
1178 }
1179 }
1180 if (canvas) {
1181 canvas->concat(transform);
1182 }
1183 if (outTransform) {
1184 *outTransform = transform;
1185 }
1186 }
1187
1188 bool colrv1_start_glyph(SkCanvas* canvas,
1189 const SkSpan<SkColor>& palette,
1190 const SkColor foregroundColor,
1191 FT_Face face,
1192 uint16_t glyphId,
1193 FT_Color_Root_Transform rootTransform,
1194 VisitedSet* activePaints);
1195
colrv1_traverse_paint(SkCanvas * canvas,const SkSpan<SkColor> & palette,const SkColor foregroundColor,FT_Face face,FT_OpaquePaint opaquePaint,VisitedSet * activePaints)1196 bool colrv1_traverse_paint(SkCanvas* canvas,
1197 const SkSpan<SkColor>& palette,
1198 const SkColor foregroundColor,
1199 FT_Face face,
1200 FT_OpaquePaint opaquePaint,
1201 VisitedSet* activePaints) {
1202 // Cycle detection, see section "5.7.11.1.9 Color glyphs as a directed acyclic graph".
1203 if (activePaints->contains(opaquePaint)) {
1204 return false;
1205 }
1206
1207 activePaints->add(opaquePaint);
1208 SK_AT_SCOPE_EXIT(activePaints->remove(opaquePaint));
1209
1210 FT_COLR_Paint paint;
1211 if (!FT_Get_Paint(face, opaquePaint, &paint)) {
1212 return false;
1213 }
1214
1215 SkAutoCanvasRestore autoRestore(canvas, true /* doSave */);
1216 switch (paint.format) {
1217 case FT_COLR_PAINTFORMAT_COLR_LAYERS: {
1218 FT_LayerIterator& layerIterator = paint.u.colr_layers.layer_iterator;
1219 FT_OpaquePaint layerPaint{nullptr, 1};
1220 while (FT_Get_Paint_Layers(face, &layerIterator, &layerPaint)) {
1221 if (!colrv1_traverse_paint(canvas, palette, foregroundColor, face,
1222 layerPaint, activePaints)) {
1223 return false;
1224 }
1225 }
1226 return true;
1227 }
1228 case FT_COLR_PAINTFORMAT_GLYPH:
1229 // Special case paint graph leaf situations to improve
1230 // performance. These are situations in the graph where a GlyphPaint
1231 // is followed by either a solid or a gradient fill. Here we can use
1232 // drawPath() + SkPaint directly which is faster than setting a
1233 // clipPath() followed by a drawPaint().
1234 FT_COLR_Paint fillPaint;
1235 if (!FT_Get_Paint(face, paint.u.glyph.paint, &fillPaint)) {
1236 return false;
1237 }
1238 if (fillPaint.format == FT_COLR_PAINTFORMAT_SOLID ||
1239 fillPaint.format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT ||
1240 fillPaint.format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT ||
1241 fillPaint.format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT)
1242 {
1243 return colrv1_draw_glyph_with_path(canvas, palette, foregroundColor,
1244 face, paint, fillPaint);
1245 }
1246 if (!colrv1_draw_paint(canvas, palette, foregroundColor, face, paint)) {
1247 return false;
1248 }
1249 return colrv1_traverse_paint(canvas, palette, foregroundColor,
1250 face, paint.u.glyph.paint, activePaints);
1251 case FT_COLR_PAINTFORMAT_COLR_GLYPH:
1252 return colrv1_start_glyph(canvas, palette, foregroundColor,
1253 face, paint.u.colr_glyph.glyphID, FT_COLOR_NO_ROOT_TRANSFORM,
1254 activePaints);
1255 case FT_COLR_PAINTFORMAT_TRANSFORM:
1256 colrv1_transform(face, paint, canvas);
1257 return colrv1_traverse_paint(canvas, palette, foregroundColor,
1258 face, paint.u.transform.paint, activePaints);
1259 case FT_COLR_PAINTFORMAT_TRANSLATE:
1260 colrv1_transform(face, paint, canvas);
1261 return colrv1_traverse_paint(canvas, palette, foregroundColor,
1262 face, paint.u.translate.paint, activePaints);
1263 case FT_COLR_PAINTFORMAT_SCALE:
1264 colrv1_transform(face, paint, canvas);
1265 return colrv1_traverse_paint(canvas, palette, foregroundColor,
1266 face, paint.u.scale.paint, activePaints);
1267 case FT_COLR_PAINTFORMAT_ROTATE:
1268 colrv1_transform(face, paint, canvas);
1269 return colrv1_traverse_paint(canvas, palette, foregroundColor,
1270 face, paint.u.rotate.paint, activePaints);
1271 case FT_COLR_PAINTFORMAT_SKEW:
1272 colrv1_transform(face, paint, canvas);
1273 return colrv1_traverse_paint(canvas, palette, foregroundColor,
1274 face, paint.u.skew.paint, activePaints);
1275 case FT_COLR_PAINTFORMAT_COMPOSITE: {
1276 SkAutoCanvasRestore acr(canvas, false);
1277 canvas->saveLayer(nullptr, nullptr);
1278 if (!colrv1_traverse_paint(canvas, palette, foregroundColor,
1279 face, paint.u.composite.backdrop_paint, activePaints)) {
1280 return false;
1281 }
1282 SkPaint blendModePaint;
1283 blendModePaint.setBlendMode(ToSkBlendMode(paint.u.composite.composite_mode));
1284 canvas->saveLayer(nullptr, &blendModePaint);
1285 return colrv1_traverse_paint(canvas, palette, foregroundColor,
1286 face, paint.u.composite.source_paint, activePaints);
1287 }
1288 case FT_COLR_PAINTFORMAT_SOLID:
1289 case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT:
1290 case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT:
1291 case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT: {
1292 return colrv1_draw_paint(canvas, palette, foregroundColor, face, paint);
1293 }
1294 default:
1295 SkASSERT(false);
1296 return false;
1297 }
1298 SkUNREACHABLE;
1299 }
1300
GetClipBoxPath(FT_Face face,uint16_t glyphId,bool untransformed)1301 SkPath GetClipBoxPath(FT_Face face, uint16_t glyphId, bool untransformed) {
1302 SkPath resultPath;
1303 SkUniqueFTSize unscaledFtSize = nullptr;
1304 FT_Size oldSize = face->size;
1305 FT_Matrix oldTransform;
1306 FT_Vector oldDelta;
1307 FT_Error err = 0;
1308
1309 if (untransformed) {
1310 unscaledFtSize.reset(
1311 [face]() -> FT_Size {
1312 FT_Size size;
1313 FT_Error err = FT_New_Size(face, &size);
1314 if (err != 0) {
1315 SK_TRACEFTR(err,
1316 "FT_New_Size(%s) failed in generateFacePathStaticCOLRv1.",
1317 face->family_name);
1318 return nullptr;
1319 }
1320 return size;
1321 }());
1322 if (!unscaledFtSize) {
1323 return resultPath;
1324 }
1325
1326 err = FT_Activate_Size(unscaledFtSize.get());
1327 if (err != 0) {
1328 return resultPath;
1329 }
1330
1331 err = FT_Set_Char_Size(face, SkIntToFDot6(face->units_per_EM), 0, 0, 0);
1332 if (err != 0) {
1333 return resultPath;
1334 }
1335
1336 FT_Get_Transform(face, &oldTransform, &oldDelta);
1337 FT_Set_Transform(face, nullptr, nullptr);
1338 }
1339
1340 FT_ClipBox colrGlyphClipBox;
1341 if (FT_Get_Color_Glyph_ClipBox(face, glyphId, &colrGlyphClipBox)) {
1342 resultPath = SkPath::Polygon({{ SkFDot6ToScalar(colrGlyphClipBox.bottom_left.x),
1343 -SkFDot6ToScalar(colrGlyphClipBox.bottom_left.y)},
1344 { SkFDot6ToScalar(colrGlyphClipBox.top_left.x),
1345 -SkFDot6ToScalar(colrGlyphClipBox.top_left.y)},
1346 { SkFDot6ToScalar(colrGlyphClipBox.top_right.x),
1347 -SkFDot6ToScalar(colrGlyphClipBox.top_right.y)},
1348 { SkFDot6ToScalar(colrGlyphClipBox.bottom_right.x),
1349 -SkFDot6ToScalar(colrGlyphClipBox.bottom_right.y)}},
1350 true);
1351 }
1352
1353 if (untransformed) {
1354 err = FT_Activate_Size(oldSize);
1355 if (err != 0) {
1356 return resultPath;
1357 }
1358 FT_Set_Transform(face, &oldTransform, &oldDelta);
1359 }
1360
1361 return resultPath;
1362 }
1363
colrv1_start_glyph(SkCanvas * canvas,const SkSpan<SkColor> & palette,const SkColor foregroundColor,FT_Face face,uint16_t glyphId,FT_Color_Root_Transform rootTransform,VisitedSet * activePaints)1364 bool colrv1_start_glyph(SkCanvas* canvas,
1365 const SkSpan<SkColor>& palette,
1366 const SkColor foregroundColor,
1367 FT_Face face,
1368 uint16_t glyphId,
1369 FT_Color_Root_Transform rootTransform,
1370 VisitedSet* activePaints) {
1371 FT_OpaquePaint opaquePaint{nullptr, 1};
1372 if (!FT_Get_Color_Glyph_Paint(face, glyphId, rootTransform, &opaquePaint)) {
1373 return false;
1374 }
1375
1376 bool untransformed = rootTransform == FT_COLOR_NO_ROOT_TRANSFORM;
1377 SkPath clipBoxPath = GetClipBoxPath(face, glyphId, untransformed);
1378 if (!clipBoxPath.isEmpty()) {
1379 canvas->clipPath(clipBoxPath, true);
1380 }
1381
1382 if (!colrv1_traverse_paint(canvas, palette, foregroundColor,
1383 face, opaquePaint, activePaints)) {
1384 return false;
1385 }
1386
1387 return true;
1388 }
1389
1390 bool colrv1_start_glyph_bounds(SkMatrix *ctm,
1391 SkRect* bounds,
1392 FT_Face face,
1393 uint16_t glyphId,
1394 FT_Color_Root_Transform rootTransform,
1395 VisitedSet* activePaints);
1396
colrv1_traverse_paint_bounds(SkMatrix * ctm,SkRect * bounds,FT_Face face,FT_OpaquePaint opaquePaint,VisitedSet * activePaints)1397 bool colrv1_traverse_paint_bounds(SkMatrix* ctm,
1398 SkRect* bounds,
1399 FT_Face face,
1400 FT_OpaquePaint opaquePaint,
1401 VisitedSet* activePaints) {
1402 // Cycle detection, see section "5.7.11.1.9 Color glyphs as a directed acyclic graph".
1403 if (activePaints->contains(opaquePaint)) {
1404 return false;
1405 }
1406
1407 activePaints->add(opaquePaint);
1408 SK_AT_SCOPE_EXIT(activePaints->remove(opaquePaint));
1409
1410 FT_COLR_Paint paint;
1411 if (!FT_Get_Paint(face, opaquePaint, &paint)) {
1412 return false;
1413 }
1414
1415 SkMatrix restoreMatrix = *ctm;
1416 SK_AT_SCOPE_EXIT(*ctm = restoreMatrix);
1417
1418 switch (paint.format) {
1419 case FT_COLR_PAINTFORMAT_COLR_LAYERS: {
1420 FT_LayerIterator& layerIterator = paint.u.colr_layers.layer_iterator;
1421 FT_OpaquePaint layerPaint{nullptr, 1};
1422 while (FT_Get_Paint_Layers(face, &layerIterator, &layerPaint)) {
1423 if (!colrv1_traverse_paint_bounds(ctm, bounds, face, layerPaint, activePaints)) {
1424 return false;
1425 }
1426 }
1427 return true;
1428 }
1429 case FT_COLR_PAINTFORMAT_GLYPH: {
1430 FT_UInt glyphID = paint.u.glyph.glyphID;
1431 SkPath path;
1432 if (!generateFacePathCOLRv1(face, glyphID, &path)) {
1433 return false;
1434 }
1435 path.transform(*ctm);
1436 bounds->join(path.getBounds());
1437 return true;
1438 }
1439 case FT_COLR_PAINTFORMAT_COLR_GLYPH: {
1440 FT_UInt glyphID = paint.u.colr_glyph.glyphID;
1441 return colrv1_start_glyph_bounds(ctm, bounds, face, glyphID, FT_COLOR_NO_ROOT_TRANSFORM,
1442 activePaints);
1443 }
1444 case FT_COLR_PAINTFORMAT_TRANSFORM: {
1445 SkMatrix transformMatrix;
1446 colrv1_transform(face, paint, nullptr, &transformMatrix);
1447 ctm->preConcat(transformMatrix);
1448 FT_OpaquePaint& transformPaint = paint.u.transform.paint;
1449 return colrv1_traverse_paint_bounds(ctm, bounds, face, transformPaint, activePaints);
1450 }
1451 case FT_COLR_PAINTFORMAT_TRANSLATE: {
1452 SkMatrix transformMatrix;
1453 colrv1_transform(face, paint, nullptr, &transformMatrix);
1454 ctm->preConcat(transformMatrix);
1455 FT_OpaquePaint& translatePaint = paint.u.translate.paint;
1456 return colrv1_traverse_paint_bounds(ctm, bounds, face, translatePaint, activePaints);
1457 }
1458 case FT_COLR_PAINTFORMAT_SCALE: {
1459 SkMatrix transformMatrix;
1460 colrv1_transform(face, paint, nullptr, &transformMatrix);
1461 ctm->preConcat(transformMatrix);
1462 FT_OpaquePaint& scalePaint = paint.u.scale.paint;
1463 return colrv1_traverse_paint_bounds(ctm, bounds, face, scalePaint, activePaints);
1464 }
1465 case FT_COLR_PAINTFORMAT_ROTATE: {
1466 SkMatrix transformMatrix;
1467 colrv1_transform(face, paint, nullptr, &transformMatrix);
1468 ctm->preConcat(transformMatrix);
1469 FT_OpaquePaint& rotatePaint = paint.u.rotate.paint;
1470 return colrv1_traverse_paint_bounds(ctm, bounds, face, rotatePaint, activePaints);
1471 }
1472 case FT_COLR_PAINTFORMAT_SKEW: {
1473 SkMatrix transformMatrix;
1474 colrv1_transform(face, paint, nullptr, &transformMatrix);
1475 ctm->preConcat(transformMatrix);
1476 FT_OpaquePaint& skewPaint = paint.u.skew.paint;
1477 return colrv1_traverse_paint_bounds(ctm, bounds, face, skewPaint, activePaints);
1478 }
1479 case FT_COLR_PAINTFORMAT_COMPOSITE: {
1480 FT_OpaquePaint& backdropPaint = paint.u.composite.backdrop_paint;
1481 FT_OpaquePaint& sourcePaint = paint.u.composite. source_paint;
1482 return colrv1_traverse_paint_bounds(ctm, bounds, face, backdropPaint, activePaints) &&
1483 colrv1_traverse_paint_bounds(ctm, bounds, face, sourcePaint, activePaints);
1484 }
1485 case FT_COLR_PAINTFORMAT_SOLID:
1486 case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT:
1487 case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT:
1488 case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT: {
1489 return true;
1490 }
1491 default:
1492 SkASSERT(false);
1493 return false;
1494 }
1495 SkUNREACHABLE;
1496 }
1497
1498
colrv1_start_glyph_bounds(SkMatrix * ctm,SkRect * bounds,FT_Face face,uint16_t glyphId,FT_Color_Root_Transform rootTransform,VisitedSet * activePaints)1499 bool colrv1_start_glyph_bounds(SkMatrix *ctm,
1500 SkRect* bounds,
1501 FT_Face face,
1502 uint16_t glyphId,
1503 FT_Color_Root_Transform rootTransform,
1504 VisitedSet* activePaints) {
1505 FT_OpaquePaint opaquePaint{nullptr, 1};
1506 return FT_Get_Color_Glyph_Paint(face, glyphId, rootTransform, &opaquePaint) &&
1507 colrv1_traverse_paint_bounds(ctm, bounds, face, opaquePaint, activePaints);
1508 }
1509 #endif // TT_SUPPORT_COLRV1
1510
1511 } // namespace
1512
1513
1514 #ifdef TT_SUPPORT_COLRV1
drawCOLRv1Glyph(FT_Face face,const SkGlyph & glyph,uint32_t loadGlyphFlags,SkSpan<SkColor> palette,SkCanvas * canvas)1515 bool SkScalerContext_FreeType_Base::drawCOLRv1Glyph(FT_Face face,
1516 const SkGlyph& glyph,
1517 uint32_t loadGlyphFlags,
1518 SkSpan<SkColor> palette,
1519 SkCanvas* canvas) {
1520 if (this->isSubpixel()) {
1521 canvas->translate(SkFixedToScalar(glyph.getSubXFixed()),
1522 SkFixedToScalar(glyph.getSubYFixed()));
1523 }
1524
1525 VisitedSet activePaints;
1526 bool haveLayers = colrv1_start_glyph(canvas, palette,
1527 fRec.fForegroundColor,
1528 face, glyph.getGlyphID(),
1529 FT_COLOR_INCLUDE_ROOT_TRANSFORM,
1530 &activePaints);
1531 SkASSERTF(haveLayers, "Could not get COLRv1 layers from '%s'.", face->family_name);
1532 return haveLayers;
1533 }
1534 #endif // TT_SUPPORT_COLRV1
1535
1536 #ifdef FT_COLOR_H
drawCOLRv0Glyph(FT_Face face,const SkGlyph & glyph,uint32_t loadGlyphFlags,SkSpan<SkColor> palette,SkCanvas * canvas)1537 bool SkScalerContext_FreeType_Base::drawCOLRv0Glyph(FT_Face face,
1538 const SkGlyph& glyph,
1539 uint32_t loadGlyphFlags,
1540 SkSpan<SkColor> palette,
1541 SkCanvas* canvas) {
1542 if (this->isSubpixel()) {
1543 canvas->translate(SkFixedToScalar(glyph.getSubXFixed()),
1544 SkFixedToScalar(glyph.getSubYFixed()));
1545 }
1546
1547 bool haveLayers = false;
1548 FT_LayerIterator layerIterator;
1549 layerIterator.p = nullptr;
1550 FT_UInt layerGlyphIndex = 0;
1551 FT_UInt layerColorIndex = 0;
1552 SkPaint paint;
1553 paint.setAntiAlias(!(loadGlyphFlags & FT_LOAD_TARGET_MONO));
1554 while (FT_Get_Color_Glyph_Layer(face, glyph.getGlyphID(), &layerGlyphIndex,
1555 &layerColorIndex, &layerIterator)) {
1556 haveLayers = true;
1557 if (layerColorIndex == 0xFFFF) {
1558 paint.setColor(fRec.fForegroundColor);
1559 } else {
1560 paint.setColor(palette[layerColorIndex]);
1561 }
1562 SkPath path;
1563 if (this->generateFacePath(face, layerGlyphIndex, loadGlyphFlags, &path)) {
1564 canvas->drawPath(path, paint);
1565 }
1566 }
1567 SkASSERTF(haveLayers, "Could not get COLRv0 layers from '%s'.", face->family_name);
1568 return haveLayers;
1569 }
1570 #endif // FT_COLOR_H
1571
1572 #if defined(FT_CONFIG_OPTION_SVG)
drawSVGGlyph(FT_Face face,const SkGlyph & glyph,uint32_t loadGlyphFlags,SkSpan<SkColor> palette,SkCanvas * canvas)1573 bool SkScalerContext_FreeType_Base::drawSVGGlyph(FT_Face face,
1574 const SkGlyph& glyph,
1575 uint32_t loadGlyphFlags,
1576 SkSpan<SkColor> palette,
1577 SkCanvas* canvas) {
1578 SkASSERT(face->glyph->format == FT_GLYPH_FORMAT_SVG);
1579
1580 FT_SVG_Document ftSvg = (FT_SVG_Document)face->glyph->other;
1581 SkMatrix m;
1582 FT_Matrix ftMatrix = ftSvg->transform;
1583 FT_Vector ftOffset = ftSvg->delta;
1584 m.setAll(
1585 SkFixedToFloat(ftMatrix.xx), -SkFixedToFloat(ftMatrix.xy), SkFixedToFloat(ftOffset.x),
1586 -SkFixedToFloat(ftMatrix.yx), SkFixedToFloat(ftMatrix.yy), -SkFixedToFloat(ftOffset.y),
1587 0 , 0 , 1 );
1588 m.postScale(SkFixedToFloat(ftSvg->metrics.x_scale) / 64.0f,
1589 SkFixedToFloat(ftSvg->metrics.y_scale) / 64.0f);
1590 if (this->isSubpixel()) {
1591 m.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
1592 SkFixedToScalar(glyph.getSubYFixed()));
1593 }
1594 canvas->concat(m);
1595
1596 SkGraphics::OpenTypeSVGDecoderFactory svgFactory = SkGraphics::GetOpenTypeSVGDecoderFactory();
1597 if (!svgFactory) {
1598 return false;
1599 }
1600 auto svgDecoder = svgFactory(ftSvg->svg_document, ftSvg->svg_document_length);
1601 if (!svgDecoder) {
1602 return false;
1603 }
1604 return svgDecoder->render(*canvas, ftSvg->units_per_EM, glyph.getGlyphID(),
1605 fRec.fForegroundColor, palette);
1606 }
1607 #endif // FT_CONFIG_OPTION_SVG
1608
generateGlyphImage(FT_Face face,const SkGlyph & glyph,const SkMatrix & bitmapTransform)1609 void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face,
1610 const SkGlyph& glyph,
1611 const SkMatrix& bitmapTransform)
1612 {
1613 switch ( face->glyph->format ) {
1614 case FT_GLYPH_FORMAT_OUTLINE: {
1615 FT_Outline* outline = &face->glyph->outline;
1616
1617 int dx = 0, dy = 0;
1618 if (this->isSubpixel()) {
1619 dx = SkFixedToFDot6(glyph.getSubXFixed());
1620 dy = SkFixedToFDot6(glyph.getSubYFixed());
1621 // negate dy since freetype-y-goes-up and skia-y-goes-down
1622 dy = -dy;
1623 }
1624
1625 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
1626
1627 if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
1628 const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
1629 const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
1630
1631 FT_Outline_Translate(outline, dx, dy);
1632 FT_Error err = FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V :
1633 FT_RENDER_MODE_LCD);
1634 if (err) {
1635 SK_TRACEFTR(err, "Could not render glyph %p.", face->glyph);
1636 return;
1637 }
1638
1639 SkMask mask = glyph.mask();
1640 if constexpr (kSkShowTextBlitCoverage) {
1641 memset(mask.fImage, 0x80, mask.fBounds.height() * mask.fRowBytes);
1642 }
1643 FT_GlyphSlotRec& ftGlyph = *face->glyph;
1644
1645 if (!SkIRect::Intersects(mask.fBounds,
1646 SkIRect::MakeXYWH( ftGlyph.bitmap_left,
1647 -ftGlyph.bitmap_top,
1648 ftGlyph.bitmap.width,
1649 ftGlyph.bitmap.rows)))
1650 {
1651 return;
1652 }
1653
1654 // If the FT_Bitmap extent is larger, discard bits of the bitmap outside the mask.
1655 // If the SkMask extent is larger, shrink mask to fit bitmap (clearing discarded).
1656 unsigned char* origBuffer = ftGlyph.bitmap.buffer;
1657 // First align the top left (origin).
1658 if (-ftGlyph.bitmap_top < mask.fBounds.fTop) {
1659 int32_t topDiff = mask.fBounds.fTop - (-ftGlyph.bitmap_top);
1660 ftGlyph.bitmap.buffer += ftGlyph.bitmap.pitch * topDiff;
1661 ftGlyph.bitmap.rows -= topDiff;
1662 ftGlyph.bitmap_top = -mask.fBounds.fTop;
1663 }
1664 if (ftGlyph.bitmap_left < mask.fBounds.fLeft) {
1665 int32_t leftDiff = mask.fBounds.fLeft - ftGlyph.bitmap_left;
1666 ftGlyph.bitmap.buffer += leftDiff;
1667 ftGlyph.bitmap.width -= leftDiff;
1668 ftGlyph.bitmap_left = mask.fBounds.fLeft;
1669 }
1670 if (mask.fBounds.fTop < -ftGlyph.bitmap_top) {
1671 mask.fImage += mask.fRowBytes * (-ftGlyph.bitmap_top - mask.fBounds.fTop);
1672 mask.fBounds.fTop = -ftGlyph.bitmap_top;
1673 }
1674 if (mask.fBounds.fLeft < ftGlyph.bitmap_left) {
1675 mask.fImage += sizeof(uint16_t) * (ftGlyph.bitmap_left - mask.fBounds.fLeft);
1676 mask.fBounds.fLeft = ftGlyph.bitmap_left;
1677 }
1678 // Origins aligned, clean up the width and height.
1679 int ftVertScale = (doVert ? 3 : 1);
1680 int ftHoriScale = (doVert ? 1 : 3);
1681 if (mask.fBounds.height() * ftVertScale < SkToInt(ftGlyph.bitmap.rows)) {
1682 ftGlyph.bitmap.rows = mask.fBounds.height() * ftVertScale;
1683 }
1684 if (mask.fBounds.width() * ftHoriScale < SkToInt(ftGlyph.bitmap.width)) {
1685 ftGlyph.bitmap.width = mask.fBounds.width() * ftHoriScale;
1686 }
1687 if (SkToInt(ftGlyph.bitmap.rows) < mask.fBounds.height() * ftVertScale) {
1688 mask.fBounds.fBottom = mask.fBounds.fTop + ftGlyph.bitmap.rows / ftVertScale;
1689 }
1690 if (SkToInt(ftGlyph.bitmap.width) < mask.fBounds.width() * ftHoriScale) {
1691 mask.fBounds.fRight = mask.fBounds.fLeft + ftGlyph.bitmap.width / ftHoriScale;
1692 }
1693 if (fPreBlend.isApplicable()) {
1694 copyFT2LCD16<true>(ftGlyph.bitmap, mask, doBGR,
1695 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1696 } else {
1697 copyFT2LCD16<false>(ftGlyph.bitmap, mask, doBGR,
1698 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1699 }
1700 // Restore the buffer pointer so FreeType can properly free it.
1701 ftGlyph.bitmap.buffer = origBuffer;
1702 } else {
1703 FT_BBox bbox;
1704 FT_Bitmap target;
1705 FT_Outline_Get_CBox(outline, &bbox);
1706 /*
1707 what we really want to do for subpixel is
1708 offset(dx, dy)
1709 compute_bounds
1710 offset(bbox & !63)
1711 but that is two calls to offset, so we do the following, which
1712 achieves the same thing with only one offset call.
1713 */
1714 FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
1715 dy - ((bbox.yMin + dy) & ~63));
1716
1717 target.width = glyph.fWidth;
1718 target.rows = glyph.fHeight;
1719 target.pitch = glyph.rowBytes();
1720 target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
1721 target.pixel_mode = compute_pixel_mode(glyph.fMaskFormat);
1722 target.num_grays = 256;
1723
1724 FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
1725 if constexpr (kSkShowTextBlitCoverage) {
1726 if (glyph.fMaskFormat == SkMask::kBW_Format) {
1727 for (unsigned y = 0; y < target.rows; y += 2) {
1728 for (unsigned x = (y & 0x2); x < target.width; x+=4) {
1729 uint8_t& b = target.buffer[(target.pitch * y) + (x >> 3)];
1730 b = b ^ (1 << (0x7 - (x & 0x7)));
1731 }
1732 }
1733 } else {
1734 for (unsigned y = 0; y < target.rows; ++y) {
1735 for (unsigned x = 0; x < target.width; ++x) {
1736 uint8_t& a = target.buffer[(target.pitch * y) + x];
1737 a = std::max<uint8_t>(a, 0x20);
1738 }
1739 }
1740 }
1741 }
1742 }
1743 } break;
1744
1745 case FT_GLYPH_FORMAT_BITMAP: {
1746 FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
1747 SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1748
1749 // Assume that the other formats do not exist.
1750 SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
1751 FT_PIXEL_MODE_GRAY == pixel_mode ||
1752 FT_PIXEL_MODE_BGRA == pixel_mode);
1753
1754 // These are the only formats this ScalerContext should request.
1755 SkASSERT(SkMask::kBW_Format == maskFormat ||
1756 SkMask::kA8_Format == maskFormat ||
1757 SkMask::kARGB32_Format == maskFormat ||
1758 SkMask::kLCD16_Format == maskFormat);
1759
1760 // If no scaling needed, directly copy glyph bitmap.
1761 if (bitmapTransform.isIdentity()) {
1762 SkMask dstMask = glyph.mask();
1763 copyFTBitmap(face->glyph->bitmap, dstMask);
1764 break;
1765 }
1766
1767 // Otherwise, scale the bitmap.
1768
1769 // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
1770 SkBitmap unscaledBitmap;
1771 // TODO: mark this as sRGB when the blits will be sRGB.
1772 unscaledBitmap.setInfo(SkImageInfo::Make(face->glyph->bitmap.width,
1773 face->glyph->bitmap.rows,
1774 SkColorType_for_FTPixelMode(pixel_mode),
1775 kPremul_SkAlphaType));
1776 if (!unscaledBitmap.tryAllocPixels()) {
1777 // TODO: set the fImage to indicate "missing"
1778 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
1779 return;
1780 }
1781
1782 SkMask unscaledBitmapAlias;
1783 unscaledBitmapAlias.fImage = reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels());
1784 unscaledBitmapAlias.fBounds.setWH(unscaledBitmap.width(), unscaledBitmap.height());
1785 unscaledBitmapAlias.fRowBytes = unscaledBitmap.rowBytes();
1786 unscaledBitmapAlias.fFormat = SkMaskFormat_for_SkColorType(unscaledBitmap.colorType());
1787 copyFTBitmap(face->glyph->bitmap, unscaledBitmapAlias);
1788
1789 // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
1790 // BW requires an A8 target for resizing, which can then be down sampled.
1791 // LCD should use a 4x A8 target, which will then be down sampled.
1792 // For simplicity, LCD uses A8 and is replicated.
1793 int bitmapRowBytes = 0;
1794 if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
1795 bitmapRowBytes = glyph.rowBytes();
1796 }
1797 SkBitmap dstBitmap;
1798 // TODO: mark this as sRGB when the blits will be sRGB.
1799 dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
1800 SkColorType_for_SkMaskFormat(maskFormat),
1801 kPremul_SkAlphaType),
1802 bitmapRowBytes);
1803 if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
1804 if (!dstBitmap.tryAllocPixels()) {
1805 // TODO: set the fImage to indicate "missing"
1806 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
1807 return;
1808 }
1809 } else {
1810 dstBitmap.setPixels(glyph.fImage);
1811 }
1812
1813 // Scale unscaledBitmap into dstBitmap.
1814 SkCanvas canvas(dstBitmap);
1815 if constexpr (kSkShowTextBlitCoverage) {
1816 canvas.clear(0x33FF0000);
1817 } else {
1818 canvas.clear(SK_ColorTRANSPARENT);
1819 }
1820 canvas.translate(-glyph.fLeft, -glyph.fTop);
1821 canvas.concat(bitmapTransform);
1822 canvas.translate(face->glyph->bitmap_left, -face->glyph->bitmap_top);
1823
1824 SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kNearest);
1825 canvas.drawImage(unscaledBitmap.asImage().get(), 0, 0, sampling, nullptr);
1826
1827 // If the destination is BW or LCD, convert from A8.
1828 if (SkMask::kBW_Format == maskFormat) {
1829 // Copy the A8 dstBitmap into the A1 glyph.fImage.
1830 SkMask dstMask = glyph.mask();
1831 packA8ToA1(dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
1832 } else if (SkMask::kLCD16_Format == maskFormat) {
1833 // Copy the A8 dstBitmap into the LCD16 glyph.fImage.
1834 uint8_t* src = dstBitmap.getAddr8(0, 0);
1835 uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
1836 for (int y = dstBitmap.height(); y --> 0;) {
1837 for (int x = 0; x < dstBitmap.width(); ++x) {
1838 dst[x] = grayToRGB16(src[x]);
1839 }
1840 dst = (uint16_t*)((char*)dst + glyph.rowBytes());
1841 src += dstBitmap.rowBytes();
1842 }
1843 }
1844 } break;
1845
1846 default:
1847 SkDEBUGFAIL("unknown glyph format");
1848 memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
1849 return;
1850 }
1851
1852 // We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
1853 // it is optional
1854 #if defined(SK_GAMMA_APPLY_TO_A8)
1855 if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
1856 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
1857 unsigned rowBytes = glyph.rowBytes();
1858
1859 for (int y = glyph.fHeight - 1; y >= 0; --y) {
1860 for (int x = glyph.fWidth - 1; x >= 0; --x) {
1861 dst[x] = fPreBlend.fG[dst[x]];
1862 }
1863 dst += rowBytes;
1864 }
1865 }
1866 #endif
1867 }
1868
1869 ///////////////////////////////////////////////////////////////////////////////
1870
1871 namespace {
1872
1873 class SkFTGeometrySink {
1874 SkPath* fPath;
1875 bool fStarted;
1876 FT_Vector fCurrent;
1877
goingTo(const FT_Vector * pt)1878 void goingTo(const FT_Vector* pt) {
1879 if (!fStarted) {
1880 fStarted = true;
1881 fPath->moveTo(SkFDot6ToScalar(fCurrent.x), -SkFDot6ToScalar(fCurrent.y));
1882 }
1883 fCurrent = *pt;
1884 }
1885
currentIsNot(const FT_Vector * pt)1886 bool currentIsNot(const FT_Vector* pt) {
1887 return fCurrent.x != pt->x || fCurrent.y != pt->y;
1888 }
1889
Move(const FT_Vector * pt,void * ctx)1890 static int Move(const FT_Vector* pt, void* ctx) {
1891 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
1892 if (self.fStarted) {
1893 self.fPath->close();
1894 self.fStarted = false;
1895 }
1896 self.fCurrent = *pt;
1897 return 0;
1898 }
1899
Line(const FT_Vector * pt,void * ctx)1900 static int Line(const FT_Vector* pt, void* ctx) {
1901 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
1902 if (self.currentIsNot(pt)) {
1903 self.goingTo(pt);
1904 self.fPath->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
1905 }
1906 return 0;
1907 }
1908
Quad(const FT_Vector * pt0,const FT_Vector * pt1,void * ctx)1909 static int Quad(const FT_Vector* pt0, const FT_Vector* pt1, void* ctx) {
1910 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
1911 if (self.currentIsNot(pt0) || self.currentIsNot(pt1)) {
1912 self.goingTo(pt1);
1913 self.fPath->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
1914 SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y));
1915 }
1916 return 0;
1917 }
1918
Cubic(const FT_Vector * pt0,const FT_Vector * pt1,const FT_Vector * pt2,void * ctx)1919 static int Cubic(const FT_Vector* pt0, const FT_Vector* pt1, const FT_Vector* pt2, void* ctx) {
1920 SkFTGeometrySink& self = *(SkFTGeometrySink*)ctx;
1921 if (self.currentIsNot(pt0) || self.currentIsNot(pt1) || self.currentIsNot(pt2)) {
1922 self.goingTo(pt2);
1923 self.fPath->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
1924 SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y),
1925 SkFDot6ToScalar(pt2->x), -SkFDot6ToScalar(pt2->y));
1926 }
1927 return 0;
1928 }
1929
1930 public:
SkFTGeometrySink(SkPath * path)1931 SkFTGeometrySink(SkPath* path) : fPath{path}, fStarted{false}, fCurrent{0,0} {}
1932
1933 inline static constexpr const FT_Outline_Funcs Funcs{
1934 /*move_to =*/ SkFTGeometrySink::Move,
1935 /*line_to =*/ SkFTGeometrySink::Line,
1936 /*conic_to =*/ SkFTGeometrySink::Quad,
1937 /*cubic_to =*/ SkFTGeometrySink::Cubic,
1938 /*shift = */ 0,
1939 /*delta =*/ 0,
1940 };
1941 };
1942
generateGlyphPathStatic(FT_Face face,SkPath * path)1943 bool generateGlyphPathStatic(FT_Face face, SkPath* path) {
1944 SkFTGeometrySink sink{path};
1945 if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE ||
1946 FT_Outline_Decompose(&face->glyph->outline, &SkFTGeometrySink::Funcs, &sink))
1947 {
1948 path->reset();
1949 return false;
1950 }
1951 path->close();
1952 return true;
1953 }
1954
generateFacePathStatic(FT_Face face,SkGlyphID glyphID,uint32_t loadGlyphFlags,SkPath * path)1955 bool generateFacePathStatic(FT_Face face, SkGlyphID glyphID, uint32_t loadGlyphFlags, SkPath* path){
1956 loadGlyphFlags |= FT_LOAD_BITMAP_METRICS_ONLY; // Don't decode any bitmaps.
1957 loadGlyphFlags |= FT_LOAD_NO_BITMAP; // Ignore embedded bitmaps.
1958 loadGlyphFlags &= ~FT_LOAD_RENDER; // Don't scan convert.
1959 loadGlyphFlags &= ~FT_LOAD_COLOR; // Ignore SVG.
1960 if (FT_Load_Glyph(face, glyphID, loadGlyphFlags)) {
1961 path->reset();
1962 return false;
1963 }
1964 return generateGlyphPathStatic(face, path);
1965 }
1966
1967 #ifdef TT_SUPPORT_COLRV1
generateFacePathCOLRv1(FT_Face face,SkGlyphID glyphID,SkPath * path)1968 bool generateFacePathCOLRv1(FT_Face face, SkGlyphID glyphID, SkPath* path) {
1969 uint32_t flags = 0;
1970 flags |= FT_LOAD_BITMAP_METRICS_ONLY; // Don't decode any bitmaps.
1971 flags |= FT_LOAD_NO_BITMAP; // Ignore embedded bitmaps.
1972 flags &= ~FT_LOAD_RENDER; // Don't scan convert.
1973 flags &= ~FT_LOAD_COLOR; // Ignore SVG.
1974 flags |= FT_LOAD_NO_HINTING;
1975 flags |= FT_LOAD_NO_AUTOHINT;
1976 flags |= FT_LOAD_IGNORE_TRANSFORM;
1977
1978 SkUniqueFTSize unscaledFtSize([face]() -> FT_Size {
1979 FT_Size size;
1980 FT_Error err = FT_New_Size(face, &size);
1981 if (err != 0) {
1982 SK_TRACEFTR(err, "FT_New_Size(%s) failed in generateFacePathStaticCOLRv1.",
1983 face->family_name);
1984 return nullptr;
1985 }
1986 return size;
1987 }());
1988
1989 if (!unscaledFtSize) {
1990 return false;
1991 }
1992
1993 FT_Size oldSize = face->size;
1994
1995 auto tryGeneratePath = [face, &unscaledFtSize, glyphID, flags, path]() {
1996 FT_Error err = 0;
1997
1998 err = FT_Activate_Size(unscaledFtSize.get());
1999 if (err != 0) {
2000 return false;
2001 }
2002
2003 err = FT_Set_Char_Size(face, SkIntToFDot6(face->units_per_EM),
2004 SkIntToFDot6(face->units_per_EM), 72, 72);
2005 if (err != 0) {
2006 return false;
2007 }
2008
2009 err = FT_Load_Glyph(face, glyphID, flags);
2010 if (err != 0) {
2011 path->reset();
2012 return false;
2013 }
2014
2015 if (!generateGlyphPathStatic(face, path)) {
2016 path->reset();
2017 return false;
2018 }
2019
2020 return true;
2021 };
2022
2023 bool pathGenerationResult = tryGeneratePath();
2024
2025 FT_Activate_Size(oldSize);
2026
2027 return pathGenerationResult;
2028 }
2029 #endif
2030
2031 } // namespace
2032
generateGlyphPath(FT_Face face,SkPath * path)2033 bool SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face, SkPath* path) {
2034 if (!generateGlyphPathStatic(face, path)) {
2035 return false;
2036 }
2037 if (face->glyph->outline.flags & FT_OUTLINE_OVERLAP) {
2038 Simplify(*path, path);
2039 // Simplify will return an even-odd path.
2040 // A stroke+fill (for fake bold) may be incorrect for even-odd.
2041 // https://github.com/flutter/flutter/issues/112546
2042 AsWinding(*path, path);
2043 }
2044 return true;
2045 }
2046
generateFacePath(FT_Face face,SkGlyphID glyphID,uint32_t loadGlyphFlags,SkPath * path)2047 bool SkScalerContext_FreeType_Base::generateFacePath(FT_Face face,
2048 SkGlyphID glyphID,
2049 uint32_t loadGlyphFlags,
2050 SkPath* path) {
2051 return generateFacePathStatic(face, glyphID, loadGlyphFlags, path);
2052 }
2053
2054 #ifdef TT_SUPPORT_COLRV1
computeColrV1GlyphBoundingBox(FT_Face face,SkGlyphID glyphID,SkRect * bounds)2055 bool SkScalerContext_FreeType_Base::computeColrV1GlyphBoundingBox(FT_Face face,
2056 SkGlyphID glyphID,
2057 SkRect* bounds) {
2058 SkMatrix ctm;
2059 *bounds = SkRect::MakeEmpty();
2060 VisitedSet activePaints;
2061 return colrv1_start_glyph_bounds(&ctm, bounds, face, glyphID,
2062 FT_COLOR_INCLUDE_ROOT_TRANSFORM, &activePaints);
2063 }
2064 #endif
2065