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