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