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