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