• 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/core/SkBBHFactory.h"
16 #include "include/core/SkBitmap.h"
17 #include "include/core/SkData.h"
18 #include "include/core/SkDrawable.h"
19 #include "include/core/SkFontMetrics.h"
20 #include "include/core/SkGraphics.h"
21 #include "include/core/SkOpenTypeSVGDecoder.h"
22 #include "include/core/SkPath.h"
23 #include "include/core/SkPictureRecorder.h"
24 #include "include/private/base/SkMutex.h"
25 #include "include/private/base/SkTo.h"
26 #include "src/core/SkDraw.h"
27 #include "src/core/SkEndian.h"
28 #include "src/core/SkGlyph.h"
29 #include "src/core/SkMaskGamma.h"
30 #include "src/core/SkMatrixProvider.h"
31 #include "src/core/SkRasterClip.h"
32 #include "src/core/SkScalerContext.h"
33 #include "src/core/SkSharedMutex.h"
34 #include "src/ports/SkScalerContext_win_dw.h"
35 #include "src/ports/SkTypeface_win_dw.h"
36 #include "src/sfnt/SkOTTable_EBLC.h"
37 #include "src/sfnt/SkOTTable_EBSC.h"
38 #include "src/sfnt/SkOTTable_gasp.h"
39 #include "src/sfnt/SkOTTable_maxp.h"
40 #include "src/utils/SkMatrix22.h"
41 #include "src/utils/win/SkDWrite.h"
42 #include "src/utils/win/SkDWriteGeometrySink.h"
43 #include "src/utils/win/SkHRESULT.h"
44 #include "src/utils/win/SkTScopedComPtr.h"
45 
46 #include <dwrite.h>
47 #include <dwrite_1.h>
48 #include <dwrite_3.h>
49 
50 namespace {
51 static inline const constexpr bool kSkShowTextBlitCoverage = false;
52 
53 /* Note:
54  * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe.
55  * The mutex returned from maybe_dw_mutex protects the calls that are
56  * problematic.
57  */
maybe_dw_mutex(DWriteFontTypeface & typeface)58 static SkSharedMutex* maybe_dw_mutex(DWriteFontTypeface& typeface) {
59     static SkSharedMutex mutex;
60     return typeface.fDWriteFontFace4 ? nullptr : &mutex;
61 }
62 
63 class SK_SCOPED_CAPABILITY Exclusive {
64 public:
65     explicit Exclusive(SkSharedMutex* maybe_lock) SK_ACQUIRE(*maybe_lock)
66         : fLock(maybe_lock) {
67         if (fLock) {
68             fLock->acquire();
69         }
70     }
SK_RELEASE_CAPABILITY()71     ~Exclusive() SK_RELEASE_CAPABILITY() {
72         if (fLock) {
73             fLock->release();
74         }
75     }
76 
77 private:
78     SkSharedMutex* fLock;
79 };
80 class SK_SCOPED_CAPABILITY Shared {
81 public:
82     explicit Shared(SkSharedMutex* maybe_lock) SK_ACQUIRE_SHARED(*maybe_lock)
83         : fLock(maybe_lock)  {
84         if (fLock) {
85             fLock->acquireShared();
86         }
87     }
88 
89     // You would think this should be SK_RELEASE_SHARED_CAPABILITY, but SK_SCOPED_CAPABILITY
90     // doesn't fully understand the difference between shared and exclusive.
91     // Please review https://reviews.llvm.org/D52578 for more information.
SK_RELEASE_CAPABILITY()92     ~Shared() SK_RELEASE_CAPABILITY() {
93         if (fLock) {
94             fLock->releaseShared();
95         }
96     }
97 
98 private:
99     SkSharedMutex* fLock;
100 };
101 
isLCD(const SkScalerContextRec & rec)102 static bool isLCD(const SkScalerContextRec& rec) {
103     return SkMask::kLCD16_Format == rec.fMaskFormat;
104 }
105 
is_hinted(DWriteFontTypeface * typeface)106 static bool is_hinted(DWriteFontTypeface* typeface) {
107     Exclusive l(maybe_dw_mutex(*typeface));
108     AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
109     if (!maxp.fExists) {
110         return false;
111     }
112     if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
113         return false;
114     }
115     if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
116         return false;
117     }
118     return (0 != maxp->version.tt.maxSizeOfInstructions);
119 }
120 
121 /** A GaspRange is inclusive, [min, max]. */
122 struct GaspRange {
123     using Behavior = SkOTTableGridAndScanProcedure::GaspRange::behavior;
GaspRange__anonaec314400111::GaspRange124     GaspRange(int min, int max, int version, Behavior flags)
125         : fMin(min), fMax(max), fVersion(version), fFlags(flags) { }
126     int fMin;
127     int fMax;
128     int fVersion;
129     Behavior fFlags;
130 };
131 
get_gasp_range(DWriteFontTypeface * typeface,int size,GaspRange * range)132 bool get_gasp_range(DWriteFontTypeface* typeface, int size, GaspRange* range) {
133     AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
134     if (!gasp.fExists) {
135         return false;
136     }
137     if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
138         return false;
139     }
140     if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
141         gasp->version != SkOTTableGridAndScanProcedure::version1)
142     {
143         return false;
144     }
145 
146     uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
147     if (numRanges > 1024 ||
148         gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
149         sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
150     {
151         return false;
152     }
153 
154     const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
155             SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
156     int minPPEM = -1;
157     for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) {
158         int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM);
159         if (minPPEM < size && size <= maxPPEM) {
160             range->fMin = minPPEM + 1;
161             range->fMax = maxPPEM;
162             range->fVersion = SkEndian_SwapBE16(gasp->version);
163             range->fFlags = rangeTable->flags;
164             return true;
165         }
166         minPPEM = maxPPEM;
167     }
168     return false;
169 }
170 /** If the rendering mode for the specified 'size' is gridfit, then place
171  *  the gridfit range into 'range'. Otherwise, leave 'range' alone.
172  */
is_gridfit_only(GaspRange::Behavior flags)173 static bool is_gridfit_only(GaspRange::Behavior flags) {
174     return flags.raw.value == GaspRange::Behavior::Raw::GridfitMask;
175 }
176 
has_bitmap_strike(DWriteFontTypeface * typeface,GaspRange range)177 static bool has_bitmap_strike(DWriteFontTypeface* typeface, GaspRange range) {
178     Exclusive l(maybe_dw_mutex(*typeface));
179     {
180         AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
181         if (!eblc.fExists) {
182             return false;
183         }
184         if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
185             return false;
186         }
187         if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
188             return false;
189         }
190 
191         uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
192         if (numSizes > 1024 ||
193             eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
194                          sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
195         {
196             return false;
197         }
198 
199         const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
200                 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
201         for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
202             if (sizeTable->ppemX == sizeTable->ppemY &&
203                 range.fMin <= sizeTable->ppemX && sizeTable->ppemX <= range.fMax)
204             {
205                 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
206                 // to determine the actual number of glyphs with bitmaps.
207 
208                 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
209 
210                 // TODO: Ensure that the bitmaps are bi-level?
211                 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
212                     return true;
213                 }
214             }
215         }
216     }
217 
218     {
219         AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
220         if (!ebsc.fExists) {
221             return false;
222         }
223         if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
224             return false;
225         }
226         if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
227             return false;
228         }
229 
230         uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
231         if (numSizes > 1024 ||
232             ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
233                          sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
234         {
235             return false;
236         }
237 
238         const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
239                 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
240         for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
241             if (scaleTable->ppemX == scaleTable->ppemY &&
242                 range.fMin <= scaleTable->ppemX && scaleTable->ppemX <= range.fMax) {
243                 // EBSC tables are normally only found in bitmap only fonts.
244                 return true;
245             }
246         }
247     }
248 
249     return false;
250 }
251 
both_zero(SkScalar a,SkScalar b)252 static bool both_zero(SkScalar a, SkScalar b) {
253     return 0 == a && 0 == b;
254 }
255 
256 // returns false if there is any non-90-rotation or skew
is_axis_aligned(const SkScalerContextRec & rec)257 static bool is_axis_aligned(const SkScalerContextRec& rec) {
258     return 0 == rec.fPreSkewX &&
259            (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
260             both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
261 }
262 
263 }  //namespace
264 
SkScalerContext_DW(sk_sp<DWriteFontTypeface> typefaceRef,const SkScalerContextEffects & effects,const SkDescriptor * desc)265 SkScalerContext_DW::SkScalerContext_DW(sk_sp<DWriteFontTypeface> typefaceRef,
266                                        const SkScalerContextEffects& effects,
267                                        const SkDescriptor* desc)
268         : SkScalerContext(std::move(typefaceRef), effects, desc)
269 {
270     DWriteFontTypeface* typeface = this->getDWriteTypeface();
271     fGlyphCount = typeface->fDWriteFontFace->GetGlyphCount();
272 
273     // In general, all glyphs should use NATURAL_SYMMETRIC
274     // except when bi-level rendering is requested or there are embedded
275     // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
276     //
277     // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
278     // this. As a result, determine the actual size of the text and then see if
279     // there are any embedded bi-level bitmaps of that size. If there are, then
280     // force bitmaps by requesting bi-level rendering.
281     //
282     // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
283     // square pixels and only uses ppemY. Therefore the transform must track any
284     // non-uniform x-scale.
285     //
286     // Also, rotated glyphs should have the same absolute advance widths as
287     // horizontal glyphs and the subpixel flag should not affect glyph shapes.
288 
289     SkVector scale;
290     fRec.computeMatrices(SkScalerContextRec::PreMatrixScale::kVertical, &scale, &fSkXform);
291 
292     fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
293     fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
294     fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
295     fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
296     fXform.dx = 0;
297     fXform.dy = 0;
298 
299     // realTextSize is the actual device size we want (as opposed to the size the user requested).
300     // gdiTextSize is the size we request when GDI compatible.
301     // If the scale is negative, this means the matrix will do the flip anyway.
302     const SkScalar realTextSize = scale.fY;
303     // Due to floating point math, the lower bits are suspect. Round carefully.
304     SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
305     if (gdiTextSize == 0) {
306         gdiTextSize = SK_Scalar1;
307     }
308 
309     bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
310     bool treatLikeBitmap = false;
311     bool axisAlignedBitmap = false;
312     if (bitmapRequested) {
313         // When embedded bitmaps are requested, treat the entire range like
314         // a bitmap strike if the range is gridfit only and contains a bitmap.
315         int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
316         GaspRange range(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior());
317         if (get_gasp_range(typeface, bitmapPPEM, &range)) {
318             if (!is_gridfit_only(range.fFlags)) {
319                 range = GaspRange(bitmapPPEM, bitmapPPEM, 0, GaspRange::Behavior());
320             }
321         }
322         treatLikeBitmap = has_bitmap_strike(typeface, range);
323 
324         axisAlignedBitmap = is_axis_aligned(fRec);
325     }
326 
327     GaspRange range(0, 0xFFFF, 0, GaspRange::Behavior());
328 
329     // If the user requested aliased, do so with aliased compatible metrics.
330     if (SkMask::kBW_Format == fRec.fMaskFormat) {
331         fTextSizeRender = gdiTextSize;
332         fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
333         fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
334         fTextSizeMeasure = gdiTextSize;
335         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
336 
337     // If we can use a bitmap, use gdi classic rendering and measurement.
338     // This will not always provide a bitmap, but matches expected behavior.
339     } else if (treatLikeBitmap && axisAlignedBitmap) {
340         fTextSizeRender = gdiTextSize;
341         fRenderingMode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
342         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
343         fTextSizeMeasure = gdiTextSize;
344         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
345 
346     // If rotated but the horizontal text could have used a bitmap,
347     // render high quality rotated glyphs but measure using bitmap metrics.
348     } else if (treatLikeBitmap) {
349         fTextSizeRender = gdiTextSize;
350         fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
351         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
352         fTextSizeMeasure = gdiTextSize;
353         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
354 
355     // If the font has a gasp table version 1, use it to determine symmetric rendering.
356     } else if (get_gasp_range(typeface, SkScalarRoundToInt(gdiTextSize), &range) &&
357                range.fVersion >= 1)
358     {
359         fTextSizeRender = realTextSize;
360         fRenderingMode = range.fFlags.field.SymmetricSmoothing
361                        ? DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
362                        : DWRITE_RENDERING_MODE_NATURAL;
363         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
364         fTextSizeMeasure = realTextSize;
365         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
366 
367     // If the requested size is above 20px or there are no bytecode hints, use symmetric rendering.
368     } else if (realTextSize > SkIntToScalar(20) || !is_hinted(typeface)) {
369         fTextSizeRender = realTextSize;
370         fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
371         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
372         fTextSizeMeasure = realTextSize;
373         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
374 
375     // Fonts with hints, no gasp or gasp version 0, and below 20px get non-symmetric rendering.
376     // Often such fonts have hints which were only tested with GDI ClearType classic.
377     // Some of these fonts rely on drop out control in the y direction in order to be legible.
378     // Tenor Sans
379     //    https://fonts.google.com/specimen/Tenor+Sans
380     // Gill Sans W04
381     //    https://cdn.leagueoflegends.com/lolkit/1.1.9/resources/fonts/gill-sans-w04-book.woff
382     //    https://na.leagueoflegends.com/en/news/game-updates/patch/patch-410-notes
383     // See https://crbug.com/385897
384     } else {
385         fTextSizeRender = gdiTextSize;
386         fRenderingMode = DWRITE_RENDERING_MODE_NATURAL;
387         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
388         fTextSizeMeasure = realTextSize;
389         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
390     }
391 
392     // DirectWrite2 allows for grayscale hinting.
393     fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
394     if (typeface->fFactory2 && typeface->fDWriteFontFace2 &&
395         SkMask::kA8_Format == fRec.fMaskFormat &&
396         !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag))
397     {
398         // DWRITE_TEXTURE_ALIASED_1x1 is now misnamed, it must also be used with grayscale.
399         fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
400         fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE;
401     }
402 
403     // DirectWrite2 allows hinting to be disabled.
404     fGridFitMode = DWRITE_GRID_FIT_MODE_ENABLED;
405     if (fRec.getHinting() == SkFontHinting::kNone) {
406         fGridFitMode = DWRITE_GRID_FIT_MODE_DISABLED;
407         if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) {
408             fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
409         }
410     }
411 
412     if (this->isLinearMetrics()) {
413         fTextSizeMeasure = realTextSize;
414         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
415     }
416 
417     // The GDI measuring modes don't seem to work well with CBDT fonts (DWrite.dll 10.0.18362.836).
418     if (fMeasuringMode != DWRITE_MEASURING_MODE_NATURAL) {
419         constexpr UINT32 CBDTTag = DWRITE_MAKE_OPENTYPE_TAG('C','B','D','T');
420         AutoDWriteTable CBDT(typeface->fDWriteFontFace.get(), CBDTTag);
421         if (CBDT.fExists) {
422             fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
423         }
424     }
425 }
426 
~SkScalerContext_DW()427 SkScalerContext_DW::~SkScalerContext_DW() {
428 }
429 
generateAdvance(SkGlyph * glyph)430 bool SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
431     glyph->fAdvanceX = 0;
432     glyph->fAdvanceY = 0;
433     uint16_t glyphId = glyph->getGlyphID();
434     DWriteFontTypeface* typeface = this->getDWriteTypeface();
435 
436     // DirectWrite treats all out of bounds glyph ids as having the same data as glyph 0.
437     // For consistency with all other backends, treat out of range glyph ids as an error.
438     if (fGlyphCount <= glyphId) {
439         return false;
440     }
441 
442     DWRITE_GLYPH_METRICS gm;
443 
444     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
445         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
446     {
447         Exclusive l(maybe_dw_mutex(*typeface));
448         HRBM(typeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
449                  fTextSizeMeasure,
450                  1.0f, // pixelsPerDip
451                  // This parameter does not act like the lpmat2 parameter to GetGlyphOutlineW.
452                  // If it did then GsA here and G_inv below to mapVectors.
453                  nullptr,
454                  DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
455                  &glyphId, 1,
456                  &gm),
457              "Could not get gdi compatible glyph metrics.");
458     } else {
459         Exclusive l(maybe_dw_mutex(*typeface));
460         HRBM(typeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
461              "Could not get design metrics.");
462     }
463 
464     DWRITE_FONT_METRICS dwfm;
465     {
466         Shared l(maybe_dw_mutex(*typeface));
467         typeface->fDWriteFontFace->GetMetrics(&dwfm);
468     }
469     SkScalar advanceX = fTextSizeMeasure * gm.advanceWidth / dwfm.designUnitsPerEm;
470 
471     SkVector advance = { advanceX, 0 };
472     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
473         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
474     {
475         // DirectWrite produced 'compatible' metrics, but while close,
476         // the end result is not always an integer as it would be with GDI.
477         advance.fX = SkScalarRoundToScalar(advance.fX);
478     }
479     fSkXform.mapVectors(&advance, 1);
480 
481     glyph->fAdvanceX = SkScalarToFloat(advance.fX);
482     glyph->fAdvanceY = SkScalarToFloat(advance.fY);
483     return true;
484 }
485 
getBoundingBox(SkGlyph * glyph,DWRITE_RENDERING_MODE renderingMode,DWRITE_TEXTURE_TYPE textureType,RECT * bbox)486 HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
487                                            DWRITE_RENDERING_MODE renderingMode,
488                                            DWRITE_TEXTURE_TYPE textureType,
489                                            RECT* bbox)
490 {
491     DWriteFontTypeface* typeface = this->getDWriteTypeface();
492 
493     //Measure raster size.
494     fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
495     fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
496 
497     FLOAT advance = 0;
498 
499     UINT16 glyphId = glyph->getGlyphID();
500 
501     DWRITE_GLYPH_OFFSET offset;
502     offset.advanceOffset = 0.0f;
503     offset.ascenderOffset = 0.0f;
504 
505     DWRITE_GLYPH_RUN run;
506     run.glyphCount = 1;
507     run.glyphAdvances = &advance;
508     run.fontFace = typeface->fDWriteFontFace.get();
509     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
510     run.bidiLevel = 0;
511     run.glyphIndices = &glyphId;
512     run.isSideways = FALSE;
513     run.glyphOffsets = &offset;
514 
515     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
516     {
517         Exclusive l(maybe_dw_mutex(*typeface));
518         // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
519         if (typeface->fFactory2 &&
520                 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
521                  fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
522         {
523             HRM(typeface->fFactory2->CreateGlyphRunAnalysis(
524                     &run,
525                     &fXform,
526                     renderingMode,
527                     fMeasuringMode,
528                     fGridFitMode,
529                     fAntiAliasMode,
530                     0.0f, // baselineOriginX,
531                     0.0f, // baselineOriginY,
532                     &glyphRunAnalysis),
533                 "Could not create DW2 glyph run analysis.");
534         } else {
535             HRM(typeface->fFactory->CreateGlyphRunAnalysis(&run,
536                     1.0f, // pixelsPerDip,
537                     &fXform,
538                     renderingMode,
539                     fMeasuringMode,
540                     0.0f, // baselineOriginX,
541                     0.0f, // baselineOriginY,
542                     &glyphRunAnalysis),
543                 "Could not create glyph run analysis.");
544         }
545     }
546     {
547         Shared l(maybe_dw_mutex(*typeface));
548         HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
549             "Could not get texture bounds.");
550     }
551     return S_OK;
552 }
553 
isColorGlyph(const SkGlyph & glyph)554 bool SkScalerContext_DW::isColorGlyph(const SkGlyph& glyph) {
555     // One would think that with newer DirectWrite that this could be like isPngGlyph
556     // except test for DWRITE_GLYPH_IMAGE_FORMATS_COLR, but that doesn't seem to work.
557 
558     SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayer;
559     return getColorGlyphRun(glyph, &colorLayer);
560 }
561 
isPngGlyph(const SkGlyph & glyph)562 bool SkScalerContext_DW::isPngGlyph(const SkGlyph& glyph) {
563     if (!this->getDWriteTypeface()->fDWriteFontFace4) {
564         return false;
565     }
566 
567     DWRITE_GLYPH_IMAGE_FORMATS f;
568     IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->fDWriteFontFace4.get();
569     HRBM(fontFace4->GetGlyphImageFormats(glyph.getGlyphID(), 0, UINT32_MAX, &f),
570          "Cannot get glyph image formats.");
571     return f & DWRITE_GLYPH_IMAGE_FORMATS_PNG;
572 }
573 
isSVGGlyph(const SkGlyph & glyph)574 bool SkScalerContext_DW::isSVGGlyph(const SkGlyph& glyph) {
575     if (!SkGraphics::GetOpenTypeSVGDecoderFactory() ||
576         !this->getDWriteTypeface()->fDWriteFontFace4)
577     {
578         return false;
579     }
580 
581     DWRITE_GLYPH_IMAGE_FORMATS f;
582     IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->fDWriteFontFace4.get();
583     HRBM(fontFace4->GetGlyphImageFormats(glyph.getGlyphID(), 0, UINT32_MAX, &f),
584          "Cannot get glyph image formats.");
585     return f & DWRITE_GLYPH_IMAGE_FORMATS_SVG;
586 }
587 
getColorGlyphRun(const SkGlyph & glyph,IDWriteColorGlyphRunEnumerator ** colorGlyph)588 bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph,
589                                           IDWriteColorGlyphRunEnumerator** colorGlyph)
590 {
591     FLOAT advance = 0;
592     UINT16 glyphId = glyph.getGlyphID();
593 
594     DWRITE_GLYPH_OFFSET offset;
595     offset.advanceOffset = 0.0f;
596     offset.ascenderOffset = 0.0f;
597 
598     DWRITE_GLYPH_RUN run;
599     run.glyphCount = 1;
600     run.glyphAdvances = &advance;
601     run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
602     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
603     run.bidiLevel = 0;
604     run.glyphIndices = &glyphId;
605     run.isSideways = FALSE;
606     run.glyphOffsets = &offset;
607 
608     HRESULT hr = this->getDWriteTypeface()->fFactory2->TranslateColorGlyphRun(
609         0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph);
610     if (hr == DWRITE_E_NOCOLOR) {
611         return false;
612     }
613     HRBM(hr, "Failed to translate color glyph run");
614     return true;
615 }
616 
SetGlyphBounds(SkGlyph * glyph,const SkRect & bounds)617 void SkScalerContext_DW::SetGlyphBounds(SkGlyph* glyph, const SkRect& bounds) {
618     SkIRect ibounds = bounds.roundOut();
619 
620     if (!SkTFitsIn<decltype(glyph->fWidth )>(ibounds.width ()) ||
621         !SkTFitsIn<decltype(glyph->fHeight)>(ibounds.height()) ||
622         !SkTFitsIn<decltype(glyph->fTop   )>(ibounds.top   ()) ||
623         !SkTFitsIn<decltype(glyph->fLeft  )>(ibounds.left  ())  )
624     {
625         ibounds = SkIRect::MakeEmpty();
626     }
627 
628     glyph->fWidth  = SkToU16(ibounds.width ());
629     glyph->fHeight = SkToU16(ibounds.height());
630     glyph->fTop    = SkToS16(ibounds.top   ());
631     glyph->fLeft   = SkToS16(ibounds.left  ());
632 }
633 
generateColorMetrics(SkGlyph * glyph)634 bool SkScalerContext_DW::generateColorMetrics(SkGlyph* glyph) {
635     SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers;
636     if (!getColorGlyphRun(*glyph, &colorLayers)) {
637         return false;
638     }
639     SkASSERT(colorLayers.get());
640 
641     SkRect bounds = SkRect::MakeEmpty();
642     BOOL hasNextRun = FALSE;
643     while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) {
644         const DWRITE_COLOR_GLYPH_RUN* colorGlyph;
645         HRBM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run");
646 
647         SkPath path;
648         SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
649         HRBM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
650             "Could not create geometry to path converter.");
651         {
652             Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
653             HRBM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
654                     colorGlyph->glyphRun.fontEmSize,
655                     colorGlyph->glyphRun.glyphIndices,
656                     colorGlyph->glyphRun.glyphAdvances,
657                     colorGlyph->glyphRun.glyphOffsets,
658                     colorGlyph->glyphRun.glyphCount,
659                     colorGlyph->glyphRun.isSideways,
660                     colorGlyph->glyphRun.bidiLevel % 2, //rtl
661                     geometryToPath.get()),
662                 "Could not create glyph outline.");
663         }
664         bounds.join(path.getBounds());
665     }
666     SkMatrix matrix = fSkXform;
667     if (this->isSubpixel()) {
668         matrix.postTranslate(SkFixedToScalar(glyph->getSubXFixed()),
669                              SkFixedToScalar(glyph->getSubYFixed()));
670     }
671     matrix.mapRect(&bounds);
672     SetGlyphBounds(glyph, bounds);
673     return true;
674 }
675 
generateSVGMetrics(SkGlyph * glyph)676 bool SkScalerContext_DW::generateSVGMetrics(SkGlyph* glyph) {
677     SkPictureRecorder recorder;
678     SkRect infiniteRect = SkRect::MakeLTRB(-SK_ScalarInfinity, -SK_ScalarInfinity,
679                                             SK_ScalarInfinity,  SK_ScalarInfinity);
680     sk_sp<SkBBoxHierarchy> bboxh = SkRTreeFactory()();
681     SkCanvas* recordingCanvas = recorder.beginRecording(infiniteRect, bboxh);
682     if (!this->drawSVGGlyphImage(*glyph, *recordingCanvas)) {
683         return false;
684     }
685     sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture();
686     SkRect bounds = pic->cullRect();
687     SkASSERT(bounds.isFinite());
688 
689     SetGlyphBounds(glyph, bounds);
690     return true;
691 }
692 
693 namespace {
694 struct Context {
695     SkTScopedComPtr<IDWriteFontFace4> fontFace4;
696     void* glyphDataContext;
Context__anonaec314400211::Context697     Context(IDWriteFontFace4* face4, void* context)
698         : fontFace4(SkRefComPtr(face4))
699         , glyphDataContext(context)
700     {}
701 };
702 
ReleaseProc(const void * ptr,void * context)703 static void ReleaseProc(const void* ptr, void* context) {
704     Context* ctx = (Context*)context;
705     ctx->fontFace4->ReleaseGlyphImageData(ctx->glyphDataContext);
706     delete ctx;
707 }
708 }
709 
generatePngMetrics(SkGlyph * glyph)710 bool SkScalerContext_DW::generatePngMetrics(SkGlyph* glyph) {
711     SkASSERT(isPngGlyph(*glyph));
712     SkASSERT(this->getDWriteTypeface()->fDWriteFontFace4);
713 
714     IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->fDWriteFontFace4.get();
715     DWRITE_GLYPH_IMAGE_DATA glyphData;
716     void* glyphDataContext;
717     HRBM(fontFace4->GetGlyphImageData(glyph->getGlyphID(),
718                                       fTextSizeRender,
719                                       DWRITE_GLYPH_IMAGE_FORMATS_PNG,
720                                       &glyphData,
721                                       &glyphDataContext),
722          "Glyph image data could not be acquired.");
723 
724     Context* context = new Context(fontFace4, glyphDataContext);
725     sk_sp<SkData> data = SkData::MakeWithProc(glyphData.imageData,
726                                               glyphData.imageDataSize,
727                                               &ReleaseProc,
728                                               context);
729 
730     std::unique_ptr<SkCodec> codec = SkCodec::MakeFromData(std::move(data));
731     if (!codec) {
732         return false;
733     }
734 
735     SkImageInfo info = codec->getInfo();
736     SkRect bounds = SkRect::MakeLTRB(SkIntToScalar(info.bounds().fLeft),
737                                      SkIntToScalar(info.bounds().fTop),
738                                      SkIntToScalar(info.bounds().fRight),
739                                      SkIntToScalar(info.bounds().fBottom));
740 
741     SkMatrix matrix = fSkXform;
742     SkScalar scale = fTextSizeRender / glyphData.pixelsPerEm;
743     matrix.preScale(scale, scale);
744     matrix.preTranslate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y);
745     if (this->isSubpixel()) {
746         matrix.postTranslate(SkFixedToScalar(glyph->getSubXFixed()),
747                              SkFixedToScalar(glyph->getSubYFixed()));
748     }
749     matrix.mapRect(&bounds);
750     SetGlyphBounds(glyph, bounds);
751     return true;
752 }
753 
generateMetrics(SkGlyph * glyph,SkArenaAlloc * alloc)754 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph, SkArenaAlloc* alloc) {
755 
756      // GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
757      // { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
758      // for small but not quite zero and large (but not really large) glyphs,
759      // Only set as non-empty if the returned bounds are non-empty.
760     auto glyphCheckAndSetBounds = [](SkGlyph* glyph, const RECT& bbox) {
761         if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
762             return false;
763         }
764 
765         // We're trying to pack left and top into int16_t,
766         // and width and height into uint16_t, after outsetting by 1.
767         if (!SkIRect::MakeXYWH(-32767, -32767, 65535, 65535).contains(
768                     SkIRect::MakeLTRB(bbox.left, bbox.top, bbox.right, bbox.bottom))) {
769             return false;
770         }
771 
772         glyph->fWidth = SkToU16(bbox.right - bbox.left);
773         glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
774         glyph->fLeft = SkToS16(bbox.left);
775         glyph->fTop = SkToS16(bbox.top);
776         return true;
777     };
778 
779     glyph->fWidth = 0;
780     glyph->fHeight = 0;
781     glyph->fLeft = 0;
782     glyph->fTop = 0;
783 
784     if (!this->generateAdvance(glyph)) {
785         return;
786     }
787 
788     DWriteFontTypeface* typeface = this->getDWriteTypeface();
789     if (typeface->fIsColorFont) {
790         if (isColorGlyph(*glyph) && generateColorMetrics(glyph)) {
791             glyph->fMaskFormat = SkMask::kARGB32_Format;
792             glyph->fScalerContextBits |= ScalerContextBits::COLR;
793             glyph->setPath(alloc, nullptr, false);
794             return;
795         }
796 
797         if (isSVGGlyph(*glyph) && generateSVGMetrics(glyph)) {
798             glyph->fMaskFormat = SkMask::kARGB32_Format;
799             glyph->fScalerContextBits |= ScalerContextBits::SVG;
800             glyph->setPath(alloc, nullptr, false);
801             return;
802         }
803 
804         if (isPngGlyph(*glyph) && generatePngMetrics(glyph)) {
805             glyph->fMaskFormat = SkMask::kARGB32_Format;
806             glyph->fScalerContextBits |= ScalerContextBits::PNG;
807             glyph->setPath(alloc, nullptr, false);
808             return;
809         }
810     }
811 
812     RECT bbox;
813     HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox),
814          "Requested bounding box could not be determined.");
815 
816     if (glyphCheckAndSetBounds(glyph, bbox)) {
817         return;
818     }
819 
820     // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
821     // glyphs of the specified texture type or it is too big for smoothing.
822     // When this happens, try with the alternate texture type.
823     if (DWRITE_TEXTURE_ALIASED_1x1 != fTextureType ||
824         DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE == fAntiAliasMode)
825     {
826         HRVM(this->getBoundingBox(glyph,
827                                   DWRITE_RENDERING_MODE_ALIASED,
828                                   DWRITE_TEXTURE_ALIASED_1x1,
829                                   &bbox),
830              "Fallback bounding box could not be determined.");
831         if (glyphCheckAndSetBounds(glyph, bbox)) {
832             glyph->fScalerContextBits |= ScalerContextBits::ForceBW;
833             glyph->fMaskFormat = SkMask::kBW_Format;
834         }
835     }
836     // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
837     // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
838 
839     // GetAlphaTextureBounds can fail for various reasons. As a fallback, attempt to generate the
840     // metrics from the path
841     SkDEBUGCODE(glyph->fAdvancesBoundsFormatAndInitialPathDone = true;)
842     this->getPath(*glyph, alloc);
843     const SkPath* devPath = glyph->path();
844     if (devPath) {
845         // Sometimes all the above fails. If so, try to create the glyph from path.
846         const SkMask::Format format = glyph->maskFormat();
847         const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
848         const bool a8LCD = SkToBool(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag);
849         const bool hairline = glyph->pathIsHairline();
850         if (GenerateMetricsFromPath(glyph, *devPath, format, doVert, a8LCD, hairline)) {
851             glyph->fScalerContextBits |= ScalerContextBits::PATH;
852         }
853     }
854 }
855 
generateFontMetrics(SkFontMetrics * metrics)856 void SkScalerContext_DW::generateFontMetrics(SkFontMetrics* metrics) {
857     if (nullptr == metrics) {
858         return;
859     }
860 
861     sk_bzero(metrics, sizeof(*metrics));
862 
863     DWRITE_FONT_METRICS dwfm;
864     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
865         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
866     {
867         this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleMetrics(
868              fTextSizeRender,
869              1.0f, // pixelsPerDip
870              &fXform,
871              &dwfm);
872     } else {
873         this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm);
874     }
875 
876     SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
877 
878     metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
879     metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
880     metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
881     metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
882     metrics->fCapHeight = fTextSizeRender * SkIntToScalar(dwfm.capHeight) / upem;
883     metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
884     metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
885     metrics->fStrikeoutThickness = fTextSizeRender * SkIntToScalar(dwfm.strikethroughThickness) / upem;
886     metrics->fStrikeoutPosition = -(fTextSizeRender * SkIntToScalar(dwfm.strikethroughPosition) / upem);
887 
888     metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag;
889     metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag;
890     metrics->fFlags |= SkFontMetrics::kStrikeoutThicknessIsValid_Flag;
891     metrics->fFlags |= SkFontMetrics::kStrikeoutPositionIsValid_Flag;
892 
893     SkTScopedComPtr<IDWriteFontFace5> fontFace5;
894     if (SUCCEEDED(this->getDWriteTypeface()->fDWriteFontFace->QueryInterface(&fontFace5))) {
895         if (fontFace5->HasVariations()) {
896             // The bounds are only valid for the default variation.
897             metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag;
898         }
899     }
900 
901     if (this->getDWriteTypeface()->fDWriteFontFace1.get()) {
902         DWRITE_FONT_METRICS1 dwfm1;
903         this->getDWriteTypeface()->fDWriteFontFace1->GetMetrics(&dwfm1);
904         metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
905         metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
906         metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
907         metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
908 
909         metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
910         return;
911     }
912 
913     AutoTDWriteTable<SkOTTableHead> head(this->getDWriteTypeface()->fDWriteFontFace.get());
914     if (head.fExists &&
915         head.fSize >= sizeof(SkOTTableHead) &&
916         head->version == SkOTTableHead::version1)
917     {
918         metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
919         metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
920         metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
921         metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
922 
923         metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
924         return;
925     }
926 
927     // The real bounds weren't actually available.
928     metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag;
929     metrics->fTop = metrics->fAscent;
930     metrics->fBottom = metrics->fDescent;
931 }
932 
933 ///////////////////////////////////////////////////////////////////////////////
934 
935 #include "include/private/SkColorData.h"
936 
BilevelToBW(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph)937 void SkScalerContext_DW::BilevelToBW(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
938     const int width = glyph.width();
939     const size_t dstRB = (width + 7) >> 3;
940     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
941 
942     int byteCount = width >> 3;
943     int bitCount = width & 7;
944 
945     for (int y = 0; y < glyph.height(); ++y) {
946         if (byteCount > 0) {
947             for (int i = 0; i < byteCount; ++i) {
948                 unsigned byte = 0;
949                 byte |= src[0] & (1 << 7);
950                 byte |= src[1] & (1 << 6);
951                 byte |= src[2] & (1 << 5);
952                 byte |= src[3] & (1 << 4);
953                 byte |= src[4] & (1 << 3);
954                 byte |= src[5] & (1 << 2);
955                 byte |= src[6] & (1 << 1);
956                 byte |= src[7] & (1 << 0);
957                 dst[i] = byte;
958                 src += 8;
959             }
960         }
961         if (bitCount > 0) {
962             unsigned byte = 0;
963             unsigned mask = 0x80;
964             for (int i = 0; i < bitCount; i++) {
965                 byte |= (src[i]) & mask;
966                 mask >>= 1;
967             }
968             dst[byteCount] = byte;
969         }
970         src += bitCount;
971         dst += dstRB;
972     }
973 
974     if constexpr (kSkShowTextBlitCoverage) {
975         dst = static_cast<uint8_t*>(glyph.fImage);
976         for (unsigned y = 0; y < (unsigned)glyph.height(); y += 2) {
977             for (unsigned x = (y & 0x2); x < (unsigned)glyph.width(); x+=4) {
978                 uint8_t& b = dst[(dstRB * y) + (x >> 3)];
979                 b = b ^ (1 << (0x7 - (x & 0x7)));
980             }
981         }
982     }
983 }
984 
985 template<bool APPLY_PREBLEND>
GrayscaleToA8(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph,const uint8_t * table8)986 void SkScalerContext_DW::GrayscaleToA8(const uint8_t* SK_RESTRICT src,
987                                        const SkGlyph& glyph,
988                                        const uint8_t* table8) {
989     const size_t dstRB = glyph.rowBytes();
990     const int width = glyph.width();
991     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
992 
993     for (int y = 0; y < glyph.height(); y++) {
994         for (int i = 0; i < width; i++) {
995             U8CPU a = *(src++);
996             dst[i] = sk_apply_lut_if<APPLY_PREBLEND>(a, table8);
997             if constexpr (kSkShowTextBlitCoverage) {
998                 dst[i] = std::max<U8CPU>(0x30, dst[i]);
999             }
1000         }
1001         dst = SkTAddOffset<uint8_t>(dst, dstRB);
1002     }
1003 }
1004 
1005 template<bool APPLY_PREBLEND>
RGBToA8(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph,const uint8_t * table8)1006 void SkScalerContext_DW::RGBToA8(const uint8_t* SK_RESTRICT src,
1007                                  const SkGlyph& glyph,
1008                                  const uint8_t* table8) {
1009     const size_t dstRB = glyph.rowBytes();
1010     const int width = glyph.width();
1011     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
1012 
1013     for (int y = 0; y < glyph.height(); y++) {
1014         for (int i = 0; i < width; i++) {
1015             U8CPU r = *(src++);
1016             U8CPU g = *(src++);
1017             U8CPU b = *(src++);
1018             dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
1019             if constexpr (kSkShowTextBlitCoverage) {
1020                 dst[i] = std::max<U8CPU>(0x30, dst[i]);
1021             }
1022         }
1023         dst = SkTAddOffset<uint8_t>(dst, dstRB);
1024     }
1025 }
1026 
1027 template<bool APPLY_PREBLEND, bool RGB>
RGBToLcd16(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1028 void SkScalerContext_DW::RGBToLcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
1029                                     const uint8_t* tableR, const uint8_t* tableG,
1030                                     const uint8_t* tableB) {
1031     const size_t dstRB = glyph.rowBytes();
1032     const int width = glyph.width();
1033     uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
1034 
1035     for (int y = 0; y < glyph.height(); y++) {
1036         for (int i = 0; i < width; i++) {
1037             U8CPU r, g, b;
1038             if (RGB) {
1039                 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
1040                 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
1041                 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
1042             } else {
1043                 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
1044                 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
1045                 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
1046             }
1047             if constexpr (kSkShowTextBlitCoverage) {
1048                 r = std::max<U8CPU>(0x30, r);
1049                 g = std::max<U8CPU>(0x30, g);
1050                 b = std::max<U8CPU>(0x30, b);
1051             }
1052             dst[i] = SkPack888ToRGB16(r, g, b);
1053         }
1054         dst = SkTAddOffset<uint16_t>(dst, dstRB);
1055     }
1056 }
1057 
drawDWMask(const SkGlyph & glyph,DWRITE_RENDERING_MODE renderingMode,DWRITE_TEXTURE_TYPE textureType)1058 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
1059                                            DWRITE_RENDERING_MODE renderingMode,
1060                                            DWRITE_TEXTURE_TYPE textureType)
1061 {
1062     DWriteFontTypeface* typeface = this->getDWriteTypeface();
1063 
1064     int sizeNeeded = glyph.width() * glyph.height();
1065     if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) {
1066         sizeNeeded *= 3;
1067     }
1068     if (sizeNeeded > fBits.size()) {
1069         fBits.resize(sizeNeeded);
1070     }
1071 
1072     // erase
1073     memset(fBits.begin(), 0, sizeNeeded);
1074 
1075     fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
1076     fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
1077 
1078     FLOAT advance = 0.0f;
1079 
1080     UINT16 index = glyph.getGlyphID();
1081 
1082     DWRITE_GLYPH_OFFSET offset;
1083     offset.advanceOffset = 0.0f;
1084     offset.ascenderOffset = 0.0f;
1085 
1086     DWRITE_GLYPH_RUN run;
1087     run.glyphCount = 1;
1088     run.glyphAdvances = &advance;
1089     run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
1090     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
1091     run.bidiLevel = 0;
1092     run.glyphIndices = &index;
1093     run.isSideways = FALSE;
1094     run.glyphOffsets = &offset;
1095     {
1096         SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
1097         {
1098             Exclusive l(maybe_dw_mutex(*typeface));
1099             // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
1100             if (this->getDWriteTypeface()->fFactory2 &&
1101                     (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
1102                      fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
1103             {
1104                 HRNM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis(&run,
1105                          &fXform,
1106                          renderingMode,
1107                          fMeasuringMode,
1108                          fGridFitMode,
1109                          fAntiAliasMode,
1110                          0.0f, // baselineOriginX,
1111                          0.0f, // baselineOriginY,
1112                          &glyphRunAnalysis),
1113                      "Could not create DW2 glyph run analysis.");
1114             } else {
1115                 HRNM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run,
1116                          1.0f, // pixelsPerDip,
1117                          &fXform,
1118                          renderingMode,
1119                          fMeasuringMode,
1120                          0.0f, // baselineOriginX,
1121                          0.0f, // baselineOriginY,
1122                          &glyphRunAnalysis),
1123                      "Could not create glyph run analysis.");
1124             }
1125         }
1126         //NOTE: this assumes that the glyph has already been measured
1127         //with an exact same glyph run analysis.
1128         RECT bbox;
1129         bbox.left = glyph.left();
1130         bbox.top = glyph.top();
1131         bbox.right = glyph.left() + glyph.width();
1132         bbox.bottom = glyph.top() + glyph.height();
1133         {
1134             Shared l(maybe_dw_mutex(*typeface));
1135             HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
1136                     &bbox,
1137                     fBits.begin(),
1138                     sizeNeeded),
1139                 "Could not draw mask.");
1140         }
1141     }
1142     return fBits.begin();
1143 }
1144 
drawColorGlyphImage(const SkGlyph & glyph,SkCanvas & canvas)1145 bool SkScalerContext_DW::drawColorGlyphImage(const SkGlyph& glyph, SkCanvas& canvas) {
1146     SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers;
1147     if (!getColorGlyphRun(glyph, &colorLayers)) {
1148         SkASSERTF(false, "Could not get color layers");
1149         return false;
1150     }
1151 
1152     SkPaint paint;
1153     paint.setAntiAlias(fRenderingMode != DWRITE_RENDERING_MODE_ALIASED);
1154 
1155     if (this->isSubpixel()) {
1156         canvas.translate(SkFixedToScalar(glyph.getSubXFixed()),
1157                          SkFixedToScalar(glyph.getSubYFixed()));
1158     }
1159     canvas.concat(fSkXform);
1160 
1161     DWriteFontTypeface* typeface = this->getDWriteTypeface();
1162     size_t paletteEntryCount = typeface->fPaletteEntryCount;
1163     SkColor* palette = typeface->fPalette.get();
1164     BOOL hasNextRun = FALSE;
1165     while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) {
1166         const DWRITE_COLOR_GLYPH_RUN* colorGlyph;
1167         HRBM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run");
1168 
1169         SkColor color;
1170         if (colorGlyph->paletteIndex == 0xffff) {
1171             color = fRec.fForegroundColor;
1172         } else if (colorGlyph->paletteIndex < paletteEntryCount) {
1173             color = palette[colorGlyph->paletteIndex];
1174         } else {
1175             SK_TRACEHR(DWRITE_E_NOCOLOR, "Invalid palette index.");
1176             color = SK_ColorBLACK;
1177         }
1178         paint.setColor(color);
1179 
1180         SkPath path;
1181         SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1182         HRBM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
1183              "Could not create geometry to path converter.");
1184         {
1185             Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
1186             HRBM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
1187                      colorGlyph->glyphRun.fontEmSize,
1188                      colorGlyph->glyphRun.glyphIndices,
1189                      colorGlyph->glyphRun.glyphAdvances,
1190                      colorGlyph->glyphRun.glyphOffsets,
1191                      colorGlyph->glyphRun.glyphCount,
1192                      colorGlyph->glyphRun.isSideways,
1193                      colorGlyph->glyphRun.bidiLevel % 2, //rtl
1194                      geometryToPath.get()),
1195                  "Could not create glyph outline.");
1196         }
1197         canvas.drawPath(path, paint);
1198     }
1199     return true;
1200 }
1201 
generateColorGlyphImage(const SkGlyph & glyph)1202 bool SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) {
1203     SkASSERT(isColorGlyph(glyph));
1204     SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format);
1205 
1206     SkBitmap dstBitmap;
1207     // TODO: mark this as sRGB when the blits will be sRGB.
1208     dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
1209                                         kN32_SkColorType, kPremul_SkAlphaType),
1210                                         glyph.rowBytes());
1211     dstBitmap.setPixels(glyph.fImage);
1212 
1213     SkCanvas canvas(dstBitmap);
1214     if constexpr (kSkShowTextBlitCoverage) {
1215         canvas.clear(0x33FF0000);
1216     } else {
1217         canvas.clear(SK_ColorTRANSPARENT);
1218     }
1219     canvas.translate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop));
1220 
1221     return this->drawColorGlyphImage(glyph, canvas);
1222 }
1223 
drawSVGGlyphImage(const SkGlyph & glyph,SkCanvas & canvas)1224 bool SkScalerContext_DW::drawSVGGlyphImage(const SkGlyph& glyph, SkCanvas& canvas) {
1225     SkASSERT(isSVGGlyph(glyph));
1226     SkASSERT(this->getDWriteTypeface()->fDWriteFontFace4);
1227 
1228     SkGraphics::OpenTypeSVGDecoderFactory svgFactory = SkGraphics::GetOpenTypeSVGDecoderFactory();
1229     if (!svgFactory) {
1230         return false;
1231     }
1232 
1233     DWriteFontTypeface* typeface = this->getDWriteTypeface();
1234     IDWriteFontFace4* fontFace4 = typeface->fDWriteFontFace4.get();
1235     DWRITE_GLYPH_IMAGE_DATA glyphData;
1236     void* glyphDataContext;
1237     HRBM(fontFace4->GetGlyphImageData(glyph.getGlyphID(),
1238                                       fTextSizeRender,
1239                                       DWRITE_GLYPH_IMAGE_FORMATS_SVG,
1240                                       &glyphData,
1241                                       &glyphDataContext),
1242          "Glyph SVG data could not be acquired.");
1243     auto svgDecoder = svgFactory((const uint8_t*)glyphData.imageData, glyphData.imageDataSize);
1244     fontFace4->ReleaseGlyphImageData(glyphDataContext);
1245     if (!svgDecoder) {
1246         return false;
1247     }
1248 
1249     size_t paletteEntryCount = typeface->fPaletteEntryCount;
1250     SkColor* palette = typeface->fPalette.get();
1251     int upem = typeface->getUnitsPerEm();
1252 
1253     SkMatrix matrix = fSkXform;
1254     SkScalar scale = fTextSizeRender / upem;
1255     matrix.preScale(scale, scale);
1256     matrix.preTranslate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y);
1257     if (this->isSubpixel()) {
1258         matrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
1259                              SkFixedToScalar(glyph.getSubYFixed()));
1260     }
1261     canvas.concat(matrix);
1262 
1263     return svgDecoder->render(canvas, upem, glyph.getGlyphID(),
1264                               fRec.fForegroundColor, SkSpan(palette, paletteEntryCount));
1265 }
1266 
generateSVGGlyphImage(const SkGlyph & glyph)1267 bool SkScalerContext_DW::generateSVGGlyphImage(const SkGlyph& glyph) {
1268     SkASSERT(isSVGGlyph(glyph));
1269     SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format);
1270 
1271     SkBitmap dstBitmap;
1272     // TODO: mark this as sRGB when the blits will be sRGB.
1273     dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
1274         kN32_SkColorType, kPremul_SkAlphaType),
1275         glyph.rowBytes());
1276     dstBitmap.setPixels(glyph.fImage);
1277 
1278     SkCanvas canvas(dstBitmap);
1279     if constexpr (kSkShowTextBlitCoverage) {
1280         canvas.clear(0x33FF0000);
1281     } else {
1282         canvas.clear(SK_ColorTRANSPARENT);
1283     }
1284     canvas.translate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop));
1285 
1286     return this->drawSVGGlyphImage(glyph, canvas);
1287 }
1288 
drawPngGlyphImage(const SkGlyph & glyph,SkCanvas & canvas)1289 bool SkScalerContext_DW::drawPngGlyphImage(const SkGlyph& glyph, SkCanvas& canvas) {
1290     IDWriteFontFace4* fontFace4 = this->getDWriteTypeface()->fDWriteFontFace4.get();
1291     DWRITE_GLYPH_IMAGE_DATA glyphData;
1292     void* glyphDataContext;
1293     HRBM(fontFace4->GetGlyphImageData(glyph.getGlyphID(),
1294                                       fTextSizeRender,
1295                                       DWRITE_GLYPH_IMAGE_FORMATS_PNG,
1296                                       &glyphData,
1297                                       &glyphDataContext),
1298          "Glyph image data could not be acquired.");
1299     Context* context = new Context(fontFace4, glyphDataContext);
1300     sk_sp<SkData> data = SkData::MakeWithProc(glyphData.imageData,
1301                                               glyphData.imageDataSize,
1302                                               &ReleaseProc,
1303                                               context);
1304     sk_sp<SkImage> image = SkImage::MakeFromEncoded(std::move(data));
1305     if (!image) {
1306         return false;
1307     }
1308 
1309     if (this->isSubpixel()) {
1310         canvas.translate(SkFixedToScalar(glyph.getSubXFixed()),
1311                          SkFixedToScalar(glyph.getSubYFixed()));
1312     }
1313     canvas.concat(fSkXform);
1314     SkScalar ratio = fTextSizeRender / glyphData.pixelsPerEm;
1315     canvas.scale(ratio, ratio);
1316     canvas.translate(-glyphData.horizontalLeftOrigin.x, -glyphData.horizontalLeftOrigin.y);
1317     canvas.drawImage(image, 0, 0);
1318     return true;
1319 }
1320 
generatePngGlyphImage(const SkGlyph & glyph)1321 bool SkScalerContext_DW::generatePngGlyphImage(const SkGlyph& glyph) {
1322     SkASSERT(isPngGlyph(glyph));
1323     SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format);
1324     SkASSERT(this->getDWriteTypeface()->fDWriteFontFace4);
1325 
1326     SkBitmap dstBitmap;
1327     dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(),
1328                                         kN32_SkColorType, kPremul_SkAlphaType),
1329                                         glyph.rowBytes());
1330     dstBitmap.setPixels(glyph.fImage);
1331 
1332     SkCanvas canvas(dstBitmap);
1333     canvas.clear(SK_ColorTRANSPARENT);
1334     canvas.translate(-glyph.left(), -glyph.top());
1335 
1336     return this->drawPngGlyphImage(glyph, canvas);
1337 }
1338 
generateImage(const SkGlyph & glyph)1339 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
1340     ScalerContextBits::value_type format = glyph.fScalerContextBits & ScalerContextBits::FormatMask;
1341     if (format == ScalerContextBits::COLR) {
1342         this->generateColorGlyphImage(glyph);
1343         return;
1344     }
1345     if (format == ScalerContextBits::SVG) {
1346         this->generateSVGGlyphImage(glyph);
1347         return;
1348     }
1349     if (format == ScalerContextBits::PNG) {
1350         this->generatePngGlyphImage(glyph);
1351         return;
1352     }
1353     if (format == ScalerContextBits::PATH) {
1354         const SkPath* devPath = glyph.path();
1355         SkASSERT_RELEASE(devPath);
1356         SkMask mask = glyph.mask();
1357         SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
1358         const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
1359         const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
1360         const bool a8LCD = SkToBool(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag);
1361         const bool hairline = glyph.pathIsHairline();
1362         GenerateImageFromPath(mask, *devPath, fPreBlend, doBGR, doVert, a8LCD, hairline);
1363         return;
1364     }
1365 
1366     //Create the mask.
1367     DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
1368     DWRITE_TEXTURE_TYPE textureType = fTextureType;
1369     if (glyph.fScalerContextBits & ScalerContextBits::ForceBW) {
1370         renderingMode = DWRITE_RENDERING_MODE_ALIASED;
1371         textureType = DWRITE_TEXTURE_ALIASED_1x1;
1372     }
1373     const void* bits = this->drawDWMask(glyph, renderingMode, textureType);
1374     if (!bits) {
1375         sk_bzero(glyph.fImage, glyph.imageSize());
1376         return;
1377     }
1378 
1379     //Copy the mask into the glyph.
1380     const uint8_t* src = (const uint8_t*)bits;
1381     if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
1382         SkASSERT(SkMask::kBW_Format == glyph.fMaskFormat);
1383         SkASSERT(DWRITE_TEXTURE_ALIASED_1x1 == textureType);
1384         BilevelToBW(src, glyph);
1385     } else if (!isLCD(fRec)) {
1386         if (textureType == DWRITE_TEXTURE_ALIASED_1x1) {
1387             if (fPreBlend.isApplicable()) {
1388                 GrayscaleToA8<true>(src, glyph, fPreBlend.fG);
1389             } else {
1390                 GrayscaleToA8<false>(src, glyph, fPreBlend.fG);
1391             }
1392         } else {
1393             if (fPreBlend.isApplicable()) {
1394                 RGBToA8<true>(src, glyph, fPreBlend.fG);
1395             } else {
1396                 RGBToA8<false>(src, glyph, fPreBlend.fG);
1397             }
1398         }
1399     } else {
1400         SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat);
1401         if (fPreBlend.isApplicable()) {
1402             if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
1403                 RGBToLcd16<true, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1404             } else {
1405                 RGBToLcd16<true, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1406             }
1407         } else {
1408             if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
1409                 RGBToLcd16<false, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1410             } else {
1411                 RGBToLcd16<false, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1412             }
1413         }
1414     }
1415 }
1416 
generatePath(const SkGlyph & glyph,SkPath * path)1417 bool SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
1418     SkASSERT(path);
1419     path->reset();
1420 
1421     SkGlyphID glyphID = glyph.getGlyphID();
1422 
1423     // DirectWrite treats all out of bounds glyph ids as having the same data as glyph 0.
1424     // For consistency with all other backends, treat out of range glyph ids as an error.
1425     if (fGlyphCount <= glyphID) {
1426         return false;
1427     }
1428 
1429     SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1430     HRBM(SkDWriteGeometrySink::Create(path, &geometryToPath),
1431          "Could not create geometry to path converter.");
1432     UINT16 glyphId = SkTo<UINT16>(glyphID);
1433     {
1434         Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
1435         //TODO: convert to<->from DIUs? This would make a difference if hinting.
1436         //It may not be needed, it appears that DirectWrite only hints at em size.
1437         HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
1438              SkScalarToFloat(fTextSizeRender),
1439              &glyphId,
1440              nullptr, //advances
1441              nullptr, //offsets
1442              1, //num glyphs
1443              FALSE, //sideways
1444              FALSE, //rtl
1445              geometryToPath.get()),
1446              "Could not create glyph outline.");
1447     }
1448 
1449     path->transform(fSkXform);
1450     return true;
1451 }
1452 
generateDrawable(const SkGlyph & glyph)1453 sk_sp<SkDrawable> SkScalerContext_DW::generateDrawable(const SkGlyph& glyph) {
1454     struct GlyphDrawable : public SkDrawable {
1455         SkScalerContext_DW* fSelf;
1456         SkGlyph fGlyph;
1457         GlyphDrawable(SkScalerContext_DW* self, const SkGlyph& glyph) : fSelf(self), fGlyph(glyph){}
1458         SkRect onGetBounds() override { return fGlyph.rect();  }
1459         size_t onApproximateBytesUsed() override { return sizeof(GlyphDrawable); }
1460         void maybeShowTextBlitCoverage(SkCanvas* canvas) {
1461             if constexpr (kSkShowTextBlitCoverage) {
1462                 SkPaint paint;
1463                 paint.setColor(0x3300FF00);
1464                 paint.setStyle(SkPaint::kFill_Style);
1465                 canvas->drawRect(this->onGetBounds(), paint);
1466             }
1467         }
1468     };
1469     struct COLRGlyphDrawable : public GlyphDrawable {
1470         using GlyphDrawable::GlyphDrawable;
1471         void onDraw(SkCanvas* canvas) override {
1472             this->maybeShowTextBlitCoverage(canvas);
1473             fSelf->drawColorGlyphImage(fGlyph, *canvas);
1474         }
1475     };
1476     struct SVGGlyphDrawable : public GlyphDrawable {
1477         using GlyphDrawable::GlyphDrawable;
1478         void onDraw(SkCanvas* canvas) override {
1479             this->maybeShowTextBlitCoverage(canvas);
1480             fSelf->drawSVGGlyphImage(fGlyph, *canvas);
1481         }
1482     };
1483     ScalerContextBits::value_type format = glyph.fScalerContextBits & ScalerContextBits::FormatMask;
1484     if (format == ScalerContextBits::COLR) {
1485         return sk_sp<SkDrawable>(new COLRGlyphDrawable(this, glyph));
1486     }
1487     if (format == ScalerContextBits::SVG) {
1488         return sk_sp<SkDrawable>(new SVGGlyphDrawable(this, glyph));
1489     }
1490     return nullptr;
1491 }
1492 
1493 #endif//defined(SK_BUILD_FOR_WIN)
1494