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