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