• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #include "src/utils/win/SkDWriteNTDDI_VERSION.h"
8 
9 #include "include/core/SkTypes.h"
10 #if defined(SK_BUILD_FOR_WIN)
11 
12 #undef GetGlyphIndices
13 
14 #include "include/codec/SkCodec.h"
15 #include "include/codec/SkPngDecoder.h"
16 #include "include/core/SkBBHFactory.h"
17 #include "include/core/SkBitmap.h"
18 #include "include/core/SkData.h"
19 #include "include/core/SkDrawable.h"
20 #include "include/core/SkFontMetrics.h"
21 #include "include/core/SkGraphics.h"
22 #include "include/core/SkImage.h"
23 #include "include/core/SkOpenTypeSVGDecoder.h"
24 #include "include/core/SkPath.h"
25 #include "include/core/SkPictureRecorder.h"
26 #include "include/effects/SkGradientShader.h"
27 #include "include/private/base/SkMutex.h"
28 #include "include/private/base/SkTo.h"
29 #include "src/base/SkEndian.h"
30 #include "src/base/SkScopeExit.h"
31 #include "src/base/SkSharedMutex.h"
32 #include "src/core/SkDraw.h"
33 #include "src/core/SkGlyph.h"
34 #include "src/core/SkMaskGamma.h"
35 #include "src/core/SkRasterClip.h"
36 #include "src/core/SkScalerContext.h"
37 #include "src/ports/SkScalerContext_win_dw.h"
38 #include "src/ports/SkTypeface_win_dw.h"
39 #include "src/sfnt/SkOTTable_EBLC.h"
40 #include "src/sfnt/SkOTTable_EBSC.h"
41 #include "src/sfnt/SkOTTable_gasp.h"
42 #include "src/sfnt/SkOTTable_maxp.h"
43 #include "src/utils/SkMatrix22.h"
44 #include "src/utils/win/SkDWrite.h"
45 #include "src/utils/win/SkDWriteGeometrySink.h"
46 #include "src/utils/win/SkHRESULT.h"
47 #include "src/utils/win/SkTScopedComPtr.h"
48 
49 #include <dwrite.h>
50 #include <dwrite_1.h>
51 #include <dwrite_3.h>
52 
53 namespace {
54 static inline const constexpr bool kSkShowTextBlitCoverage = false;
55 
56 /* Note:
57  * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe.
58  * The mutex returned from maybe_dw_mutex protects the calls that are
59  * problematic.
60  */
maybe_dw_mutex(DWriteFontTypeface & typeface)61 static SkSharedMutex* maybe_dw_mutex(DWriteFontTypeface& typeface) {
62     static SkSharedMutex mutex;
63     return typeface.fDWriteFontFace4 ? nullptr : &mutex;
64 }
65 
66 class SK_SCOPED_CAPABILITY Exclusive {
67 public:
68     explicit Exclusive(SkSharedMutex* maybe_lock) SK_ACQUIRE(*maybe_lock)
69         : fLock(maybe_lock) {
70         if (fLock) {
71             fLock->acquire();
72         }
73     }
SK_RELEASE_CAPABILITY()74     ~Exclusive() SK_RELEASE_CAPABILITY() {
75         if (fLock) {
76             fLock->release();
77         }
78     }
79 
80 private:
81     SkSharedMutex* fLock;
82 };
83 class SK_SCOPED_CAPABILITY Shared {
84 public:
85     explicit Shared(SkSharedMutex* maybe_lock) SK_ACQUIRE_SHARED(*maybe_lock)
86         : fLock(maybe_lock)  {
87         if (fLock) {
88             fLock->acquireShared();
89         }
90     }
91 
92     // You would think this should be SK_RELEASE_SHARED_CAPABILITY, but SK_SCOPED_CAPABILITY
93     // doesn't fully understand the difference between shared and exclusive.
94     // Please review https://reviews.llvm.org/D52578 for more information.
SK_RELEASE_CAPABILITY()95     ~Shared() SK_RELEASE_CAPABILITY() {
96         if (fLock) {
97             fLock->releaseShared();
98         }
99     }
100 
101 private:
102     SkSharedMutex* fLock;
103 };
104 
isLCD(const SkScalerContextRec & rec)105 static bool isLCD(const SkScalerContextRec& rec) {
106     return SkMask::kLCD16_Format == rec.fMaskFormat;
107 }
108 
is_hinted(DWriteFontTypeface * typeface)109 static bool is_hinted(DWriteFontTypeface* typeface) {
110     Exclusive l(maybe_dw_mutex(*typeface));
111     AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
112     if (!maxp.fExists) {
113         return false;
114     }
115     if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
116         return false;
117     }
118     if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
119         return false;
120     }
121     return (0 != maxp->version.tt.maxSizeOfInstructions);
122 }
123 
124 /** A GaspRange is inclusive, [min, max]. */
125 struct GaspRange {
126     using Behavior = SkOTTableGridAndScanProcedure::GaspRange::behavior;
GaspRange__anon0365400f0111::GaspRange127     GaspRange(int min, int max, int version, Behavior flags)
128         : fMin(min), fMax(max), fVersion(version), fFlags(flags) { }
129     int fMin;
130     int fMax;
131     int fVersion;
132     Behavior fFlags;
133 };
134 
get_gasp_range(DWriteFontTypeface * typeface,int size,GaspRange * range)135 bool get_gasp_range(DWriteFontTypeface* typeface, int size, GaspRange* range) {
136     AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
137     if (!gasp.fExists) {
138         return false;
139     }
140     if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
141         return false;
142     }
143     if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
144         gasp->version != SkOTTableGridAndScanProcedure::version1)
145     {
146         return false;
147     }
148 
149     uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
150     if (numRanges > 1024 ||
151         gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
152         sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
153     {
154         return false;
155     }
156 
157     const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
158             SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
159     int minPPEM = -1;
160     for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) {
161         int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM);
162         if (minPPEM < size && size <= maxPPEM) {
163             range->fMin = minPPEM + 1;
164             range->fMax = maxPPEM;
165             range->fVersion = SkEndian_SwapBE16(gasp->version);
166             range->fFlags = rangeTable->flags;
167             return true;
168         }
169         minPPEM = maxPPEM;
170     }
171     return false;
172 }
173 /** If the rendering mode for the specified 'size' is gridfit, then place
174  *  the gridfit range into 'range'. Otherwise, leave 'range' alone.
175  */
is_gridfit_only(GaspRange::Behavior flags)176 static bool is_gridfit_only(GaspRange::Behavior flags) {
177     return flags.raw.value == GaspRange::Behavior::Raw::GridfitMask;
178 }
179 
has_bitmap_strike(DWriteFontTypeface * typeface,GaspRange range)180 static bool has_bitmap_strike(DWriteFontTypeface* typeface, GaspRange range) {
181     Exclusive l(maybe_dw_mutex(*typeface));
182     {
183         AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
184         if (!eblc.fExists) {
185             return false;
186         }
187         if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
188             return false;
189         }
190         if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
191             return false;
192         }
193 
194         uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
195         if (numSizes > 1024 ||
196             eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
197                          sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
198         {
199             return false;
200         }
201 
202         const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
203                 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
204         for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
205             if (sizeTable->ppemX == sizeTable->ppemY &&
206                 range.fMin <= sizeTable->ppemX && sizeTable->ppemX <= range.fMax)
207             {
208                 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
209                 // to determine the actual number of glyphs with bitmaps.
210 
211                 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
212 
213                 // TODO: Ensure that the bitmaps are bi-level?
214                 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
215                     return true;
216                 }
217             }
218         }
219     }
220 
221     {
222         AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
223         if (!ebsc.fExists) {
224             return false;
225         }
226         if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
227             return false;
228         }
229         if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
230             return false;
231         }
232 
233         uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
234         if (numSizes > 1024 ||
235             ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
236                          sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
237         {
238             return false;
239         }
240 
241         const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
242                 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
243         for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
244             if (scaleTable->ppemX == scaleTable->ppemY &&
245                 range.fMin <= scaleTable->ppemX && scaleTable->ppemX <= range.fMax) {
246                 // EBSC tables are normally only found in bitmap only fonts.
247                 return true;
248             }
249         }
250     }
251 
252     return false;
253 }
254 
both_zero(SkScalar a,SkScalar b)255 static bool both_zero(SkScalar a, SkScalar b) {
256     return 0 == a && 0 == b;
257 }
258 
259 // returns false if there is any non-90-rotation or skew
is_axis_aligned(const SkScalerContextRec & rec)260 static bool is_axis_aligned(const SkScalerContextRec& rec) {
261     return 0 == rec.fPreSkewX &&
262            (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
263             both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
264 }
265 
266 }  //namespace
267 
SkScalerContext_DW(sk_sp<DWriteFontTypeface> typefaceRef,const SkScalerContextEffects & effects,const SkDescriptor * desc)268 SkScalerContext_DW::SkScalerContext_DW(sk_sp<DWriteFontTypeface> typefaceRef,
269                                        const SkScalerContextEffects& effects,
270                                        const SkDescriptor* desc)
271         : SkScalerContext(std::move(typefaceRef), effects, desc)
272 {
273     DWriteFontTypeface* typeface = this->getDWriteTypeface();
274     fGlyphCount = typeface->fDWriteFontFace->GetGlyphCount();
275 
276     // In general, all glyphs should use NATURAL_SYMMETRIC
277     // except when bi-level rendering is requested or there are embedded
278     // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
279     //
280     // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
281     // this. As a result, determine the actual size of the text and then see if
282     // there are any embedded bi-level bitmaps of that size. If there are, then
283     // force bitmaps by requesting bi-level rendering.
284     //
285     // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
286     // square pixels and only uses ppemY. Therefore the transform must track any
287     // non-uniform x-scale.
288     //
289     // Also, rotated glyphs should have the same absolute advance widths as
290     // horizontal glyphs and the subpixel flag should not affect glyph shapes.
291 
292     SkVector scale;
293     fRec.computeMatrices(SkScalerContextRec::PreMatrixScale::kVertical, &scale, &fSkXform);
294 
295     fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
296     fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
297     fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
298     fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
299     fXform.dx = 0;
300     fXform.dy = 0;
301 
302     // realTextSize is the actual device size we want (as opposed to the size the user requested).
303     // gdiTextSize is the size we request when GDI compatible.
304     // If the scale is negative, this means the matrix will do the flip anyway.
305     const SkScalar realTextSize = scale.fY;
306     // Due to floating point math, the lower bits are suspect. Round carefully.
307     SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
308     if (gdiTextSize == 0) {
309         gdiTextSize = SK_Scalar1;
310     }
311 
312     bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
313     bool treatLikeBitmap = false;
314     bool axisAlignedBitmap = false;
315     if (bitmapRequested) {
316         // When embedded bitmaps are requested, treat the entire range like
317         // a bitmap strike if the range is gridfit only and contains a bitmap.
318         int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
319         GaspRange range(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior());
320         if (get_gasp_range(typeface, bitmapPPEM, &range)) {
321             if (!is_gridfit_only(range.fFlags)) {
322                 range = GaspRange(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior());
323             }
324         }
325         treatLikeBitmap = has_bitmap_strike(typeface, range);
326 
327         axisAlignedBitmap = is_axis_aligned(fRec);
328     }
329 
330     GaspRange range(0, 0xFFFF, 0, GaspRange::Behavior());
331 
332     // If the user requested aliased, do so with aliased compatible metrics.
333     if (SkMask::kBW_Format == fRec.fMaskFormat) {
334         fTextSizeRender = gdiTextSize;
335         fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
336         fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
337         fTextSizeMeasure = gdiTextSize;
338         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
339 
340     // If we can use a bitmap, use gdi classic rendering and measurement.
341     // This will not always provide a bitmap, but matches expected behavior.
342     } else if (treatLikeBitmap && axisAlignedBitmap) {
343         fTextSizeRender = gdiTextSize;
344         fRenderingMode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
345         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
346         fTextSizeMeasure = gdiTextSize;
347         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
348 
349     // If rotated but the horizontal text could have used a bitmap,
350     // render high quality rotated glyphs but measure using bitmap metrics.
351     } else if (treatLikeBitmap) {
352         fTextSizeRender = gdiTextSize;
353         fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
354         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
355         fTextSizeMeasure = gdiTextSize;
356         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
357 
358     // If the font has a gasp table version 1, use it to determine symmetric rendering.
359     } else if (get_gasp_range(typeface, SkScalarRoundToInt(gdiTextSize), &range) &&
360                range.fVersion >= 1)
361     {
362         fTextSizeRender = realTextSize;
363         fRenderingMode = range.fFlags.field.SymmetricSmoothing
364                        ? DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
365                        : DWRITE_RENDERING_MODE_NATURAL;
366         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
367         fTextSizeMeasure = realTextSize;
368         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
369 
370     // If the requested size is above 20px or there are no bytecode hints, use symmetric rendering.
371     } else if (realTextSize > SkIntToScalar(20) || !is_hinted(typeface)) {
372         fTextSizeRender = realTextSize;
373         fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
374         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
375         fTextSizeMeasure = realTextSize;
376         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
377 
378     // Fonts with hints, no gasp or gasp version 0, and below 20px get non-symmetric rendering.
379     // Often such fonts have hints which were only tested with GDI ClearType classic.
380     // Some of these fonts rely on drop out control in the y direction in order to be legible.
381     // Tenor Sans
382     //    https://fonts.google.com/specimen/Tenor+Sans
383     // Gill Sans W04
384     //    https://cdn.leagueoflegends.com/lolkit/1.1.9/resources/fonts/gill-sans-w04-book.woff
385     //    https://na.leagueoflegends.com/en/news/game-updates/patch/patch-410-notes
386     // See https://crbug.com/385897
387     } else {
388         fTextSizeRender = gdiTextSize;
389         fRenderingMode = DWRITE_RENDERING_MODE_NATURAL;
390         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
391         fTextSizeMeasure = realTextSize;
392         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
393     }
394 
395     // DirectWrite2 allows for grayscale hinting.
396     fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
397     if (typeface->fFactory2 && typeface->fDWriteFontFace2 &&
398         SkMask::kA8_Format == fRec.fMaskFormat &&
399         !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag))
400     {
401         // DWRITE_TEXTURE_ALIASED_1x1 is now misnamed, it must also be used with grayscale.
402         fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
403         fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE;
404     }
405 
406     // DirectWrite2 allows hinting to be disabled.
407     fGridFitMode = DWRITE_GRID_FIT_MODE_ENABLED;
408     if (fRec.getHinting() == SkFontHinting::kNone) {
409         fGridFitMode = DWRITE_GRID_FIT_MODE_DISABLED;
410         if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) {
411             fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
412         }
413     }
414 
415     if (this->isLinearMetrics()) {
416         fTextSizeMeasure = realTextSize;
417         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
418     }
419 
420     // The GDI measuring modes don't seem to work well with CBDT fonts (DWrite.dll 10.0.18362.836).
421     if (fMeasuringMode != DWRITE_MEASURING_MODE_NATURAL) {
422         constexpr UINT32 CBDTTag = DWRITE_MAKE_OPENTYPE_TAG('C','B','D','T');
423         AutoDWriteTable CBDT(typeface->fDWriteFontFace.get(), CBDTTag);
424         if (CBDT.fExists) {
425             fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
426         }
427     }
428 }
429 
~SkScalerContext_DW()430 SkScalerContext_DW::~SkScalerContext_DW() {
431 }
432 
433 #if DWRITE_CORE || (defined(NTDDI_WIN11_ZN) && NTDDI_VERSION >= NTDDI_WIN11_ZN)
434 
435 namespace {
sk_color_from(DWRITE_COLOR_F const & color)436 SkColor4f sk_color_from(DWRITE_COLOR_F const& color) {
437     // DWRITE_COLOR_F and SkColor4f are laid out the same and this should be a no-op.
438     return SkColor4f{ color.r, color.g, color.b, color.a };
439 }
dw_color_from(SkColor4f const & color)440 DWRITE_COLOR_F dw_color_from(SkColor4f const& color) {
441     // DWRITE_COLOR_F and SkColor4f are laid out the same and this should be a no-op.
442     // Avoid brace initialization as DWRITE_COLOR_F can be defined as four floats (dxgitype.h,
443     // d3d9types.h) or four unions of two floats (dwrite_2.h, d3dtypes.h). The type changed in
444     // Direct3D 10, but the change does not appear to be documented.
445     DWRITE_COLOR_F dwColor;
446     dwColor.r = color.fR;
447     dwColor.g = color.fG;
448     dwColor.b = color.fB;
449     dwColor.a = color.fA;
450     return dwColor;
451 }
452 
sk_rect_from(D2D_RECT_F const & rect)453 SkRect sk_rect_from(D2D_RECT_F const& rect) {
454     // D2D_RECT_F and SkRect are both y-down and laid the same so this should be a no-op.
455     return SkRect{ rect.left, rect.top, rect.right, rect.bottom };
456 }
D2D_RECT_F_is_empty(const D2D_RECT_F & r)457 constexpr bool D2D_RECT_F_is_empty(const D2D_RECT_F& r) {
458     return r.right <= r.left || r.bottom <= r.top;
459 }
460 
sk_matrix_from(DWRITE_MATRIX const & m)461 SkMatrix sk_matrix_from(DWRITE_MATRIX const& m) {
462     // DWRITE_MATRIX and SkMatrix are y-down. However DWRITE_MATRIX is affine only.
463     return SkMatrix::MakeAll(
464         m.m11, m.m21, m.dx,
465         m.m12, m.m22, m.dy,
466         0, 0, 1);
467 }
468 
sk_tile_mode_from(D2D1_EXTEND_MODE extendMode)469 SkTileMode sk_tile_mode_from(D2D1_EXTEND_MODE extendMode) {
470     switch (extendMode) {
471     case D2D1_EXTEND_MODE_CLAMP:
472         return SkTileMode::kClamp;
473     case D2D1_EXTEND_MODE_WRAP:
474         return SkTileMode::kRepeat;
475     case D2D1_EXTEND_MODE_MIRROR:
476         return SkTileMode::kMirror;
477     default:
478         return SkTileMode::kClamp;
479     }
480 }
481 
sk_blend_mode_from(DWRITE_COLOR_COMPOSITE_MODE compositeMode)482 SkBlendMode sk_blend_mode_from(DWRITE_COLOR_COMPOSITE_MODE compositeMode) {
483     switch (compositeMode) {
484     case DWRITE_COLOR_COMPOSITE_CLEAR:
485         return SkBlendMode::kClear;
486     case DWRITE_COLOR_COMPOSITE_SRC:
487         return SkBlendMode::kSrc;
488     case DWRITE_COLOR_COMPOSITE_DEST:
489         return SkBlendMode::kDst;
490     case DWRITE_COLOR_COMPOSITE_SRC_OVER:
491         return SkBlendMode::kSrcOver;
492     case DWRITE_COLOR_COMPOSITE_DEST_OVER:
493         return SkBlendMode::kDstOver;
494     case DWRITE_COLOR_COMPOSITE_SRC_IN:
495         return SkBlendMode::kSrcIn;
496     case DWRITE_COLOR_COMPOSITE_DEST_IN:
497         return SkBlendMode::kDstIn;
498     case DWRITE_COLOR_COMPOSITE_SRC_OUT:
499         return SkBlendMode::kSrcOut;
500     case DWRITE_COLOR_COMPOSITE_DEST_OUT:
501         return SkBlendMode::kDstOut;
502     case DWRITE_COLOR_COMPOSITE_SRC_ATOP:
503         return SkBlendMode::kSrcATop;
504     case DWRITE_COLOR_COMPOSITE_DEST_ATOP:
505         return SkBlendMode::kDstATop;
506     case DWRITE_COLOR_COMPOSITE_XOR:
507         return SkBlendMode::kXor;
508     case DWRITE_COLOR_COMPOSITE_PLUS:
509         return SkBlendMode::kPlus;
510 
511     case DWRITE_COLOR_COMPOSITE_SCREEN:
512         return SkBlendMode::kScreen;
513     case DWRITE_COLOR_COMPOSITE_OVERLAY:
514         return SkBlendMode::kOverlay;
515     case DWRITE_COLOR_COMPOSITE_DARKEN:
516         return SkBlendMode::kDarken;
517     case DWRITE_COLOR_COMPOSITE_LIGHTEN:
518         return SkBlendMode::kLighten;
519     case DWRITE_COLOR_COMPOSITE_COLOR_DODGE:
520         return SkBlendMode::kColorDodge;
521     case DWRITE_COLOR_COMPOSITE_COLOR_BURN:
522         return SkBlendMode::kColorBurn;
523     case DWRITE_COLOR_COMPOSITE_HARD_LIGHT:
524         return SkBlendMode::kHardLight;
525     case DWRITE_COLOR_COMPOSITE_SOFT_LIGHT:
526         return SkBlendMode::kSoftLight;
527     case DWRITE_COLOR_COMPOSITE_DIFFERENCE:
528         return SkBlendMode::kDifference;
529     case DWRITE_COLOR_COMPOSITE_EXCLUSION:
530         return SkBlendMode::kExclusion;
531     case DWRITE_COLOR_COMPOSITE_MULTIPLY:
532         return SkBlendMode::kMultiply;
533 
534     case DWRITE_COLOR_COMPOSITE_HSL_HUE:
535         return SkBlendMode::kHue;
536     case DWRITE_COLOR_COMPOSITE_HSL_SATURATION:
537         return SkBlendMode::kSaturation;
538     case DWRITE_COLOR_COMPOSITE_HSL_COLOR:
539         return SkBlendMode::kColor;
540     case DWRITE_COLOR_COMPOSITE_HSL_LUMINOSITY:
541         return SkBlendMode::kLuminosity;
542     default:
543         return SkBlendMode::kDst;
544     }
545 }
546 
SkVectorProjection(SkPoint a,SkPoint b)547 inline SkPoint SkVectorProjection(SkPoint a, SkPoint b) {
548     SkScalar length = b.length();
549     if (!length) {
550         return SkPoint();
551     }
552     SkPoint bNormalized = b;
553     bNormalized.normalize();
554     bNormalized.scale(SkPoint::DotProduct(a, b) / length);
555     return bNormalized;
556 }
557 
558 // This linear interpolation is used for calculating a truncated color line in special edge cases.
559 // This interpolation needs to be kept in sync with what the gradient shader would normally do when
560 // truncating and drawing color lines. When drawing into N32 surfaces, this is expected to be true.
561 // If that changes, or if we support other color spaces in CPAL tables at some point, this needs to
562 // be looked at.
lerpSkColor(D2D1_COLOR_F c0,D2D1_COLOR_F c1,float t)563 D2D1_COLOR_F lerpSkColor(D2D1_COLOR_F c0, D2D1_COLOR_F c1, float t) {
564     // Due to the floating point calculation in the caller, when interpolating between very narrow
565     // stops, we may get values outside the interpolation range, guard against these.
566     if (t < 0) {
567         return c0;
568     }
569     if (t > 1) {
570         return c1;
571     }
572     const auto c0_4f = skvx::float4(c0.r, c0.g, c0.b, c0.a),
573                c1_4f = skvx::float4(c1.r, c1.g, c1.b, c1.a),
574                 c_4f = c0_4f + (c1_4f - c0_4f) * t;
575     D2D1_COLOR_F r;
576     c_4f.store(&r);
577     return r;
578 }
579 
580 enum TruncateStops {
581     TruncateStart,
582     TruncateEnd,
583 };
584 // Truncate a vector of color stops at a previously computed stop position and insert at that
585 // position the color interpolated between the surrounding stops.
truncateToStopInterpolating(SkScalar zeroRadiusStop,std::vector<D2D1_GRADIENT_STOP> & stops,TruncateStops truncateStops)586 void truncateToStopInterpolating(SkScalar zeroRadiusStop,
587                                  std::vector<D2D1_GRADIENT_STOP>& stops,
588                                  TruncateStops truncateStops) {
589     if (stops.size() <= 1u ||
590         zeroRadiusStop < stops.front().position || stops.back().position < zeroRadiusStop) {
591         return;
592     }
593 
594     auto lcmp = [](D2D1_GRADIENT_STOP const& stop, SkScalar position) {
595         return stop.position < position;
596     };
597     auto ucmp = [](SkScalar position, D2D1_GRADIENT_STOP const& stop) {
598         return position < stop.position;
599     };
600     size_t afterIndex = (truncateStops == TruncateStart)
601         ? std::lower_bound(stops.begin(), stops.end(), zeroRadiusStop, lcmp) - stops.begin()
602         : std::upper_bound(stops.begin(), stops.end(), zeroRadiusStop, ucmp) - stops.begin();
603 
604     const float t = (zeroRadiusStop - stops[afterIndex - 1].position) /
605         (stops[afterIndex].position - stops[afterIndex - 1].position);
606     D2D1_COLOR_F lerpColor = lerpSkColor(stops[afterIndex - 1].color, stops[afterIndex].color, t);
607 
608     if (truncateStops == TruncateStart) {
609         stops.erase(stops.begin(), stops.begin() + afterIndex);
610         stops.insert(stops.begin(), { 0, lerpColor });
611     } else {
612         stops.erase(stops.begin() + afterIndex, stops.end());
613         stops.insert(stops.end(), { 1, lerpColor });
614     }
615 }
616 } // namespace
617 
drawColorV1Paint(SkCanvas & canvas,IDWritePaintReader & reader,DWRITE_PAINT_ELEMENT const & element)618 bool SkScalerContext_DW::drawColorV1Paint(SkCanvas& canvas,
619                                           IDWritePaintReader& reader,
620                                           DWRITE_PAINT_ELEMENT const & element)
621 {
622     // Helper to draw the specified number of children.
623     auto drawChildren = [&](uint32_t childCount) -> bool {
624         if (childCount != 0) {
625             DWRITE_PAINT_ELEMENT childElement;
626             HRB(reader.MoveToFirstChild(&childElement));
627             this->drawColorV1Paint(canvas, reader, childElement);
628 
629             for (uint32_t i = 1; i < childCount; i++) {
630                 HRB(reader.MoveToNextSibling(&childElement));
631                 this->drawColorV1Paint(canvas, reader, childElement);
632             }
633 
634             HRB(reader.MoveToParent());
635         }
636         return true;
637     };
638 
639     SkAutoCanvasRestore restoreCanvas(&canvas, true);
640     switch (element.paintType) {
641     case DWRITE_PAINT_TYPE_NONE:
642         return true;
643 
644     case DWRITE_PAINT_TYPE_LAYERS: {
645         // A layers paint element has a variable number of children.
646         return drawChildren(element.paint.layers.childCount);
647     }
648 
649     case DWRITE_PAINT_TYPE_SOLID_GLYPH: {
650         // A solid glyph paint element has no children.
651         // glyphIndex, color.value, color.paletteEntryIndex, color.alpha, color.colorAttributes
652         auto const& solidGlyph = element.paint.solidGlyph;
653 
654         SkPath path;
655         SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
656         HRBM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
657              "Could not create geometry to path converter.");
658         UINT16 glyphId = SkTo<UINT16>(solidGlyph.glyphIndex);
659         {
660             Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
661             HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
662                      SkScalarToFloat(fTextSizeRender),
663                      &glyphId,
664                      nullptr, //advances
665                      nullptr, //offsets
666                      1, //num glyphs
667                      FALSE, //sideways
668                      FALSE, //rtl
669                      geometryToPath.get()),
670                  "Could not create glyph outline.");
671         }
672 
673         path.transform(SkMatrix::Scale(1.0f / fTextSizeRender, 1.0f / fTextSizeRender));
674         SkPaint skPaint;
675         skPaint.setColor4f(sk_color_from(solidGlyph.color.value));
676         skPaint.setAntiAlias(fRenderingMode != DWRITE_RENDERING_MODE_ALIASED);
677         canvas.drawPath(path, skPaint);
678         return true;
679     }
680 
681     case DWRITE_PAINT_TYPE_SOLID: {
682         // A solid paint element has no children.
683         // value, paletteEntryIndex, alphaMultiplier, colorAttributes
684         SkPaint skPaint;
685         skPaint.setColor4f(sk_color_from(element.paint.solid.value));
686         canvas.drawPaint(skPaint);
687         return true;
688     }
689 
690     case DWRITE_PAINT_TYPE_LINEAR_GRADIENT: {
691         auto const& linearGradient = element.paint.linearGradient;
692         // A linear gradient paint element has no children.
693         // x0, y0, x1, y1, x2, y2, extendMode, gradientStopCount, [colorStops]
694 
695         if (linearGradient.gradientStopCount == 0) {
696             return true;
697         }
698         std::vector<D2D1_GRADIENT_STOP> stops;
699         stops.resize(linearGradient.gradientStopCount);
700 
701         // If success stops will be ordered.
702         HRBM(reader.GetGradientStops(0, stops.size(), stops.data()),
703              "Could not get linear gradient stops.");
704         SkPaint skPaint;
705         if (stops.size() == 1) {
706             skPaint.setColor4f(sk_color_from(stops[0].color));
707             canvas.drawPaint(skPaint);
708             return true;
709         }
710         SkPoint linePositions[2] = { {linearGradient.x0, linearGradient.y0},
711                                      {linearGradient.x1, linearGradient.y1} };
712         SkPoint p0 = linePositions[0];
713         SkPoint p1 = linePositions[1];
714         SkPoint p2 = SkPoint::Make(linearGradient.x2, linearGradient.y2);
715 
716         // If p0p1 or p0p2 are degenerate probably nothing should be drawn.
717         // If p0p1 and p0p2 are parallel then one side is the first color and the other side is
718         // the last color, depending on the direction.
719         // For now, just use the first color.
720         if (p1 == p0 || p2 == p0 || !SkPoint::CrossProduct(p1 - p0, p2 - p0)) {
721             skPaint.setColor4f(sk_color_from(stops[0].color));
722             canvas.drawPaint(skPaint);
723             return true;
724         }
725 
726         // Follow implementation note in nanoemoji:
727         // https://github.com/googlefonts/nanoemoji/blob/0ac6e7bb4d8202db692574d8530a9b643f1b3b3c/src/nanoemoji/svg.py#L188
728         // to compute a new gradient end point P3 as the orthogonal
729         // projection of the vector from p0 to p1 onto a line perpendicular
730         // to line p0p2 and passing through p0.
731         SkVector perpendicularToP2P0 = (p2 - p0);
732         perpendicularToP2P0 = SkPoint::Make( perpendicularToP2P0.y(),
733                                             -perpendicularToP2P0.x());
734         SkVector p3 = p0 + SkVectorProjection((p1 - p0), perpendicularToP2P0);
735         linePositions[1] = p3;
736 
737         // Project/scale points according to stop extrema along p0p3 line,
738         // p3 being the result of the projection above, then scale stops to
739         // to [0, 1] range so that repeat modes work.  The Skia linear
740         // gradient shader performs the repeat modes over the 0 to 1 range,
741         // that's why we need to scale the stops to within that range.
742         SkTileMode tileMode = sk_tile_mode_from(SkTo<D2D1_EXTEND_MODE>(linearGradient.extendMode));
743         SkScalar colorStopRange = stops.back().position - stops.front().position;
744         // If the color stops are all at the same offset position, repeat and reflect modes
745         // become meaningless.
746         if (colorStopRange == 0.f) {
747             if (tileMode != SkTileMode::kClamp) {
748                 //skPaint.setColor(SK_ColorTRANSPARENT);
749                 return true;
750             } else {
751                 // Insert duplicated fake color stop in pad case at +1.0f to enable the projection
752                 // of circles for an originally 0-length color stop range. Adding this stop will
753                 // paint the equivalent gradient, because: All font specified color stops are in the
754                 // same spot, mode is pad, so everything before this spot is painted with the first
755                 // color, everything after this spot is painted with the last color. Not adding this
756                 // stop will skip the projection and result in specifying non-normalized color stops
757                 // to the shader.
758                 stops.push_back({ stops.back().position + 1.0f, stops.back().color });
759                 colorStopRange = 1.0f;
760             }
761         }
762         SkASSERT(colorStopRange != 0.f);
763 
764         // If the colorStopRange is 0 at this point, the default behavior of the shader is to
765         // clamp to 1 color stops that are above 1, clamp to 0 for color stops that are below 0,
766         // and repeat the outer color stops at 0 and 1 if the color stops are inside the
767         // range. That will result in the correct rendering.
768         if ((colorStopRange != 1 || stops.front().position != 0.f)) {
769             SkVector p0p3 = p3 - p0;
770             SkVector p0Offset = p0p3;
771             p0Offset.scale(stops.front().position);
772             SkVector p1Offset = p0p3;
773             p1Offset.scale(stops.back().position);
774 
775             linePositions[0] = p0 + p0Offset;
776             linePositions[1] = p0 + p1Offset;
777 
778             SkScalar scaleFactor = 1 / colorStopRange;
779             SkScalar startOffset = stops.front().position;
780             for (D2D1_GRADIENT_STOP& stop : stops) {
781                 stop.position = (stop.position - startOffset) * scaleFactor;
782             }
783         }
784 
785         std::unique_ptr<SkColor4f[]> skColors(new SkColor4f[stops.size()]);
786         std::unique_ptr<SkScalar[]> skStops(new SkScalar[stops.size()]);
787         for (size_t i = 0; i < stops.size(); ++i) {
788             skColors[i] = sk_color_from(stops[i].color);
789             skStops[i] = stops[i].position;
790         }
791 
792         sk_sp<SkShader> shader(SkGradientShader::MakeLinear(
793             linePositions,
794             skColors.get(), SkColorSpace::MakeSRGB(), skStops.get(), stops.size(),
795             tileMode,
796             SkGradientShader::Interpolation{
797                 SkGradientShader::Interpolation::InPremul::kNo,
798                 SkGradientShader::Interpolation::ColorSpace::kSRGB,
799                 SkGradientShader::Interpolation::HueMethod::kShorter
800             },
801             nullptr));
802 
803         SkASSERT(shader);
804         // An opaque color is needed to ensure the gradient is not modulated by alpha.
805         skPaint.setColor(SK_ColorBLACK);
806         skPaint.setShader(shader);
807         canvas.drawPaint(skPaint);
808         return true;
809     }
810 
811     case DWRITE_PAINT_TYPE_RADIAL_GRADIENT: {
812         auto const& radialGradient = element.paint.radialGradient;
813         // A radial gradient paint element has no children.
814         // x0, y0, radius0, x1, y1, radius1, extendMode, gradientStopCount, [colorsStops]
815 
816         SkPoint start = SkPoint::Make(radialGradient.x0, radialGradient.y0);
817         SkScalar startRadius = radialGradient.radius0;
818         SkPoint end = SkPoint::Make(radialGradient.x1, radialGradient.y1);
819         SkScalar endRadius = radialGradient.radius1;
820 
821         if (radialGradient.gradientStopCount == 0) {
822             return true;
823         }
824         std::vector<D2D1_GRADIENT_STOP> stops;
825         stops.resize(radialGradient.gradientStopCount);
826 
827         // If success stops will be ordered.
828         HRBM(reader.GetGradientStops(0, stops.size(), stops.data()),
829              "Could not get radial gradient stops.");
830         SkPaint skPaint;
831         if (stops.size() == 1) {
832             skPaint.setColor4f(sk_color_from(stops[0].color));
833             canvas.drawPaint(skPaint);
834             return true;
835         }
836 
837         SkScalar colorStopRange = stops.back().position - stops.front().position;
838         SkTileMode tileMode = sk_tile_mode_from(SkTo<D2D1_EXTEND_MODE>(radialGradient.extendMode));
839 
840         if (colorStopRange == 0.f) {
841             if (tileMode != SkTileMode::kClamp) {
842                 //skPaint.setColor(SK_ColorTRANSPARENT);
843                 return true;
844             } else {
845                 // Insert duplicated fake color stop in pad case at +1.0f to enable the projection
846                 // of circles for an originally 0-length color stop range. Adding this stop will
847                 // paint the equivalent gradient, because: All font specified color stops are in the
848                 // same spot, mode is pad, so everything before this spot is painted with the first
849                 // color, everything after this spot is painted with the last color. Not adding this
850                 // stop will skip the projection and result in specifying non-normalized color stops
851                 // to the shader.
852                 stops.push_back({ stops.back().position + 1.0f, stops.back().color });
853                 colorStopRange = 1.0f;
854             }
855         }
856         SkASSERT(colorStopRange != 0.f);
857 
858         // If the colorStopRange is 0 at this point, the default behavior of the shader is to
859         // clamp to 1 color stops that are above 1, clamp to 0 for color stops that are below 0,
860         // and repeat the outer color stops at 0 and 1 if the color stops are inside the
861         // range. That will result in the correct rendering.
862         if (colorStopRange != 1 || stops.front().position != 0.f) {
863             // For the Skia two-point caonical shader to understand the
864             // COLRv1 color stops we need to scale stops to 0 to 1 range and
865             // interpolate new centers and radii. Otherwise the shader
866             // clamps stops outside the range to 0 and 1 (larger interval)
867             // or repeats the outer stops at 0 and 1 if the (smaller
868             // interval).
869             SkVector startToEnd = end - start;
870             SkScalar radiusDiff = endRadius - startRadius;
871             SkScalar scaleFactor = 1 / colorStopRange;
872             SkScalar stopsStartOffset = stops.front().position;
873 
874             SkVector startOffset = startToEnd;
875             startOffset.scale(stops.front().position);
876             SkVector endOffset = startToEnd;
877             endOffset.scale(stops.back().position);
878 
879             // The order of the following computations is important in order to avoid
880             // overwriting start or startRadius before the second reassignment.
881             end = start + endOffset;
882             start = start + startOffset;
883             endRadius = startRadius + radiusDiff * stops.back().position;
884             startRadius = startRadius + radiusDiff * stops.front().position;
885 
886             for (auto& stop : stops) {
887                 stop.position = (stop.position - stopsStartOffset) * scaleFactor;
888             }
889         }
890 
891         // For negative radii, interpolation is needed to prepare parameters suitable
892         // for invoking the shader. Implementation below as resolution discussed in
893         // https://github.com/googlefonts/colr-gradients-spec/issues/367.
894         // Truncate to manually interpolated color for tile mode clamp, otherwise
895         // calculate positive projected circles.
896         if (startRadius < 0 || endRadius < 0) {
897             if (startRadius == endRadius && startRadius < 0) {
898                 //skPaint.setColor(SK_ColorTRANSPARENT);
899                 return true;
900             }
901 
902             if (tileMode == SkTileMode::kClamp) {
903                 SkVector startToEnd = end - start;
904                 SkScalar radiusDiff = endRadius - startRadius;
905                 SkScalar zeroRadiusStop = 0.f;
906                 TruncateStops truncateSide = TruncateStart;
907                 if (startRadius < 0) {
908                     truncateSide = TruncateStart;
909 
910                     // Compute color stop position where radius is = 0.  After the scaling
911                     // of stop positions to the normal 0,1 range that we have done above,
912                     // the size of the radius as a function of the color stops is: r(x) = r0
913                     // + x*(r1-r0) Solving this function for r(x) = 0, we get: x = -r0 /
914                     // (r1-r0)
915                     zeroRadiusStop = -startRadius / (endRadius - startRadius);
916                     startRadius = 0.f;
917                     SkVector startEndDiff = end - start;
918                     startEndDiff.scale(zeroRadiusStop);
919                     start = start + startEndDiff;
920                 }
921 
922                 if (endRadius < 0) {
923                     truncateSide = TruncateEnd;
924                     zeroRadiusStop = -startRadius / (endRadius - startRadius);
925                     endRadius = 0.f;
926                     SkVector startEndDiff = end - start;
927                     startEndDiff.scale(1 - zeroRadiusStop);
928                     end = end - startEndDiff;
929                 }
930 
931                 if (!(startRadius == 0 && endRadius == 0)) {
932                     truncateToStopInterpolating(zeroRadiusStop, stops, truncateSide);
933                 } else {
934                     // If both radii have become negative and where clamped to 0, we need to
935                     // produce a single color cone, otherwise the shader colors the whole
936                     // plane in a single color when two radii are specified as 0.
937                     if (radiusDiff > 0) {
938                         end = start + startToEnd;
939                         endRadius = radiusDiff;
940                         stops.erase(stops.begin(), stops.end() - 1);
941                     } else {
942                         start -= startToEnd;
943                         startRadius = -radiusDiff;
944                         stops.erase(stops.begin() + 1, stops.end());
945                     }
946                 }
947             } else {
948                 if (startRadius < 0 || endRadius < 0) {
949                     auto roundIntegerMultiple = [](SkScalar factorZeroCrossing,
950                         SkTileMode tileMode) {
951                             int roundedMultiple = factorZeroCrossing > 0
952                                 ? ceilf(factorZeroCrossing)
953                                 : floorf(factorZeroCrossing) - 1;
954                             if (tileMode == SkTileMode::kMirror && roundedMultiple % 2 != 0) {
955                                 roundedMultiple += roundedMultiple < 0 ? -1 : 1;
956                             }
957                             return roundedMultiple;
958                     };
959 
960                     SkVector startToEnd = end - start;
961                     SkScalar radiusDiff = endRadius - startRadius;
962                     SkScalar factorZeroCrossing = (startRadius / (startRadius - endRadius));
963                     bool inRange = 0.f <= factorZeroCrossing && factorZeroCrossing <= 1.0f;
964                     SkScalar direction = inRange && radiusDiff < 0 ? -1.0f : 1.0f;
965                     SkScalar circleProjectionFactor =
966                         roundIntegerMultiple(factorZeroCrossing * direction, tileMode);
967                     startToEnd.scale(circleProjectionFactor);
968                     startRadius += circleProjectionFactor * radiusDiff;
969                     endRadius += circleProjectionFactor * radiusDiff;
970                     start += startToEnd;
971                     end += startToEnd;
972                 }
973             }
974         }
975 
976         std::unique_ptr<SkColor4f[]> skColors(new SkColor4f[stops.size()]);
977         std::unique_ptr<SkScalar[]> skStops(new SkScalar[stops.size()]);
978         for (size_t i = 0; i < stops.size(); ++i) {
979             skColors[i] = sk_color_from(stops[i].color);
980             skStops[i] = stops[i].position;
981         }
982 
983         // An opaque color is needed to ensure the gradient is not modulated by alpha.
984         skPaint.setColor(SK_ColorBLACK);
985         skPaint.setShader(SkGradientShader::MakeTwoPointConical(
986             start, startRadius, end, endRadius,
987             skColors.get(), SkColorSpace::MakeSRGB(), skStops.get(), stops.size(),
988             tileMode,
989             SkGradientShader::Interpolation{
990                 SkGradientShader::Interpolation::InPremul::kNo,
991                 SkGradientShader::Interpolation::ColorSpace::kSRGB,
992                 SkGradientShader::Interpolation::HueMethod::kShorter
993             },
994             nullptr));
995         canvas.drawPaint(skPaint);
996         return true;
997     }
998 
999     case DWRITE_PAINT_TYPE_SWEEP_GRADIENT: {
1000         auto const& sweepGradient = element.paint.sweepGradient;
1001         // A sweep gradient paint element has no children.
1002         // centerX, centerY, startAngle, endAngle, extendMode, gradientStopCount, [colorStops]
1003 
1004         if (sweepGradient.gradientStopCount == 0) {
1005             return true;
1006         }
1007         std::vector<D2D1_GRADIENT_STOP> stops;
1008         stops.resize(sweepGradient.gradientStopCount);
1009 
1010         // If success stops will be ordered.
1011         HRBM(reader.GetGradientStops(0, stops.size(), stops.data()),
1012              "Could not get sweep gradient stops");
1013         SkPaint skPaint;
1014         if (stops.size() == 1) {
1015             skPaint.setColor4f(sk_color_from(stops[0].color));
1016             canvas.drawPaint(skPaint);
1017             return true;
1018         }
1019 
1020         SkPoint center = SkPoint::Make(sweepGradient.centerX, sweepGradient.centerY);
1021 
1022         SkScalar startAngle = sweepGradient.startAngle;
1023         SkScalar endAngle = sweepGradient.endAngle;
1024         // OpenType 1.9.1 adds a shift to the angle to ease specification of a 0 to 360
1025         // degree sweep. This appears to already be applied by DW.
1026         //startAngle += 180.0f;
1027         //endAngle += 180.0f;
1028 
1029         // An opaque color is needed to ensure the gradient is not modulated by alpha.
1030         skPaint.setColor(SK_ColorBLACK);
1031 
1032         // New (Var)SweepGradient implementation compliant with OpenType 1.9.1 from here.
1033 
1034         // The shader expects stops from 0 to 1, so we need to account for
1035         // minimum and maximum stop positions being different from 0 and
1036         // 1. We do that by scaling minimum and maximum stop positions to
1037         // the 0 to 1 interval and scaling the angles inverse proportionally.
1038 
1039         // 1) Scale angles to their equivalent positions if stops were from 0 to 1.
1040 
1041         SkScalar sectorAngle = endAngle - startAngle;
1042         SkTileMode tileMode = sk_tile_mode_from(SkTo<D2D1_EXTEND_MODE>(sweepGradient.extendMode));
1043         if (sectorAngle == 0 && tileMode != SkTileMode::kClamp) {
1044             // "If the ColorLine's extend mode is reflect or repeat and start and end angle
1045             // are equal, nothing is drawn.".
1046             //skPaint.setColor(SK_ColorTRANSPARENT);
1047             return true;
1048         }
1049 
1050         SkScalar startAngleScaled = startAngle + sectorAngle * stops.front().position;
1051         SkScalar endAngleScaled = startAngle + sectorAngle * stops.back().position;
1052 
1053         // 2) Scale stops accordingly to 0 to 1 range.
1054 
1055         float colorStopRange = stops.back().position - stops.front().position;
1056         if (colorStopRange == 0.f) {
1057             if (tileMode != SkTileMode::kClamp) {
1058                 //skPaint.setColor(SK_ColorTRANSPARENT);
1059                 return true;
1060             } else {
1061                 // Insert duplicated fake color stop in pad case at +1.0f to feed the shader correct
1062                 // values and enable painting a pad sweep gradient with two colors. Adding this stop
1063                 // will paint the equivalent gradient, because: All font specified color stops are
1064                 // in the same spot, mode is pad, so everything before this spot is painted with the
1065                 // first color, everything after this spot is painted with the last color. Not
1066                 // adding this stop will skip the projection and result in specifying non-normalized
1067                 // color stops to the shader.
1068                 stops.push_back({ stops.back().position + 1.0f, stops.back().color });
1069                 colorStopRange = 1.0f;
1070             }
1071         }
1072 
1073         SkScalar scaleFactor = 1 / colorStopRange;
1074         SkScalar startOffset = stops.front().position;
1075 
1076         for (D2D1_GRADIENT_STOP& stop : stops) {
1077             stop.position = (stop.position - startOffset) * scaleFactor;
1078         }
1079 
1080         /* https://docs.microsoft.com/en-us/typography/opentype/spec/colr#sweep-gradients
1081         * "The angles are expressed in counter-clockwise degrees from
1082         * the direction of the positive x-axis on the design
1083         * grid. [...]  The color line progresses from the start angle
1084         * to the end angle in the counter-clockwise direction;" -
1085         * Convert angles and stops from counter-clockwise to clockwise
1086         * for the shader if the gradient is not already reversed due to
1087         * start angle being larger than end angle. */
1088         startAngleScaled = 360.f - startAngleScaled;
1089         endAngleScaled = 360.f - endAngleScaled;
1090         if (startAngleScaled >= endAngleScaled) {
1091             std::swap(startAngleScaled, endAngleScaled);
1092             std::reverse(stops.begin(), stops.end());
1093             for (auto& stop : stops) {
1094                 stop.position = 1.0f - stop.position;
1095             }
1096         }
1097 
1098         std::unique_ptr<SkColor4f[]> skColors(new SkColor4f[stops.size()]);
1099         std::unique_ptr<SkScalar[]> skStops(new SkScalar[stops.size()]);
1100         for (size_t i = 0; i < stops.size(); ++i) {
1101             skColors[i] = sk_color_from(stops[i].color);
1102             skStops[i] = stops[i].position;
1103         }
1104 
1105         skPaint.setShader(SkGradientShader::MakeSweep(
1106             center.x(), center.y(),
1107             skColors.get(), SkColorSpace::MakeSRGB(), skStops.get(), stops.size(),
1108             tileMode,
1109             startAngleScaled, endAngleScaled,
1110             SkGradientShader::Interpolation{
1111                 SkGradientShader::Interpolation::InPremul::kNo,
1112                 SkGradientShader::Interpolation::ColorSpace::kSRGB,
1113                 SkGradientShader::Interpolation::HueMethod::kShorter
1114             },
1115             nullptr));
1116         canvas.drawPaint(skPaint);
1117         return true;
1118     }
1119 
1120     case DWRITE_PAINT_TYPE_GLYPH: {
1121         // A glyph paint element has one child, which is the fill for the glyph shape glyphIndex.
1122         SkPath path;
1123         SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1124         HRBM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
1125              "Could not create geometry to path converter.");
1126         UINT16 glyphId = SkTo<UINT16>(element.paint.glyph.glyphIndex);
1127         {
1128             Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
1129             HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
1130                      SkScalarToFloat(fTextSizeRender),
1131                      &glyphId,
1132                      nullptr, //advances
1133                      nullptr, //offsets
1134                      1, //num glyphs
1135                      FALSE, //sideways
1136                      FALSE, //rtl
1137                      geometryToPath.get()),
1138                  "Could not create glyph outline.");
1139         }
1140 
1141         path.transform(SkMatrix::Scale(1.0f / fTextSizeRender, 1.0f / fTextSizeRender));
1142         canvas.clipPath(path, fRenderingMode != DWRITE_RENDERING_MODE_ALIASED);
1143 
1144         drawChildren(1);
1145         return true;
1146     }
1147 
1148     case DWRITE_PAINT_TYPE_COLOR_GLYPH: {
1149         auto const& colorGlyph = element.paint.colorGlyph;
1150         // A color glyph paint element has one child, the root of the paint tree for glyphIndex.
1151         // glyphIndex, clipBox
1152         if (D2D_RECT_F_is_empty(colorGlyph.clipBox)) {
1153             // Does not have a clip box
1154         } else {
1155             SkRect r = sk_rect_from(colorGlyph.clipBox);
1156             canvas.clipRect(r, fRenderingMode != DWRITE_RENDERING_MODE_ALIASED);
1157         }
1158 
1159         drawChildren(1);
1160         return true;
1161     }
1162 
1163     case DWRITE_PAINT_TYPE_TRANSFORM: {
1164         // A transform paint element always has one child, the transformed content.
1165         canvas.concat(sk_matrix_from(element.paint.transform));
1166         drawChildren(1);
1167         return true;
1168     }
1169 
1170     case DWRITE_PAINT_TYPE_COMPOSITE: {
1171         // A composite paint element has two children, the source and destination of the operation.
1172 
1173         SkPaint blendModePaint;
1174         blendModePaint.setBlendMode(sk_blend_mode_from(element.paint.composite.mode));
1175 
1176         SkAutoCanvasRestore acr(&canvas, false);
1177 
1178         // Need to visit the second child first and do savelayers, so manually handle children.
1179         DWRITE_PAINT_ELEMENT sourceElement;
1180         DWRITE_PAINT_ELEMENT backdropElement;
1181 
1182         HRBM(reader.MoveToFirstChild(&sourceElement), "Could not move to child.");
1183         HRBM(reader.MoveToNextSibling(&backdropElement), "Could not move to sibiling.");
1184         canvas.saveLayer(nullptr, nullptr);
1185         this->drawColorV1Paint(canvas, reader, backdropElement);
1186 
1187         HRBM(reader.MoveToParent(), "Could not move to parent.");
1188         HRBM(reader.MoveToFirstChild(&sourceElement), "Could not move to child.");
1189         canvas.saveLayer(nullptr, &blendModePaint);
1190         this->drawColorV1Paint(canvas, reader, sourceElement);
1191 
1192         HRBM(reader.MoveToParent(), "Could not move to parent.");
1193 
1194         return true;
1195     }
1196 
1197     default:
1198         return false;
1199     }
1200 }
1201 
drawColorV1Image(const SkGlyph & glyph,SkCanvas & canvas)1202 bool SkScalerContext_DW::drawColorV1Image(const SkGlyph& glyph, SkCanvas& canvas) {
1203     DWriteFontTypeface* typeface = this->getDWriteTypeface();
1204     IDWriteFontFace7* fontFace = typeface->fDWriteFontFace7/*.get()*/;
1205     if (!fontFace) {
1206         return false;
1207     }
1208     UINT32 glyphIndex = glyph.getGlyphID();
1209 
1210     SkTScopedComPtr<IDWritePaintReader> paintReader;
1211     HRBM(fontFace->CreatePaintReader(DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE,
1212                                      DWRITE_PAINT_FEATURE_LEVEL_COLR_V1,
1213                                      &paintReader),
1214          "Could not create paint reader.");
1215 
1216     DWRITE_PAINT_ELEMENT paintElement;
1217     D2D_RECT_F clipBox;
1218     DWRITE_PAINT_ATTRIBUTES attributes;
1219     HRBM(paintReader->SetCurrentGlyph(glyphIndex, &paintElement, &clipBox, &attributes),
1220          "Could not set current glyph.");
1221 
1222     if (paintElement.paintType == DWRITE_PAINT_TYPE_NONE) {
1223         // Does not have paint layers, try another format.
1224         return false;
1225     }
1226 
1227     // All coordinates (including top level clip) are reported in "em"s (1 == em).
1228     // Size up all em units to the current size and transform.
1229     // Get glyph paths at render size, divide out the render size to get em units.
1230 
1231     SkMatrix matrix = fSkXform;
1232     SkScalar scale = fTextSizeRender;
1233     matrix.preScale(scale, scale);
1234     if (this->isSubpixel()) {
1235         matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
1236                              SkFixedToScalar(glyph.getSubYFixed()));
1237     }
1238     canvas.concat(matrix);
1239 
1240     if (D2D_RECT_F_is_empty(clipBox)) {
1241         // Does not have a clip box
1242     } else {
1243         canvas.clipRect(sk_rect_from(clipBox));
1244     }
1245 
1246     // The DirectWrite interface returns resolved colors if these are provided.
1247     // Indexes and alphas are reported but there is no reason to duplicate the color calculation.
1248     paintReader->SetTextColor(dw_color_from(SkColor4f::FromColor(fRec.fForegroundColor)));
1249     paintReader->SetCustomColorPalette(typeface->fDWPalette.get(), typeface->fPaletteEntryCount);
1250 
1251     return this->drawColorV1Paint(canvas, *paintReader, paintElement);
1252 }
1253 
generateColorV1Image(const SkGlyph & glyph,void * imageBuffer)1254 bool SkScalerContext_DW::generateColorV1Image(const SkGlyph& glyph, void* imageBuffer) {
1255     SkASSERT(glyph.maskFormat() == SkMask::Format::kARGB32_Format);
1256 
1257     SkBitmap dstBitmap;
1258     // TODO: mark this as sRGB when the blits will be sRGB.
1259     dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(),
1260                       kN32_SkColorType, kPremul_SkAlphaType),
1261                       glyph.rowBytes());
1262     dstBitmap.setPixels(imageBuffer);
1263 
1264     SkCanvas canvas(dstBitmap);
1265     if constexpr (kSkShowTextBlitCoverage) {
1266         canvas.clear(0x33FF0000);
1267     } else {
1268         canvas.clear(SK_ColorTRANSPARENT);
1269     }
1270     canvas.translate(-SkIntToScalar(glyph.left()), -SkIntToScalar(glyph.top()));
1271 
1272     return this->drawColorV1Image(glyph, canvas);
1273 }
1274 
generateColorV1PaintBounds(SkMatrix * ctm,SkRect * bounds,IDWritePaintReader & reader,DWRITE_PAINT_ELEMENT const & element)1275 bool SkScalerContext_DW::generateColorV1PaintBounds(
1276     SkMatrix* ctm, SkRect* bounds,
1277     IDWritePaintReader& reader, DWRITE_PAINT_ELEMENT const & element)
1278 {
1279     // Helper to iterate over the specified number of children.
1280     auto boundChildren = [&](UINT32 childCount) -> bool {
1281         if (childCount == 0) {
1282             return true;
1283         }
1284         DWRITE_PAINT_ELEMENT childElement;
1285         HRB(reader.MoveToFirstChild(&childElement));
1286         this->generateColorV1PaintBounds(ctm, bounds, reader, childElement);
1287 
1288         for (uint32_t i = 1; i < childCount; ++i) {
1289             HRB(reader.MoveToNextSibling(&childElement));
1290             this->generateColorV1PaintBounds(ctm, bounds, reader, childElement);
1291         }
1292 
1293         HRB(reader.MoveToParent());
1294         return true;
1295     };
1296 
1297     SkMatrix restoreMatrix = *ctm;
1298     SK_AT_SCOPE_EXIT(*ctm = restoreMatrix);
1299 
1300     switch (element.paintType) {
1301     case DWRITE_PAINT_TYPE_NONE:
1302         return false;
1303 
1304     case DWRITE_PAINT_TYPE_LAYERS: {
1305         // A layers paint element has a variable number of children.
1306         return boundChildren(element.paint.layers.childCount);
1307     }
1308 
1309     case DWRITE_PAINT_TYPE_SOLID_GLYPH: {
1310         // A solid glyph paint element has no children.
1311         // glyphIndex, color.value, color.paletteEntryIndex, color.alpha, color.colorAttributes
1312 
1313         SkPath path;
1314         SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1315         HRBM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
1316             "Could not create geometry to path converter.");
1317         UINT16 glyphId = SkTo<UINT16>(element.paint.solidGlyph.glyphIndex);
1318         {
1319             Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
1320             HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
1321                     SkScalarToFloat(fTextSizeRender),
1322                     &glyphId,
1323                     nullptr, //advances
1324                     nullptr, //offsets
1325                     1, //num glyphs
1326                     FALSE, //sideways
1327                     FALSE, //rtl
1328                     geometryToPath.get()),
1329                 "Could not create glyph outline.");
1330         }
1331 
1332         SkMatrix t = *ctm;
1333         t.preConcat(SkMatrix::Scale(1.0f / fTextSizeRender, 1.0f / fTextSizeRender));
1334         path.transform(t);
1335         bounds->join(path.getBounds());
1336         return true;
1337     }
1338 
1339     case DWRITE_PAINT_TYPE_SOLID: {
1340         return true;
1341     }
1342 
1343     case DWRITE_PAINT_TYPE_LINEAR_GRADIENT: {
1344         return true;
1345     }
1346 
1347     case DWRITE_PAINT_TYPE_RADIAL_GRADIENT: {
1348         return true;
1349     }
1350 
1351     case DWRITE_PAINT_TYPE_SWEEP_GRADIENT: {
1352         return true;
1353     }
1354 
1355     case DWRITE_PAINT_TYPE_GLYPH: {
1356         // A glyph paint element has one child, which is the fill for the glyph shape glyphIndex.
1357         SkPath path;
1358         SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1359         HRBM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
1360              "Could not create geometry to path converter.");
1361         UINT16 glyphId = SkTo<UINT16>(element.paint.glyph.glyphIndex);
1362         {
1363             Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
1364             HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
1365                      SkScalarToFloat(fTextSizeRender),
1366                      &glyphId,
1367                      nullptr, //advances
1368                      nullptr, //offsets
1369                      1, //num glyphs
1370                      FALSE, //sideways
1371                      FALSE, //rtl
1372                      geometryToPath.get()),
1373                  "Could not create glyph outline.");
1374         }
1375 
1376         SkMatrix t = *ctm;
1377         t.preConcat(SkMatrix::Scale(1.0f / fTextSizeRender, 1.0f / fTextSizeRender));
1378         path.transform(t);
1379         bounds->join(path.getBounds());
1380         return true;
1381     }
1382 
1383     case DWRITE_PAINT_TYPE_COLOR_GLYPH: {
1384         // A color glyph paint element has one child, which is the root
1385         // of the paint tree for the glyph specified by glyphIndex.
1386         auto const& colorGlyph = element.paint.colorGlyph;
1387         if (D2D_RECT_F_is_empty(colorGlyph.clipBox)) {
1388             // Does not have a clip box
1389             return boundChildren(1);
1390         }
1391         SkRect r = sk_rect_from(colorGlyph.clipBox);
1392         ctm->mapRect(r);
1393         bounds->join(r);
1394         return true;
1395     }
1396 
1397     case DWRITE_PAINT_TYPE_TRANSFORM: {
1398         // A transform paint element always has one child, which is the transformed content.
1399         ctm->preConcat(sk_matrix_from(element.paint.transform));
1400         return boundChildren(1);
1401     }
1402 
1403     case DWRITE_PAINT_TYPE_COMPOSITE: {
1404         // A composite paint element has two children, the source and destination of the operation.
1405         return boundChildren(2);
1406     }
1407 
1408     default:
1409         return false;
1410     }
1411 }
1412 
generateColorV1Metrics(const SkGlyph & glyph,SkRect * bounds)1413 bool SkScalerContext_DW::generateColorV1Metrics(const SkGlyph& glyph, SkRect* bounds) {
1414     DWriteFontTypeface* typeface = this->getDWriteTypeface();
1415     IDWriteFontFace7* fontFace = typeface->fDWriteFontFace7/*.get()*/;
1416     if (!fontFace) {
1417         return false;
1418     }
1419     UINT32 glyphIndex = glyph.getGlyphID();
1420 
1421     SkTScopedComPtr<IDWritePaintReader> paintReader;
1422     HRESULT hr;
1423     // No message on failure here, since this will fail if the font has no color glyphs.
1424     hr = fontFace->CreatePaintReader(DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE,
1425                                      DWRITE_PAINT_FEATURE_LEVEL_COLR_V1,
1426                                      &paintReader);
1427     if (FAILED(hr)) {
1428         return false;
1429     }
1430 
1431     DWRITE_PAINT_ELEMENT paintElement;
1432     D2D_RECT_F clipBox;
1433     DWRITE_PAINT_ATTRIBUTES attributes;
1434     // If the glyph is not color this will succeed but return paintType NONE.
1435     HRBM(paintReader->SetCurrentGlyph(glyphIndex, &paintElement, &clipBox, &attributes),
1436          "Could not set the current glyph.");
1437 
1438     if (paintElement.paintType == DWRITE_PAINT_TYPE_NONE) {
1439         // Does not have paint layers, try another format.
1440         return false;
1441     }
1442 
1443     // All coordinates (including top level clip) are reported in "em"s (1 == em).
1444     // Size up all em units to the current size and transform.
1445 
1446     SkMatrix matrix = fSkXform;
1447     SkScalar scale = fTextSizeRender;
1448     matrix.preScale(scale, scale);
1449     if (this->isSubpixel()) {
1450         matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
1451                              SkFixedToScalar(glyph.getSubYFixed()));
1452     }
1453 
1454     SkRect r;
1455     if (D2D_RECT_F_is_empty(clipBox)) {
1456         // Does not have a clip box.
1457         r = SkRect::MakeEmpty();
1458         if (!this->generateColorV1PaintBounds(&matrix, &r, *paintReader, paintElement)) {
1459             return false;
1460         }
1461         *bounds = r;
1462     } else {
1463         *bounds = sk_rect_from(clipBox);
1464         matrix.mapRect(bounds);
1465     }
1466     return true;
1467 }
1468 
1469 #else  // DWRITE_CORE || (defined(NTDDI_WIN11_ZN) && NTDDI_VERSION >= NTDDI_WIN11_ZN)
1470 
generateColorV1Metrics(const SkGlyph &,SkRect *)1471 bool SkScalerContext_DW::generateColorV1Metrics(const SkGlyph&, SkRect*) { return false; }
generateColorV1Image(const SkGlyph &,void *)1472 bool SkScalerContext_DW::generateColorV1Image(const SkGlyph&, void*) { return false; }
drawColorV1Image(const SkGlyph &,SkCanvas &)1473 bool SkScalerContext_DW::drawColorV1Image(const SkGlyph&, SkCanvas&) { return false; }
1474 
1475 #endif  // DWRITE_CORE || (defined(NTDDI_WIN11_ZN) && NTDDI_VERSION >= NTDDI_WIN11_ZN)
1476 
setAdvance(const SkGlyph & glyph,SkVector * advance)1477 bool SkScalerContext_DW::setAdvance(const SkGlyph& glyph, SkVector* advance) {
1478     *advance = {0, 0};
1479     uint16_t glyphId = glyph.getGlyphID();
1480     DWriteFontTypeface* typeface = this->getDWriteTypeface();
1481 
1482     // DirectWrite treats all out of bounds glyph ids as having the same data as glyph 0.
1483     // For consistency with all other backends, treat out of range glyph ids as an error.
1484     if (fGlyphCount <= glyphId) {
1485         return false;
1486     }
1487 
1488     DWRITE_GLYPH_METRICS gm;
1489 
1490     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
1491         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
1492     {
1493         Exclusive l(maybe_dw_mutex(*typeface));
1494         HRBM(typeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
1495                  fTextSizeMeasure,
1496                  1.0f, // pixelsPerDip
1497                  // This parameter does not act like the lpmat2 parameter to GetGlyphOutlineW.
1498                  // If it did then GsA here and G_inv below to mapVectors.
1499                  nullptr,
1500                  DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
1501                  &glyphId, 1,
1502                  &gm),
1503              "Could not get gdi compatible glyph metrics.");
1504     } else {
1505         Exclusive l(maybe_dw_mutex(*typeface));
1506         HRBM(typeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
1507              "Could not get design metrics.");
1508     }
1509 
1510     DWRITE_FONT_METRICS dwfm;
1511     {
1512         Shared l(maybe_dw_mutex(*typeface));
1513         typeface->fDWriteFontFace->GetMetrics(&dwfm);
1514     }
1515     SkScalar advanceX = fTextSizeMeasure * gm.advanceWidth / dwfm.designUnitsPerEm;
1516 
1517     *advance = { advanceX, 0 };
1518     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
1519         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
1520     {
1521         // DirectWrite produced 'compatible' metrics, but while close,
1522         // the end result is not always an integer as it would be with GDI.
1523         advance->fX = SkScalarRoundToScalar(advance->fX);
1524     }
1525     fSkXform.mapVectors(advance, 1);
1526     return true;
1527 }
1528 
generateDWMetrics(const SkGlyph & glyph,DWRITE_RENDERING_MODE renderingMode,DWRITE_TEXTURE_TYPE textureType,SkRect * bounds)1529 bool SkScalerContext_DW::generateDWMetrics(const SkGlyph& glyph,
1530                                            DWRITE_RENDERING_MODE renderingMode,
1531                                            DWRITE_TEXTURE_TYPE textureType,
1532                                            SkRect* bounds)
1533 {
1534     DWriteFontTypeface* typeface = this->getDWriteTypeface();
1535 
1536     //Measure raster size.
1537     fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
1538     fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
1539 
1540     FLOAT advance = 0;
1541 
1542     UINT16 glyphId = glyph.getGlyphID();
1543 
1544     DWRITE_GLYPH_OFFSET offset;
1545     offset.advanceOffset = 0.0f;
1546     offset.ascenderOffset = 0.0f;
1547 
1548     DWRITE_GLYPH_RUN run;
1549     run.glyphCount = 1;
1550     run.glyphAdvances = &advance;
1551     run.fontFace = typeface->fDWriteFontFace.get();
1552     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
1553     run.bidiLevel = 0;
1554     run.glyphIndices = &glyphId;
1555     run.isSideways = FALSE;
1556     run.glyphOffsets = &offset;
1557 
1558     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
1559     {
1560         Exclusive l(maybe_dw_mutex(*typeface));
1561         // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
1562         if (typeface->fFactory2 &&
1563                 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
1564                  fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
1565         {
1566             HRBM(typeface->fFactory2->CreateGlyphRunAnalysis(
1567                     &run,
1568                     &fXform,
1569                     renderingMode,
1570                     fMeasuringMode,
1571                     fGridFitMode,
1572                     fAntiAliasMode,
1573                     0.0f, // baselineOriginX,
1574                     0.0f, // baselineOriginY,
1575                     &glyphRunAnalysis),
1576                  "Could not create DW2 glyph run analysis.");
1577         } else {
1578             HRBM(typeface->fFactory->CreateGlyphRunAnalysis(&run,
1579                     1.0f, // pixelsPerDip,
1580                     &fXform,
1581                     renderingMode,
1582                     fMeasuringMode,
1583                     0.0f, // baselineOriginX,
1584                     0.0f, // baselineOriginY,
1585                     &glyphRunAnalysis),
1586                  "Could not create glyph run analysis.");
1587         }
1588     }
1589     RECT bbox;
1590     {
1591         Shared l(maybe_dw_mutex(*typeface));
1592         HRBM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, &bbox),
1593              "Could not get texture bounds.");
1594     }
1595 
1596     // GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
1597     // { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
1598     // for small but not quite zero and large (but not really large) glyphs,
1599     // Only set as non-empty if the returned bounds are non-empty.
1600     if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
1601         return false;
1602     }
1603 
1604     *bounds = SkRect::MakeLTRB(bbox.left, bbox.top, bbox.right, bbox.bottom);
1605     return true;
1606 }
1607 
getColorGlyphRun(const SkGlyph & glyph,IDWriteColorGlyphRunEnumerator ** colorGlyph)1608 bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph,
1609                                           IDWriteColorGlyphRunEnumerator** colorGlyph)
1610 {
1611     FLOAT advance = 0;
1612     UINT16 glyphId = glyph.getGlyphID();
1613 
1614     DWRITE_GLYPH_OFFSET offset;
1615     offset.advanceOffset = 0.0f;
1616     offset.ascenderOffset = 0.0f;
1617 
1618     DWRITE_GLYPH_RUN run;
1619     run.glyphCount = 1;
1620     run.glyphAdvances = &advance;
1621     run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
1622     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
1623     run.bidiLevel = 0;
1624     run.glyphIndices = &glyphId;
1625     run.isSideways = FALSE;
1626     run.glyphOffsets = &offset;
1627 
1628     HRESULT hr = this->getDWriteTypeface()->fFactory2->TranslateColorGlyphRun(
1629         0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph);
1630     if (hr == DWRITE_E_NOCOLOR) {
1631         return false;
1632     }
1633     HRBM(hr, "Failed to translate color glyph run");
1634     return true;
1635 }
1636 
generateColorMetrics(const SkGlyph & glyph,SkRect * bounds)1637 bool SkScalerContext_DW::generateColorMetrics(const SkGlyph& glyph, SkRect* bounds) {
1638     SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers;
1639     if (!getColorGlyphRun(glyph, &colorLayers)) {
1640         return false;
1641     }
1642     SkASSERT(colorLayers.get());
1643 
1644     *bounds = SkRect::MakeEmpty();
1645     BOOL hasNextRun = FALSE;
1646     while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) {
1647         const DWRITE_COLOR_GLYPH_RUN* colorGlyph;
1648         HRBM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run");
1649 
1650         SkPath path;
1651         SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1652         HRBM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
1653              "Could not create geometry to path converter.");
1654         {
1655             Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
1656             HRBM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
1657                     colorGlyph->glyphRun.fontEmSize,
1658                     colorGlyph->glyphRun.glyphIndices,
1659                     colorGlyph->glyphRun.glyphAdvances,
1660                     colorGlyph->glyphRun.glyphOffsets,
1661                     colorGlyph->glyphRun.glyphCount,
1662                     colorGlyph->glyphRun.isSideways,
1663                     colorGlyph->glyphRun.bidiLevel % 2, //rtl
1664                     geometryToPath.get()),
1665                  "Could not create glyph outline.");
1666         }
1667         bounds->join(path.getBounds());
1668     }
1669     SkMatrix matrix = fSkXform;
1670     if (this->isSubpixel()) {
1671         matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
1672                              SkFixedToScalar(glyph.getSubYFixed()));
1673     }
1674     matrix.mapRect(bounds);
1675     return true;
1676 }
1677 
generateSVGMetrics(const SkGlyph & glyph,SkRect * bounds)1678 bool SkScalerContext_DW::generateSVGMetrics(const SkGlyph& glyph, SkRect* bounds) {
1679     SkPictureRecorder recorder;
1680     SkRect infiniteRect = SkRect::MakeLTRB(-SK_ScalarInfinity, -SK_ScalarInfinity,
1681                                             SK_ScalarInfinity,  SK_ScalarInfinity);
1682     sk_sp<SkBBoxHierarchy> bboxh = SkRTreeFactory()();
1683     SkCanvas* recordingCanvas = recorder.beginRecording(infiniteRect, bboxh);
1684     if (!this->drawSVGImage(glyph, *recordingCanvas)) {
1685         return false;
1686     }
1687     sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture();
1688     *bounds = pic->cullRect();
1689     SkASSERT(bounds->isFinite());
1690     bounds->roundOut(bounds);
1691     return true;
1692 }
1693 
1694 namespace {
1695 struct Context {
1696     SkTScopedComPtr<IDWriteFontFace4> fontFace4;
1697     void* glyphDataContext;
Context__anon0365400f0811::Context1698     Context(IDWriteFontFace4* face4, void* context)
1699         : fontFace4(SkRefComPtr(face4))
1700         , glyphDataContext(context)
1701     {}
1702 };
1703 
ReleaseProc(const void * ptr,void * context)1704 static void ReleaseProc(const void* ptr, void* context) {
1705     Context* ctx = (Context*)context;
1706     ctx->fontFace4->ReleaseGlyphImageData(ctx->glyphDataContext);
1707     delete ctx;
1708 }
1709 }
1710 
generatePngMetrics(const SkGlyph & glyph,SkRect * bounds)1711 bool SkScalerContext_DW::generatePngMetrics(const SkGlyph& glyph, SkRect* bounds) {
1712     IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->fDWriteFontFace4.get();
1713     if (!fontFace4) {
1714         return false;
1715     }
1716 
1717     DWRITE_GLYPH_IMAGE_FORMATS imageFormats;
1718     HRBM(fontFace4->GetGlyphImageFormats(glyph.getGlyphID(), 0, UINT32_MAX, &imageFormats),
1719          "Cannot get glyph image formats.");
1720     if (!(imageFormats & DWRITE_GLYPH_IMAGE_FORMATS_PNG)) {
1721         return false;
1722     }
1723 
1724     DWRITE_GLYPH_IMAGE_DATA glyphData;
1725     void* glyphDataContext;
1726     HRBM(fontFace4->GetGlyphImageData(glyph.getGlyphID(),
1727                                       fTextSizeRender,
1728                                       DWRITE_GLYPH_IMAGE_FORMATS_PNG,
1729                                       &glyphData,
1730                                       &glyphDataContext),
1731          "Glyph image data could not be acquired.");
1732 
1733     Context* context = new Context(fontFace4, glyphDataContext);
1734     sk_sp<SkData> data = SkData::MakeWithProc(glyphData.imageData,
1735                                               glyphData.imageDataSize,
1736                                               &ReleaseProc,
1737                                               context);
1738 
1739     std::unique_ptr<SkCodec> codec = SkPngDecoder::Decode(std::move(data), nullptr);
1740     if (!codec) {
1741         return false;
1742     }
1743 
1744     SkImageInfo info = codec->getInfo();
1745     *bounds = SkRect::MakeLTRB(SkIntToScalar(info.bounds().fLeft),
1746                                SkIntToScalar(info.bounds().fTop),
1747                                SkIntToScalar(info.bounds().fRight),
1748                                SkIntToScalar(info.bounds().fBottom));
1749 
1750     SkMatrix matrix = fSkXform;
1751     SkScalar scale = fTextSizeRender / glyphData.pixelsPerEm;
1752     matrix.preScale(scale, scale);
1753     matrix.preTranslate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y);
1754     if (this->isSubpixel()) {
1755         matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
1756                              SkFixedToScalar(glyph.getSubYFixed()));
1757     }
1758     matrix.mapRect(bounds);
1759     bounds->roundOut(bounds);
1760     return true;
1761 }
1762 
generateMetrics(const SkGlyph & glyph,SkArenaAlloc * alloc)1763 SkScalerContext::GlyphMetrics SkScalerContext_DW::generateMetrics(const SkGlyph& glyph,
1764                                                                   SkArenaAlloc* alloc) {
1765     GlyphMetrics mx(glyph.maskFormat());
1766 
1767     mx.extraBits = ScalerContextBits::NONE;
1768 
1769     if (!this->setAdvance(glyph, &mx.advance)) {
1770         return mx;
1771     }
1772 
1773     DWriteFontTypeface* typeface = this->getDWriteTypeface();
1774     if (typeface->fIsColorFont) {
1775         if (generateColorV1Metrics(glyph, &mx.bounds)) {
1776             mx.maskFormat = SkMask::kARGB32_Format;
1777             mx.extraBits |= ScalerContextBits::COLRv1;
1778             mx.neverRequestPath = true;
1779             return mx;
1780         }
1781 
1782         if (generateColorMetrics(glyph, &mx.bounds)) {
1783             mx.maskFormat = SkMask::kARGB32_Format;
1784             mx.extraBits |= ScalerContextBits::COLR;
1785             mx.neverRequestPath = true;
1786             return mx;
1787         }
1788 
1789         if (generateSVGMetrics(glyph, &mx.bounds)) {
1790             mx.maskFormat = SkMask::kARGB32_Format;
1791             mx.extraBits |= ScalerContextBits::SVG;
1792             mx.neverRequestPath = true;
1793             return mx;
1794         }
1795 
1796         if (generatePngMetrics(glyph, &mx.bounds)) {
1797             mx.maskFormat = SkMask::kARGB32_Format;
1798             mx.extraBits |= ScalerContextBits::PNG;
1799             mx.neverRequestPath = true;
1800             return mx;
1801         }
1802     }
1803 
1804     if (this->generateDWMetrics(glyph, fRenderingMode, fTextureType, &mx.bounds)) {
1805         mx.extraBits = ScalerContextBits::DW;
1806         return mx;
1807     }
1808 
1809     // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
1810     // glyphs of the specified texture type or it is too big for smoothing.
1811     // When this happens, try with the alternate texture type.
1812     if (DWRITE_TEXTURE_ALIASED_1x1 != fTextureType ||
1813         DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE == fAntiAliasMode)
1814     {
1815         if (this->generateDWMetrics(glyph,
1816                                     DWRITE_RENDERING_MODE_ALIASED,
1817                                     DWRITE_TEXTURE_ALIASED_1x1,
1818                                     &mx.bounds))
1819         {
1820             mx.maskFormat = SkMask::kBW_Format;
1821             mx.extraBits = ScalerContextBits::DW_1;
1822             return mx;
1823         }
1824     }
1825     // TODO: Try DWRITE_TEXTURE_CLEARTYPE_3x1 if DWRITE_TEXTURE_ALIASED_1x1 fails
1826 
1827     // GetAlphaTextureBounds can fail for various reasons.
1828     // As a fallback, attempt to generate the metrics and image from the path.
1829     mx.computeFromPath = true;
1830     mx.extraBits = ScalerContextBits::PATH;
1831     return mx;
1832 }
1833 
generateFontMetrics(SkFontMetrics * metrics)1834 void SkScalerContext_DW::generateFontMetrics(SkFontMetrics* metrics) {
1835     if (nullptr == metrics) {
1836         return;
1837     }
1838 
1839     sk_bzero(metrics, sizeof(*metrics));
1840 
1841     DWRITE_FONT_METRICS dwfm;
1842     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
1843         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
1844     {
1845         this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleMetrics(
1846              fTextSizeRender,
1847              1.0f, // pixelsPerDip
1848              &fXform,
1849              &dwfm);
1850     } else {
1851         this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm);
1852     }
1853 
1854     SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
1855 
1856     metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
1857     metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
1858     metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
1859     metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
1860     metrics->fCapHeight = fTextSizeRender * SkIntToScalar(dwfm.capHeight) / upem;
1861     metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
1862     metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
1863     metrics->fStrikeoutThickness = fTextSizeRender * SkIntToScalar(dwfm.strikethroughThickness) / upem;
1864     metrics->fStrikeoutPosition = -(fTextSizeRender * SkIntToScalar(dwfm.strikethroughPosition) / upem);
1865 
1866     metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag;
1867     metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag;
1868     metrics->fFlags |= SkFontMetrics::kStrikeoutThicknessIsValid_Flag;
1869     metrics->fFlags |= SkFontMetrics::kStrikeoutPositionIsValid_Flag;
1870 
1871     SkTScopedComPtr<IDWriteFontFace5> fontFace5;
1872     if (SUCCEEDED(this->getDWriteTypeface()->fDWriteFontFace->QueryInterface(&fontFace5))) {
1873         if (fontFace5->HasVariations()) {
1874             // The bounds are only valid for the default variation.
1875             metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag;
1876         }
1877     }
1878 
1879     if (this->getDWriteTypeface()->fDWriteFontFace1.get()) {
1880         DWRITE_FONT_METRICS1 dwfm1;
1881         this->getDWriteTypeface()->fDWriteFontFace1->GetMetrics(&dwfm1);
1882         metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
1883         metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
1884         metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
1885         metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
1886 
1887         metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
1888         return;
1889     }
1890 
1891     AutoTDWriteTable<SkOTTableHead> head(this->getDWriteTypeface()->fDWriteFontFace.get());
1892     if (head.fExists &&
1893         head.fSize >= sizeof(SkOTTableHead) &&
1894         head->version == SkOTTableHead::version1)
1895     {
1896         metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
1897         metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
1898         metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
1899         metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
1900 
1901         metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
1902         return;
1903     }
1904 
1905     // The real bounds weren't actually available.
1906     metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag;
1907     metrics->fTop = metrics->fAscent;
1908     metrics->fBottom = metrics->fDescent;
1909 }
1910 
1911 ///////////////////////////////////////////////////////////////////////////////
1912 
1913 #include "include/private/SkColorData.h"
1914 
BilevelToBW(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph,void * imageBuffer)1915 void SkScalerContext_DW::BilevelToBW(const uint8_t* SK_RESTRICT src,
1916                                      const SkGlyph& glyph, void* imageBuffer) {
1917     const int width = glyph.width();
1918     const size_t dstRB = (width + 7) >> 3;
1919     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(imageBuffer);
1920 
1921     int byteCount = width >> 3;
1922     int bitCount = width & 7;
1923 
1924     for (int y = 0; y < glyph.height(); ++y) {
1925         if (byteCount > 0) {
1926             for (int i = 0; i < byteCount; ++i) {
1927                 unsigned byte = 0;
1928                 byte |= src[0] & (1 << 7);
1929                 byte |= src[1] & (1 << 6);
1930                 byte |= src[2] & (1 << 5);
1931                 byte |= src[3] & (1 << 4);
1932                 byte |= src[4] & (1 << 3);
1933                 byte |= src[5] & (1 << 2);
1934                 byte |= src[6] & (1 << 1);
1935                 byte |= src[7] & (1 << 0);
1936                 dst[i] = byte;
1937                 src += 8;
1938             }
1939         }
1940         if (bitCount > 0) {
1941             unsigned byte = 0;
1942             unsigned mask = 0x80;
1943             for (int i = 0; i < bitCount; i++) {
1944                 byte |= (src[i]) & mask;
1945                 mask >>= 1;
1946             }
1947             dst[byteCount] = byte;
1948         }
1949         src += bitCount;
1950         dst += dstRB;
1951     }
1952 
1953     if constexpr (kSkShowTextBlitCoverage) {
1954         dst = static_cast<uint8_t*>(imageBuffer);
1955         for (unsigned y = 0; y < (unsigned)glyph.height(); y += 2) {
1956             for (unsigned x = (y & 0x2); x < (unsigned)glyph.width(); x+=4) {
1957                 uint8_t& b = dst[(dstRB * y) + (x >> 3)];
1958                 b = b ^ (1 << (0x7 - (x & 0x7)));
1959             }
1960         }
1961     }
1962 }
1963 
1964 template<bool APPLY_PREBLEND>
GrayscaleToA8(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph,void * imageBuffer,const uint8_t * table8)1965 void SkScalerContext_DW::GrayscaleToA8(const uint8_t* SK_RESTRICT src,
1966                                        const SkGlyph& glyph, void* imageBuffer,
1967                                        const uint8_t* table8) {
1968     const size_t dstRB = glyph.rowBytes();
1969     const int width = glyph.width();
1970     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(imageBuffer);
1971 
1972     for (int y = 0; y < glyph.height(); y++) {
1973         for (int i = 0; i < width; i++) {
1974             U8CPU a = *(src++);
1975             dst[i] = sk_apply_lut_if<APPLY_PREBLEND>(a, table8);
1976             if constexpr (kSkShowTextBlitCoverage) {
1977                 dst[i] = std::max<U8CPU>(0x30, dst[i]);
1978             }
1979         }
1980         dst = SkTAddOffset<uint8_t>(dst, dstRB);
1981     }
1982 }
1983 
1984 template<bool APPLY_PREBLEND>
RGBToA8(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph,void * imageBuffer,const uint8_t * table8)1985 void SkScalerContext_DW::RGBToA8(const uint8_t* SK_RESTRICT src,
1986                                  const SkGlyph& glyph, void* imageBuffer,
1987                                  const uint8_t* table8) {
1988     const size_t dstRB = glyph.rowBytes();
1989     const int width = glyph.width();
1990     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(imageBuffer);
1991 
1992     for (int y = 0; y < glyph.height(); y++) {
1993         for (int i = 0; i < width; i++) {
1994             U8CPU r = *(src++);
1995             U8CPU g = *(src++);
1996             U8CPU b = *(src++);
1997             dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
1998             if constexpr (kSkShowTextBlitCoverage) {
1999                 dst[i] = std::max<U8CPU>(0x30, dst[i]);
2000             }
2001         }
2002         dst = SkTAddOffset<uint8_t>(dst, dstRB);
2003     }
2004 }
2005 
2006 template<bool APPLY_PREBLEND, bool RGB>
RGBToLcd16(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph,void * imageBuffer,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)2007 void SkScalerContext_DW::RGBToLcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
2008                                     void* imageBuffer,
2009                                     const uint8_t* tableR, const uint8_t* tableG,
2010                                     const uint8_t* tableB) {
2011     const size_t dstRB = glyph.rowBytes();
2012     const int width = glyph.width();
2013     uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(imageBuffer);
2014 
2015     for (int y = 0; y < glyph.height(); y++) {
2016         for (int i = 0; i < width; i++) {
2017             U8CPU r, g, b;
2018             if (RGB) {
2019                 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
2020                 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
2021                 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
2022             } else {
2023                 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
2024                 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
2025                 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
2026             }
2027             if constexpr (kSkShowTextBlitCoverage) {
2028                 r = std::max<U8CPU>(0x30, r);
2029                 g = std::max<U8CPU>(0x30, g);
2030                 b = std::max<U8CPU>(0x30, b);
2031             }
2032             dst[i] = SkPack888ToRGB16(r, g, b);
2033         }
2034         dst = SkTAddOffset<uint16_t>(dst, dstRB);
2035     }
2036 }
2037 
getDWMaskBits(const SkGlyph & glyph,DWRITE_RENDERING_MODE renderingMode,DWRITE_TEXTURE_TYPE textureType)2038 const void* SkScalerContext_DW::getDWMaskBits(const SkGlyph& glyph,
2039                                               DWRITE_RENDERING_MODE renderingMode,
2040                                               DWRITE_TEXTURE_TYPE textureType)
2041 {
2042     DWriteFontTypeface* typeface = this->getDWriteTypeface();
2043 
2044     int sizeNeeded = glyph.width() * glyph.height();
2045     if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) {
2046         sizeNeeded *= 3;
2047     }
2048     if (sizeNeeded > fBits.size()) {
2049         fBits.resize(sizeNeeded);
2050     }
2051 
2052     // erase
2053     memset(fBits.begin(), 0, sizeNeeded);
2054 
2055     fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
2056     fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
2057 
2058     FLOAT advance = 0.0f;
2059 
2060     UINT16 index = glyph.getGlyphID();
2061 
2062     DWRITE_GLYPH_OFFSET offset;
2063     offset.advanceOffset = 0.0f;
2064     offset.ascenderOffset = 0.0f;
2065 
2066     DWRITE_GLYPH_RUN run;
2067     run.glyphCount = 1;
2068     run.glyphAdvances = &advance;
2069     run.fontFace = typeface->fDWriteFontFace.get();
2070     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
2071     run.bidiLevel = 0;
2072     run.glyphIndices = &index;
2073     run.isSideways = FALSE;
2074     run.glyphOffsets = &offset;
2075     {
2076         SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
2077         {
2078             Exclusive l(maybe_dw_mutex(*typeface));
2079             // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
2080             if (typeface->fFactory2 &&
2081                     (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
2082                      fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
2083             {
2084                 HRNM(typeface->fFactory2->CreateGlyphRunAnalysis(&run,
2085                          &fXform,
2086                          renderingMode,
2087                          fMeasuringMode,
2088                          fGridFitMode,
2089                          fAntiAliasMode,
2090                          0.0f, // baselineOriginX,
2091                          0.0f, // baselineOriginY,
2092                          &glyphRunAnalysis),
2093                      "Could not create DW2 glyph run analysis.");
2094             } else {
2095                 HRNM(typeface->fFactory->CreateGlyphRunAnalysis(&run,
2096                          1.0f, // pixelsPerDip,
2097                          &fXform,
2098                          renderingMode,
2099                          fMeasuringMode,
2100                          0.0f, // baselineOriginX,
2101                          0.0f, // baselineOriginY,
2102                          &glyphRunAnalysis),
2103                      "Could not create glyph run analysis.");
2104             }
2105         }
2106         //NOTE: this assumes that the glyph has already been measured
2107         //with an exact same glyph run analysis.
2108         RECT bbox;
2109         bbox.left = glyph.left();
2110         bbox.top = glyph.top();
2111         bbox.right = glyph.left() + glyph.width();
2112         bbox.bottom = glyph.top() + glyph.height();
2113         {
2114             Shared l(maybe_dw_mutex(*typeface));
2115             HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
2116                     &bbox,
2117                     fBits.begin(),
2118                     sizeNeeded),
2119                  "Could not draw mask.");
2120         }
2121     }
2122     return fBits.begin();
2123 }
2124 
generateDWImage(const SkGlyph & glyph,void * imageBuffer)2125 bool SkScalerContext_DW::generateDWImage(const SkGlyph& glyph, void* imageBuffer) {
2126     //Create the mask.
2127     ScalerContextBits::value_type format = glyph.extraBits();
2128     DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
2129     DWRITE_TEXTURE_TYPE textureType = fTextureType;
2130     if (format == ScalerContextBits::DW_1) {
2131         renderingMode = DWRITE_RENDERING_MODE_ALIASED;
2132         textureType = DWRITE_TEXTURE_ALIASED_1x1;
2133     }
2134     const void* bits = this->getDWMaskBits(glyph, renderingMode, textureType);
2135     if (!bits) {
2136         sk_bzero(imageBuffer, glyph.imageSize());
2137         return false;
2138     }
2139 
2140     //Copy the mask into the glyph.
2141     const uint8_t* src = (const uint8_t*)bits;
2142     if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
2143         SkASSERT(SkMask::kBW_Format == glyph.maskFormat());
2144         SkASSERT(DWRITE_TEXTURE_ALIASED_1x1 == textureType);
2145         BilevelToBW(src, glyph, imageBuffer);
2146     } else if (!isLCD(fRec)) {
2147         if (textureType == DWRITE_TEXTURE_ALIASED_1x1) {
2148             if (fPreBlend.isApplicable()) {
2149                 GrayscaleToA8<true>(src, glyph, imageBuffer, fPreBlend.fG);
2150             } else {
2151                 GrayscaleToA8<false>(src, glyph, imageBuffer, fPreBlend.fG);
2152             }
2153         } else {
2154             if (fPreBlend.isApplicable()) {
2155                 RGBToA8<true>(src, glyph, imageBuffer, fPreBlend.fG);
2156             } else {
2157                 RGBToA8<false>(src, glyph, imageBuffer, fPreBlend.fG);
2158             }
2159         }
2160     } else {
2161         SkASSERT(SkMask::kLCD16_Format == glyph.maskFormat());
2162         if (fPreBlend.isApplicable()) {
2163             if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
2164                 RGBToLcd16<true, false>(src, glyph, imageBuffer,
2165                                         fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
2166             } else {
2167                 RGBToLcd16<true, true>(src, glyph, imageBuffer,
2168                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
2169             }
2170         } else {
2171             if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
2172                 RGBToLcd16<false, false>(src, glyph, imageBuffer,
2173                                          fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
2174             } else {
2175                 RGBToLcd16<false, true>(src, glyph, imageBuffer,
2176                                         fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
2177             }
2178         }
2179     }
2180     return true;
2181 }
2182 
drawColorImage(const SkGlyph & glyph,SkCanvas & canvas)2183 bool SkScalerContext_DW::drawColorImage(const SkGlyph& glyph, SkCanvas& canvas) {
2184     SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers;
2185     if (!getColorGlyphRun(glyph, &colorLayers)) {
2186         SkASSERTF(false, "Could not get color layers");
2187         return false;
2188     }
2189 
2190     SkPaint paint;
2191     paint.setAntiAlias(fRenderingMode != DWRITE_RENDERING_MODE_ALIASED);
2192 
2193     if (this->isSubpixel()) {
2194         canvas.translate(SkFixedToScalar(glyph.getSubXFixed()),
2195                          SkFixedToScalar(glyph.getSubYFixed()));
2196     }
2197     canvas.concat(fSkXform);
2198 
2199     DWriteFontTypeface* typeface = this->getDWriteTypeface();
2200     size_t paletteEntryCount = typeface->fPaletteEntryCount;
2201     SkColor* palette = typeface->fPalette.get();
2202     BOOL hasNextRun = FALSE;
2203     while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) {
2204         const DWRITE_COLOR_GLYPH_RUN* colorGlyph;
2205         HRBM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run");
2206 
2207         SkColor color;
2208         if (colorGlyph->paletteIndex == 0xffff) {
2209             color = fRec.fForegroundColor;
2210         } else if (colorGlyph->paletteIndex < paletteEntryCount) {
2211             color = palette[colorGlyph->paletteIndex];
2212         } else {
2213             SK_TRACEHR(DWRITE_E_NOCOLOR, "Invalid palette index.");
2214             color = SK_ColorBLACK;
2215         }
2216         paint.setColor(color);
2217 
2218         SkPath path;
2219         SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
2220         HRBM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
2221              "Could not create geometry to path converter.");
2222         {
2223             Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
2224             HRBM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
2225                      colorGlyph->glyphRun.fontEmSize,
2226                      colorGlyph->glyphRun.glyphIndices,
2227                      colorGlyph->glyphRun.glyphAdvances,
2228                      colorGlyph->glyphRun.glyphOffsets,
2229                      colorGlyph->glyphRun.glyphCount,
2230                      colorGlyph->glyphRun.isSideways,
2231                      colorGlyph->glyphRun.bidiLevel % 2, //rtl
2232                      geometryToPath.get()),
2233                  "Could not create glyph outline.");
2234         }
2235         canvas.drawPath(path, paint);
2236     }
2237     return true;
2238 }
2239 
generateColorImage(const SkGlyph & glyph,void * imageBuffer)2240 bool SkScalerContext_DW::generateColorImage(const SkGlyph& glyph, void* imageBuffer) {
2241     SkASSERT(glyph.maskFormat() == SkMask::Format::kARGB32_Format);
2242 
2243     SkBitmap dstBitmap;
2244     // TODO: mark this as sRGB when the blits will be sRGB.
2245     dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(),
2246                                         kN32_SkColorType, kPremul_SkAlphaType),
2247                                         glyph.rowBytes());
2248     dstBitmap.setPixels(imageBuffer);
2249 
2250     SkCanvas canvas(dstBitmap);
2251     if constexpr (kSkShowTextBlitCoverage) {
2252         canvas.clear(0x33FF0000);
2253     } else {
2254         canvas.clear(SK_ColorTRANSPARENT);
2255     }
2256     canvas.translate(-SkIntToScalar(glyph.left()), -SkIntToScalar(glyph.top()));
2257 
2258     return this->drawColorImage(glyph, canvas);
2259 }
2260 
drawSVGImage(const SkGlyph & glyph,SkCanvas & canvas)2261 bool SkScalerContext_DW::drawSVGImage(const SkGlyph& glyph, SkCanvas& canvas) {
2262     DWriteFontTypeface* typeface = this->getDWriteTypeface();
2263     IDWriteFontFace4* fontFace4 = typeface->fDWriteFontFace4.get();
2264     if (!fontFace4) {
2265         return false;
2266     }
2267 
2268     DWRITE_GLYPH_IMAGE_FORMATS imageFormats;
2269     HRBM(fontFace4->GetGlyphImageFormats(glyph.getGlyphID(), 0, UINT32_MAX, &imageFormats),
2270          "Cannot get glyph image formats.");
2271     if (!(imageFormats & DWRITE_GLYPH_IMAGE_FORMATS_SVG)) {
2272         return false;
2273     }
2274 
2275     SkGraphics::OpenTypeSVGDecoderFactory svgFactory = SkGraphics::GetOpenTypeSVGDecoderFactory();
2276     if (!svgFactory) {
2277         return false;
2278     }
2279 
2280     DWRITE_GLYPH_IMAGE_DATA glyphData;
2281     void* glyphDataContext;
2282     HRBM(fontFace4->GetGlyphImageData(glyph.getGlyphID(),
2283                                       fTextSizeRender,
2284                                       DWRITE_GLYPH_IMAGE_FORMATS_SVG,
2285                                       &glyphData,
2286                                       &glyphDataContext),
2287          "Glyph SVG data could not be acquired.");
2288     auto svgDecoder = svgFactory((const uint8_t*)glyphData.imageData, glyphData.imageDataSize);
2289     fontFace4->ReleaseGlyphImageData(glyphDataContext);
2290     if (!svgDecoder) {
2291         return false;
2292     }
2293 
2294     size_t paletteEntryCount = typeface->fPaletteEntryCount;
2295     SkColor* palette = typeface->fPalette.get();
2296     int upem = typeface->getUnitsPerEm();
2297 
2298     SkMatrix matrix = fSkXform;
2299     SkScalar scale = fTextSizeRender / upem;
2300     matrix.preScale(scale, scale);
2301     matrix.preTranslate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y);
2302     if (this->isSubpixel()) {
2303         matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
2304                              SkFixedToScalar(glyph.getSubYFixed()));
2305     }
2306     canvas.concat(matrix);
2307 
2308     return svgDecoder->render(canvas, upem, glyph.getGlyphID(),
2309                               fRec.fForegroundColor, SkSpan(palette, paletteEntryCount));
2310 }
2311 
generateSVGImage(const SkGlyph & glyph,void * imageBuffer)2312 bool SkScalerContext_DW::generateSVGImage(const SkGlyph& glyph, void* imageBuffer) {
2313     SkASSERT(glyph.maskFormat() == SkMask::Format::kARGB32_Format);
2314 
2315     SkBitmap dstBitmap;
2316     // TODO: mark this as sRGB when the blits will be sRGB.
2317     dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(),
2318                                         kN32_SkColorType, kPremul_SkAlphaType),
2319                       glyph.rowBytes());
2320     dstBitmap.setPixels(imageBuffer);
2321 
2322     SkCanvas canvas(dstBitmap);
2323     if constexpr (kSkShowTextBlitCoverage) {
2324         canvas.clear(0x33FF0000);
2325     } else {
2326         canvas.clear(SK_ColorTRANSPARENT);
2327     }
2328     canvas.translate(-SkIntToScalar(glyph.left()), -SkIntToScalar(glyph.top()));
2329 
2330     return this->drawSVGImage(glyph, canvas);
2331 }
2332 
drawPngImage(const SkGlyph & glyph,SkCanvas & canvas)2333 bool SkScalerContext_DW::drawPngImage(const SkGlyph& glyph, SkCanvas& canvas) {
2334     IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->fDWriteFontFace4.get();
2335     if (!fontFace4) {
2336         return false;
2337     }
2338 
2339     DWRITE_GLYPH_IMAGE_DATA glyphData;
2340     void* glyphDataContext;
2341     HRBM(fontFace4->GetGlyphImageData(glyph.getGlyphID(),
2342                                       fTextSizeRender,
2343                                       DWRITE_GLYPH_IMAGE_FORMATS_PNG,
2344                                       &glyphData,
2345                                       &glyphDataContext),
2346          "Glyph image data could not be acquired.");
2347     Context* context = new Context(fontFace4, glyphDataContext);
2348     sk_sp<SkData> data = SkData::MakeWithProc(glyphData.imageData,
2349                                               glyphData.imageDataSize,
2350                                               &ReleaseProc,
2351                                               context);
2352     sk_sp<SkImage> image = SkImages::DeferredFromEncodedData(std::move(data));
2353     if (!image) {
2354         return false;
2355     }
2356 
2357     if (this->isSubpixel()) {
2358         canvas.translate(SkFixedToScalar(glyph.getSubXFixed()),
2359                          SkFixedToScalar(glyph.getSubYFixed()));
2360     }
2361     canvas.concat(fSkXform);
2362     SkScalar ratio = fTextSizeRender / glyphData.pixelsPerEm;
2363     canvas.scale(ratio, ratio);
2364     canvas.translate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y);
2365     canvas.drawImage(image, 0, 0);
2366     return true;
2367 }
2368 
generatePngImage(const SkGlyph & glyph,void * imageBuffer)2369 bool SkScalerContext_DW::generatePngImage(const SkGlyph& glyph, void* imageBuffer) {
2370     SkASSERT(glyph.maskFormat() == SkMask::Format::kARGB32_Format);
2371 
2372     SkBitmap dstBitmap;
2373     dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(),
2374                                         kN32_SkColorType, kPremul_SkAlphaType),
2375                       glyph.rowBytes());
2376     dstBitmap.setPixels(imageBuffer);
2377 
2378     SkCanvas canvas(dstBitmap);
2379     canvas.clear(SK_ColorTRANSPARENT);
2380     canvas.translate(-glyph.left(), -glyph.top());
2381 
2382     return this->drawPngImage(glyph, canvas);
2383 }
2384 
generateImage(const SkGlyph & glyph,void * imageBuffer)2385 void SkScalerContext_DW::generateImage(const SkGlyph& glyph, void* imageBuffer) {
2386     ScalerContextBits::value_type format = glyph.extraBits();
2387     if (format == ScalerContextBits::DW ||
2388         format == ScalerContextBits::DW_1)
2389     {
2390         this->generateDWImage(glyph, imageBuffer);
2391     } else if (format == ScalerContextBits::COLRv1) {
2392         this->generateColorV1Image(glyph, imageBuffer);
2393     } else if (format == ScalerContextBits::COLR) {
2394         this->generateColorImage(glyph, imageBuffer);
2395     } else if (format == ScalerContextBits::SVG) {
2396         this->generateSVGImage(glyph, imageBuffer);
2397     } else if (format == ScalerContextBits::PNG) {
2398         this->generatePngImage(glyph, imageBuffer);
2399     } else if (format == ScalerContextBits::PATH) {
2400         const SkPath* devPath = glyph.path();
2401         SkASSERT_RELEASE(devPath);
2402         SkMaskBuilder mask(static_cast<uint8_t*>(imageBuffer),
2403                            glyph.iRect(), glyph.rowBytes(), glyph.maskFormat());
2404         SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
2405         const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
2406         const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
2407         const bool a8LCD = SkToBool(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag);
2408         const bool hairline = glyph.pathIsHairline();
2409         GenerateImageFromPath(mask, *devPath, fPreBlend, doBGR, doVert, a8LCD, hairline);
2410     } else {
2411         SK_ABORT("Bad format");
2412     }
2413 }
2414 
generatePath(const SkGlyph & glyph,SkPath * path)2415 bool SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
2416     SkASSERT(path);
2417     path->reset();
2418 
2419     SkGlyphID glyphID = glyph.getGlyphID();
2420 
2421     // DirectWrite treats all out of bounds glyph ids as having the same data as glyph 0.
2422     // For consistency with all other backends, treat out of range glyph ids as an error.
2423     if (fGlyphCount <= glyphID) {
2424         return false;
2425     }
2426 
2427     SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
2428     HRBM(SkDWriteGeometrySink::Create(path, &geometryToPath),
2429          "Could not create geometry to path converter.");
2430     UINT16 glyphId = SkTo<UINT16>(glyphID);
2431     {
2432         Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
2433         //TODO: convert to<->from DIUs? This would make a difference if hinting.
2434         //It may not be needed, it appears that DirectWrite only hints at em size.
2435         HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
2436              SkScalarToFloat(fTextSizeRender),
2437              &glyphId,
2438              nullptr, //advances
2439              nullptr, //offsets
2440              1, //num glyphs
2441              FALSE, //sideways
2442              FALSE, //rtl
2443              geometryToPath.get()),
2444              "Could not create glyph outline.");
2445     }
2446 
2447     path->transform(fSkXform);
2448     return true;
2449 }
2450 
generateDrawable(const SkGlyph & glyph)2451 sk_sp<SkDrawable> SkScalerContext_DW::generateDrawable(const SkGlyph& glyph) {
2452     struct GlyphDrawable : public SkDrawable {
2453         SkScalerContext_DW* fSelf;
2454         SkGlyph fGlyph;
2455         GlyphDrawable(SkScalerContext_DW* self, const SkGlyph& glyph) : fSelf(self), fGlyph(glyph){}
2456         SkRect onGetBounds() override { return fGlyph.rect();  }
2457         size_t onApproximateBytesUsed() override { return sizeof(GlyphDrawable); }
2458         void maybeShowTextBlitCoverage(SkCanvas* canvas) {
2459             if constexpr (kSkShowTextBlitCoverage) {
2460                 SkPaint paint;
2461                 paint.setColor(0x3300FF00);
2462                 paint.setStyle(SkPaint::kFill_Style);
2463                 canvas->drawRect(this->onGetBounds(), paint);
2464             }
2465         }
2466     };
2467     struct COLRv1GlyphDrawable : public GlyphDrawable {
2468         using GlyphDrawable::GlyphDrawable;
2469         void onDraw(SkCanvas* canvas) override {
2470             this->maybeShowTextBlitCoverage(canvas);
2471             fSelf->drawColorV1Image(fGlyph, *canvas);
2472         }
2473     };
2474     struct COLRGlyphDrawable : public GlyphDrawable {
2475         using GlyphDrawable::GlyphDrawable;
2476         void onDraw(SkCanvas* canvas) override {
2477             this->maybeShowTextBlitCoverage(canvas);
2478             fSelf->drawColorImage(fGlyph, *canvas);
2479         }
2480     };
2481     struct SVGGlyphDrawable : public GlyphDrawable {
2482         using GlyphDrawable::GlyphDrawable;
2483         void onDraw(SkCanvas* canvas) override {
2484             this->maybeShowTextBlitCoverage(canvas);
2485             fSelf->drawSVGImage(fGlyph, *canvas);
2486         }
2487     };
2488     ScalerContextBits::value_type format = glyph.extraBits();
2489     if (format == ScalerContextBits::COLRv1) {
2490         return sk_sp<SkDrawable>(new COLRv1GlyphDrawable(this, glyph));
2491     }
2492     if (format == ScalerContextBits::COLR) {
2493         return sk_sp<SkDrawable>(new COLRGlyphDrawable(this, glyph));
2494     }
2495     if (format == ScalerContextBits::SVG) {
2496         return sk_sp<SkDrawable>(new SVGGlyphDrawable(this, glyph));
2497     }
2498     return nullptr;
2499 }
2500 
2501 #endif//defined(SK_BUILD_FOR_WIN)
2502