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