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