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