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