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