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