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