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
8 #include "SkTypes.h"
9 #if defined(SK_BUILD_FOR_WIN32)
10
11 #undef GetGlyphIndices
12
13 #include "SkDraw.h"
14 #include "SkDWrite.h"
15 #include "SkDWriteGeometrySink.h"
16 #include "SkEndian.h"
17 #include "SkGlyph.h"
18 #include "SkHRESULT.h"
19 #include "SkMaskGamma.h"
20 #include "SkMatrix22.h"
21 #include "SkMutex.h"
22 #include "SkOTTable_EBLC.h"
23 #include "SkOTTable_EBSC.h"
24 #include "SkOTTable_gasp.h"
25 #include "SkOTTable_maxp.h"
26 #include "SkPath.h"
27 #include "SkRasterClip.h"
28 #include "SkScalerContext.h"
29 #include "SkScalerContext_win_dw.h"
30 #include "SkSharedMutex.h"
31 #include "SkTScopedComPtr.h"
32 #include "SkTypeface_win_dw.h"
33
34 #include <dwrite.h>
35 #include <dwrite_1.h>
36
37 /* Note:
38 * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe.
39 * The DWriteFactoryMutex protects the calls that are problematic.
40 */
41 static SkSharedMutex DWriteFactoryMutex;
42
43 typedef SkAutoSharedMutexShared Shared;
44
isLCD(const SkScalerContext::Rec & rec)45 static bool isLCD(const SkScalerContext::Rec& rec) {
46 return SkMask::kLCD16_Format == rec.fMaskFormat;
47 }
48
is_hinted_without_gasp(DWriteFontTypeface * typeface)49 static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) {
50 SkAutoExclusive l(DWriteFactoryMutex);
51 AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
52 if (!maxp.fExists) {
53 return false;
54 }
55 if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
56 return false;
57 }
58 if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
59 return false;
60 }
61
62 if (0 == maxp->version.tt.maxSizeOfInstructions) {
63 // No hints.
64 return false;
65 }
66
67 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
68 return !gasp.fExists;
69 }
70
71 /** A GaspRange is inclusive, [min, max]. */
72 struct GaspRange {
73 using Behavior = SkOTTableGridAndScanProcedure::GaspRange::behavior;
GaspRangeGaspRange74 GaspRange(int min, int max, Behavior flags) : fMin(min), fMax(max), fFlags(flags) { }
75 int fMin;
76 int fMax;
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->fFlags = rangeTable->flags;
111 return true;
112 }
113 minPPEM = maxPPEM;
114 }
115 return false;
116 }
117 /** If the rendering mode for the specified 'size' is gridfit, then place
118 * the gridfit range into 'range'. Otherwise, leave 'range' alone.
119 */
is_gridfit_only(GaspRange::Behavior flags)120 static bool is_gridfit_only(GaspRange::Behavior flags) {
121 return flags.raw.value == GaspRange::Behavior::Raw::GridfitMask;
122 }
123
124 /** If the rendering mode for the specified 'size' sets SymmetricSmoothing, return true. */
gasp_allows_cleartype_symmetric(GaspRange::Behavior flags)125 static bool gasp_allows_cleartype_symmetric(GaspRange::Behavior flags) {
126 #ifdef SK_IGNORE_DIRECTWRITE_GASP_FIX
127 return true;
128 #endif
129 return flags.field.SymmetricSmoothing;
130 }
131
has_bitmap_strike(DWriteFontTypeface * typeface,GaspRange range)132 static bool has_bitmap_strike(DWriteFontTypeface* typeface, GaspRange range) {
133 SkAutoExclusive l(DWriteFactoryMutex);
134 {
135 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
136 if (!eblc.fExists) {
137 return false;
138 }
139 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
140 return false;
141 }
142 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
143 return false;
144 }
145
146 uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
147 if (numSizes > 1024 ||
148 eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
149 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
150 {
151 return false;
152 }
153
154 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
155 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
156 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
157 if (sizeTable->ppemX == sizeTable->ppemY &&
158 range.fMin <= sizeTable->ppemX && sizeTable->ppemX <= range.fMax)
159 {
160 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
161 // to determine the actual number of glyphs with bitmaps.
162
163 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
164
165 // TODO: Ensure that the bitmaps are bi-level?
166 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
167 return true;
168 }
169 }
170 }
171 }
172
173 {
174 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
175 if (!ebsc.fExists) {
176 return false;
177 }
178 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
179 return false;
180 }
181 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
182 return false;
183 }
184
185 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
186 if (numSizes > 1024 ||
187 ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
188 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
189 {
190 return false;
191 }
192
193 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
194 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
195 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
196 if (scaleTable->ppemX == scaleTable->ppemY &&
197 range.fMin <= scaleTable->ppemX && scaleTable->ppemX <= range.fMax) {
198 // EBSC tables are normally only found in bitmap only fonts.
199 return true;
200 }
201 }
202 }
203
204 return false;
205 }
206
both_zero(SkScalar a,SkScalar b)207 static bool both_zero(SkScalar a, SkScalar b) {
208 return 0 == a && 0 == b;
209 }
210
211 // returns false if there is any non-90-rotation or skew
is_axis_aligned(const SkScalerContext::Rec & rec)212 static bool is_axis_aligned(const SkScalerContext::Rec& rec) {
213 return 0 == rec.fPreSkewX &&
214 (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
215 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
216 }
217
SkScalerContext_DW(sk_sp<DWriteFontTypeface> typefaceRef,const SkScalerContextEffects & effects,const SkDescriptor * desc)218 SkScalerContext_DW::SkScalerContext_DW(sk_sp<DWriteFontTypeface> typefaceRef,
219 const SkScalerContextEffects& effects,
220 const SkDescriptor* desc)
221 : SkScalerContext(std::move(typefaceRef), effects, desc)
222 , fGlyphCount(-1) {
223
224 DWriteFontTypeface* typeface = this->getDWriteTypeface();
225 fIsColorFont = typeface->fFactory2 &&
226 typeface->fDWriteFontFace2 &&
227 typeface->fDWriteFontFace2->IsColorFont();
228
229 // In general, all glyphs should use NATURAL_SYMMETRIC
230 // except when bi-level rendering is requested or there are embedded
231 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
232 //
233 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
234 // this. As a result, determine the actual size of the text and then see if
235 // there are any embedded bi-level bitmaps of that size. If there are, then
236 // force bitmaps by requesting bi-level rendering.
237 //
238 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
239 // square pixels and only uses ppemY. Therefore the transform must track any
240 // non-uniform x-scale.
241 //
242 // Also, rotated glyphs should have the same absolute advance widths as
243 // horizontal glyphs and the subpixel flag should not affect glyph shapes.
244
245 SkVector scale;
246 SkMatrix GsA;
247 fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale,
248 &scale, &fSkXform, &GsA, &fG_inv);
249
250 fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
251 fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
252 fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
253 fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
254 fXform.dx = 0;
255 fXform.dy = 0;
256
257 fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX));
258 fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
259 fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX));
260 fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY));
261 fGsA.dx = 0;
262 fGsA.dy = 0;
263
264 // realTextSize is the actual device size we want (as opposed to the size the user requested).
265 // gdiTextSize is the size we request when GDI compatible.
266 // If the scale is negative, this means the matrix will do the flip anyway.
267 const SkScalar realTextSize = scale.fY;
268 // Due to floating point math, the lower bits are suspect. Round carefully.
269 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
270 if (gdiTextSize == 0) {
271 gdiTextSize = SK_Scalar1;
272 }
273
274 bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
275 bool treatLikeBitmap = false;
276 bool axisAlignedBitmap = false;
277 if (bitmapRequested) {
278 // When embedded bitmaps are requested, treat the entire range like
279 // a bitmap strike if the range is gridfit only and contains a bitmap.
280 int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
281 GaspRange range(bitmapPPEM, bitmapPPEM, GaspRange::Behavior());
282 if (get_gasp_range(typeface, bitmapPPEM, &range)) {
283 if (!is_gridfit_only(range.fFlags)) {
284 range = GaspRange(bitmapPPEM, bitmapPPEM, GaspRange::Behavior());
285 }
286 }
287 treatLikeBitmap = has_bitmap_strike(typeface, range);
288
289 axisAlignedBitmap = is_axis_aligned(fRec);
290 }
291
292 // If the user requested aliased, do so with aliased compatible metrics.
293 if (SkMask::kBW_Format == fRec.fMaskFormat) {
294 fTextSizeRender = gdiTextSize;
295 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
296 fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
297 fTextSizeMeasure = gdiTextSize;
298 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
299
300 // If we can use a bitmap, use gdi classic rendering and measurement.
301 // This will not always provide a bitmap, but matches expected behavior.
302 } else if (treatLikeBitmap && axisAlignedBitmap) {
303 fTextSizeRender = gdiTextSize;
304 fRenderingMode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
305 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
306 fTextSizeMeasure = gdiTextSize;
307 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
308
309 // If rotated but the horizontal text could have used a bitmap,
310 // render high quality rotated glyphs but measure using bitmap metrics.
311 } else if (treatLikeBitmap) {
312 fTextSizeRender = gdiTextSize;
313 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
314 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
315 fTextSizeMeasure = gdiTextSize;
316 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
317
318 // Fonts that have hints but no gasp table get non-symmetric rendering.
319 // Usually such fonts have low quality hints which were never tested
320 // with anything but GDI ClearType classic. Such fonts often rely on
321 // drop out control in the y direction in order to be legible.
322 } else if (is_hinted_without_gasp(typeface)) {
323 fTextSizeRender = gdiTextSize;
324 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL;
325 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
326 fTextSizeMeasure = realTextSize;
327 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
328
329 // The normal case is to use natural symmetric rendering (if permitted) and linear metrics.
330 } else {
331 fTextSizeRender = realTextSize;
332 GaspRange range(0, 0xFFFF, GaspRange::Behavior());
333 get_gasp_range(typeface, SkScalarTruncToInt(fTextSizeRender), &range);
334 fRenderingMode = gasp_allows_cleartype_symmetric(range.fFlags)
335 ? DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
336 : 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 #ifndef SK_IGNORE_DW_GRAY_FIX
345 if (typeface->fFactory2 && typeface->fDWriteFontFace2 &&
346 SkMask::kA8_Format == fRec.fMaskFormat &&
347 !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag))
348 {
349 // DWRITE_TEXTURE_ALIASED_1x1 is now misnamed, it must also be used with grayscale.
350 fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
351 fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE;
352 }
353 #endif
354
355 // DirectWrite2 allows hinting to be disabled.
356 fGridFitMode = DWRITE_GRID_FIT_MODE_ENABLED;
357 if (fRec.getHinting() == SkPaint::kNo_Hinting) {
358 fGridFitMode = DWRITE_GRID_FIT_MODE_DISABLED;
359 if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) {
360 fRenderingMode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
361 }
362 }
363
364 if (this->isSubpixel()) {
365 fTextSizeMeasure = realTextSize;
366 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
367 }
368 }
369
~SkScalerContext_DW()370 SkScalerContext_DW::~SkScalerContext_DW() {
371 }
372
generateGlyphCount()373 unsigned SkScalerContext_DW::generateGlyphCount() {
374 if (fGlyphCount < 0) {
375 fGlyphCount = this->getDWriteTypeface()->fDWriteFontFace->GetGlyphCount();
376 }
377 return fGlyphCount;
378 }
379
generateCharToGlyph(SkUnichar uni)380 uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
381 uint16_t index = 0;
382 UINT32* uniPtr = reinterpret_cast<UINT32*>(&uni);
383 this->getDWriteTypeface()->fDWriteFontFace->GetGlyphIndices(uniPtr, 1, &index);
384 return index;
385 }
386
generateAdvance(SkGlyph * glyph)387 void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
388 //Delta is the difference between the right/left side bearing metric
389 //and where the right/left side bearing ends up after hinting.
390 //DirectWrite does not provide this information.
391 glyph->fRsbDelta = 0;
392 glyph->fLsbDelta = 0;
393
394 glyph->fAdvanceX = 0;
395 glyph->fAdvanceY = 0;
396
397 uint16_t glyphId = glyph->getGlyphID();
398 DWRITE_GLYPH_METRICS gm;
399
400 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
401 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
402 {
403 SkAutoExclusive l(DWriteFactoryMutex);
404 HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
405 fTextSizeMeasure,
406 1.0f, // pixelsPerDip
407 &fGsA,
408 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
409 &glyphId, 1,
410 &gm),
411 "Could not get gdi compatible glyph metrics.");
412 } else {
413 SkAutoExclusive l(DWriteFactoryMutex);
414 HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
415 "Could not get design metrics.");
416 }
417
418 DWRITE_FONT_METRICS dwfm;
419 {
420 Shared l(DWriteFactoryMutex);
421 this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm);
422 }
423 SkScalar advanceX = fTextSizeMeasure * gm.advanceWidth / dwfm.designUnitsPerEm;
424
425 SkVector vecs[1] = { { advanceX, 0 } };
426 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
427 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
428 {
429 // DirectWrite produced 'compatible' metrics, but while close,
430 // the end result is not always an integer as it would be with GDI.
431 vecs[0].fX = SkScalarRoundToScalar(advanceX);
432 fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
433 } else {
434 fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
435 }
436
437 glyph->fAdvanceX = SkScalarToFloat(vecs[0].fX);
438 glyph->fAdvanceY = SkScalarToFloat(vecs[0].fY);
439 }
440
getBoundingBox(SkGlyph * glyph,DWRITE_RENDERING_MODE renderingMode,DWRITE_TEXTURE_TYPE textureType,RECT * bbox)441 HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
442 DWRITE_RENDERING_MODE renderingMode,
443 DWRITE_TEXTURE_TYPE textureType,
444 RECT* bbox)
445 {
446 //Measure raster size.
447 fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
448 fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
449
450 FLOAT advance = 0;
451
452 UINT16 glyphId = glyph->getGlyphID();
453
454 DWRITE_GLYPH_OFFSET offset;
455 offset.advanceOffset = 0.0f;
456 offset.ascenderOffset = 0.0f;
457
458 DWRITE_GLYPH_RUN run;
459 run.glyphCount = 1;
460 run.glyphAdvances = &advance;
461 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
462 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
463 run.bidiLevel = 0;
464 run.glyphIndices = &glyphId;
465 run.isSideways = FALSE;
466 run.glyphOffsets = &offset;
467
468 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
469 {
470 SkAutoExclusive l(DWriteFactoryMutex);
471 // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
472 if (this->getDWriteTypeface()->fFactory2 &&
473 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
474 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
475 {
476 HRM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis(
477 &run,
478 &fXform,
479 renderingMode,
480 fMeasuringMode,
481 fGridFitMode,
482 fAntiAliasMode,
483 0.0f, // baselineOriginX,
484 0.0f, // baselineOriginY,
485 &glyphRunAnalysis),
486 "Could not create DW2 glyph run analysis.");
487 } else {
488 HRM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run,
489 1.0f, // pixelsPerDip,
490 &fXform,
491 renderingMode,
492 fMeasuringMode,
493 0.0f, // baselineOriginX,
494 0.0f, // baselineOriginY,
495 &glyphRunAnalysis),
496 "Could not create glyph run analysis.");
497 }
498 }
499 {
500 Shared l(DWriteFactoryMutex);
501 HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
502 "Could not get texture bounds.");
503 }
504 return S_OK;
505 }
506
507 /** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
508 * { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
509 * for small, but not quite zero, sized glyphs.
510 * Only set as non-empty if the returned bounds are non-empty.
511 */
glyph_check_and_set_bounds(SkGlyph * glyph,const RECT & bbox)512 static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) {
513 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
514 return false;
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
getColorGlyphRun(const SkGlyph & glyph,IDWriteColorGlyphRunEnumerator ** colorGlyph)528 bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph,
529 IDWriteColorGlyphRunEnumerator** colorGlyph)
530 {
531 FLOAT advance = 0;
532 UINT16 glyphId = glyph.getGlyphID();
533
534 DWRITE_GLYPH_OFFSET offset;
535 offset.advanceOffset = 0.0f;
536 offset.ascenderOffset = 0.0f;
537
538 DWRITE_GLYPH_RUN run;
539 run.glyphCount = 1;
540 run.glyphAdvances = &advance;
541 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
542 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
543 run.bidiLevel = 0;
544 run.glyphIndices = &glyphId;
545 run.isSideways = FALSE;
546 run.glyphOffsets = &offset;
547
548 HRESULT hr = this->getDWriteTypeface()->fFactory2->TranslateColorGlyphRun(
549 0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph);
550 if (hr == DWRITE_E_NOCOLOR) {
551 return false;
552 }
553 HRBM(hr, "Failed to translate color glyph run");
554 return true;
555 }
556
generateMetrics(SkGlyph * glyph)557 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
558 glyph->fWidth = 0;
559 glyph->fHeight = 0;
560 glyph->fLeft = 0;
561 glyph->fTop = 0;
562
563 this->generateAdvance(glyph);
564
565 if (fIsColorFont && isColorGlyph(*glyph)) {
566 glyph->fMaskFormat = SkMask::kARGB32_Format;
567 }
568
569 RECT bbox;
570 HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox),
571 "Requested bounding box could not be determined.");
572
573 if (glyph_check_and_set_bounds(glyph, bbox)) {
574 return;
575 }
576
577 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
578 // glyphs of the specified texture type. When this happens, try with the
579 // alternate texture type.
580 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) {
581 HRVM(this->getBoundingBox(glyph,
582 DWRITE_RENDERING_MODE_ALIASED,
583 DWRITE_TEXTURE_ALIASED_1x1,
584 &bbox),
585 "Fallback bounding box could not be determined.");
586 if (glyph_check_and_set_bounds(glyph, bbox)) {
587 glyph->fForceBW = 1;
588 }
589 }
590 // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
591 // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
592 }
593
generateFontMetrics(SkPaint::FontMetrics * metrics)594 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) {
595 if (nullptr == metrics) {
596 return;
597 }
598
599 sk_bzero(metrics, sizeof(*metrics));
600
601 DWRITE_FONT_METRICS dwfm;
602 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
603 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
604 {
605 this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleMetrics(
606 fTextSizeRender,
607 1.0f, // pixelsPerDip
608 &fXform,
609 &dwfm);
610 } else {
611 this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm);
612 }
613
614 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
615
616 metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
617 metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
618 metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
619 metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
620 metrics->fCapHeight = fTextSizeRender * SkIntToScalar(dwfm.capHeight) / upem;
621 metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
622 metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
623
624 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag;
625 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
626
627 if (this->getDWriteTypeface()->fDWriteFontFace1.get()) {
628 DWRITE_FONT_METRICS1 dwfm1;
629 this->getDWriteTypeface()->fDWriteFontFace1->GetMetrics(&dwfm1);
630 metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
631 metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
632 metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
633 metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
634
635 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
636 return;
637 }
638
639 AutoTDWriteTable<SkOTTableHead> head(this->getDWriteTypeface()->fDWriteFontFace.get());
640 if (head.fExists &&
641 head.fSize >= sizeof(SkOTTableHead) &&
642 head->version == SkOTTableHead::version1)
643 {
644 metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
645 metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
646 metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
647 metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
648
649 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
650 return;
651 }
652
653 metrics->fTop = metrics->fAscent;
654 metrics->fBottom = metrics->fDescent;
655 }
656
657 ///////////////////////////////////////////////////////////////////////////////
658
659 #include "SkColorPriv.h"
660
bilevel_to_bw(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph)661 static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
662 const int width = glyph.fWidth;
663 const size_t dstRB = (width + 7) >> 3;
664 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
665
666 int byteCount = width >> 3;
667 int bitCount = width & 7;
668
669 for (int y = 0; y < glyph.fHeight; ++y) {
670 if (byteCount > 0) {
671 for (int i = 0; i < byteCount; ++i) {
672 unsigned byte = 0;
673 byte |= src[0] & (1 << 7);
674 byte |= src[1] & (1 << 6);
675 byte |= src[2] & (1 << 5);
676 byte |= src[3] & (1 << 4);
677 byte |= src[4] & (1 << 3);
678 byte |= src[5] & (1 << 2);
679 byte |= src[6] & (1 << 1);
680 byte |= src[7] & (1 << 0);
681 dst[i] = byte;
682 src += 8;
683 }
684 }
685 if (bitCount > 0) {
686 unsigned byte = 0;
687 unsigned mask = 0x80;
688 for (int i = 0; i < bitCount; i++) {
689 byte |= (src[i]) & mask;
690 mask >>= 1;
691 }
692 dst[byteCount] = byte;
693 }
694 src += bitCount;
695 dst += dstRB;
696 }
697 }
698
699 template<bool APPLY_PREBLEND>
grayscale_to_a8(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph,const uint8_t * table8)700 static void grayscale_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
701 const uint8_t* table8) {
702 const size_t dstRB = glyph.rowBytes();
703 const U16CPU width = glyph.fWidth;
704 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
705
706 for (U16CPU y = 0; y < glyph.fHeight; y++) {
707 for (U16CPU i = 0; i < width; i++) {
708 U8CPU a = *(src++);
709 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>(a, table8);
710 }
711 dst = SkTAddOffset<uint8_t>(dst, dstRB);
712 }
713 }
714
715 template<bool APPLY_PREBLEND>
rgb_to_a8(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph,const uint8_t * table8)716 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
717 const size_t dstRB = glyph.rowBytes();
718 const U16CPU width = glyph.fWidth;
719 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
720
721 for (U16CPU y = 0; y < glyph.fHeight; y++) {
722 for (U16CPU i = 0; i < width; i++) {
723 U8CPU r = *(src++);
724 U8CPU g = *(src++);
725 U8CPU b = *(src++);
726 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
727 }
728 dst = SkTAddOffset<uint8_t>(dst, dstRB);
729 }
730 }
731
732 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)733 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
734 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
735 const size_t dstRB = glyph.rowBytes();
736 const U16CPU width = glyph.fWidth;
737 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
738
739 for (U16CPU y = 0; y < glyph.fHeight; y++) {
740 for (U16CPU i = 0; i < width; i++) {
741 U8CPU r, g, b;
742 if (RGB) {
743 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
744 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
745 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
746 } else {
747 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
748 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
749 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
750 }
751 dst[i] = SkPack888ToRGB16(r, g, b);
752 }
753 dst = SkTAddOffset<uint16_t>(dst, dstRB);
754 }
755 }
756
drawDWMask(const SkGlyph & glyph,DWRITE_RENDERING_MODE renderingMode,DWRITE_TEXTURE_TYPE textureType)757 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
758 DWRITE_RENDERING_MODE renderingMode,
759 DWRITE_TEXTURE_TYPE textureType)
760 {
761 int sizeNeeded = glyph.fWidth * glyph.fHeight;
762 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) {
763 sizeNeeded *= 3;
764 }
765 if (sizeNeeded > fBits.count()) {
766 fBits.setCount(sizeNeeded);
767 }
768
769 // erase
770 memset(fBits.begin(), 0, sizeNeeded);
771
772 fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
773 fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
774
775 FLOAT advance = 0.0f;
776
777 UINT16 index = glyph.getGlyphID();
778
779 DWRITE_GLYPH_OFFSET offset;
780 offset.advanceOffset = 0.0f;
781 offset.ascenderOffset = 0.0f;
782
783 DWRITE_GLYPH_RUN run;
784 run.glyphCount = 1;
785 run.glyphAdvances = &advance;
786 run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
787 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
788 run.bidiLevel = 0;
789 run.glyphIndices = &index;
790 run.isSideways = FALSE;
791 run.glyphOffsets = &offset;
792 {
793 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
794 {
795 SkAutoExclusive l(DWriteFactoryMutex);
796 // IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
797 if (this->getDWriteTypeface()->fFactory2 &&
798 (fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
799 fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
800 {
801 HRNM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis(&run,
802 &fXform,
803 renderingMode,
804 fMeasuringMode,
805 fGridFitMode,
806 fAntiAliasMode,
807 0.0f, // baselineOriginX,
808 0.0f, // baselineOriginY,
809 &glyphRunAnalysis),
810 "Could not create DW2 glyph run analysis.");
811 } else {
812 HRNM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run,
813 1.0f, // pixelsPerDip,
814 &fXform,
815 renderingMode,
816 fMeasuringMode,
817 0.0f, // baselineOriginX,
818 0.0f, // baselineOriginY,
819 &glyphRunAnalysis),
820 "Could not create glyph run analysis.");
821 }
822 }
823 //NOTE: this assumes that the glyph has already been measured
824 //with an exact same glyph run analysis.
825 RECT bbox;
826 bbox.left = glyph.fLeft;
827 bbox.top = glyph.fTop;
828 bbox.right = glyph.fLeft + glyph.fWidth;
829 bbox.bottom = glyph.fTop + glyph.fHeight;
830 {
831 Shared l(DWriteFactoryMutex);
832 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
833 &bbox,
834 fBits.begin(),
835 sizeNeeded),
836 "Could not draw mask.");
837 }
838 }
839 return fBits.begin();
840 }
841
generateColorGlyphImage(const SkGlyph & glyph)842 void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) {
843 SkASSERT(isColorGlyph(glyph));
844 SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format);
845
846 memset(glyph.fImage, 0, glyph.computeImageSize());
847
848 SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers;
849 getColorGlyphRun(glyph, &colorLayers);
850 SkASSERT(colorLayers.get());
851
852 SkMatrix matrix = fSkXform;
853 matrix.postTranslate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop));
854 SkRasterClip rc(SkIRect::MakeWH(glyph.fWidth, glyph.fHeight));
855 SkDraw draw;
856 draw.fDst = SkPixmap(SkImageInfo::MakeN32(glyph.fWidth, glyph.fHeight, kPremul_SkAlphaType),
857 glyph.fImage,
858 glyph.ComputeRowBytes(glyph.fWidth, SkMask::Format::kARGB32_Format));
859 draw.fMatrix = &matrix;
860 draw.fRC = &rc;
861
862 SkPaint paint;
863 if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) {
864 paint.setFlags(SkPaint::Flags::kAntiAlias_Flag);
865 }
866
867 BOOL hasNextRun = FALSE;
868 while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) {
869 const DWRITE_COLOR_GLYPH_RUN* colorGlyph;
870 HRVM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run");
871
872 SkColor color;
873 if (colorGlyph->paletteIndex != 0xffff) {
874 color = SkColorSetARGB(SkFloatToIntRound(colorGlyph->runColor.a * 255),
875 SkFloatToIntRound(colorGlyph->runColor.r * 255),
876 SkFloatToIntRound(colorGlyph->runColor.g * 255),
877 SkFloatToIntRound(colorGlyph->runColor.b * 255));
878 } else {
879 // If all components of runColor are 0 or (equivalently) paletteIndex is 0xFFFF then
880 // the 'current brush' is used. fRec.getLuminanceColor() is kinda sorta what is wanted
881 // here, but not really, it will often be the wrong value because it wan't designed for
882 // this.
883 // TODO: implement this fully, bug.skia.org/5788
884 color = fRec.getLuminanceColor();
885 }
886 paint.setColor(color);
887
888 SkPath path;
889 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
890 HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
891 "Could not create geometry to path converter.");
892 {
893 SkAutoExclusive l(DWriteFactoryMutex);
894 HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
895 colorGlyph->glyphRun.fontEmSize,
896 colorGlyph->glyphRun.glyphIndices,
897 colorGlyph->glyphRun.glyphAdvances,
898 colorGlyph->glyphRun.glyphOffsets,
899 colorGlyph->glyphRun.glyphCount,
900 colorGlyph->glyphRun.isSideways,
901 colorGlyph->glyphRun.bidiLevel % 2, //rtl
902 geometryToPath.get()),
903 "Could not create glyph outline.");
904 }
905 draw.drawPath(path, paint, nullptr, true /* pathIsMutable */);
906 }
907 }
908
generateImage(const SkGlyph & glyph)909 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
910 //Create the mask.
911 DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
912 DWRITE_TEXTURE_TYPE textureType = fTextureType;
913 if (glyph.fForceBW) {
914 renderingMode = DWRITE_RENDERING_MODE_ALIASED;
915 textureType = DWRITE_TEXTURE_ALIASED_1x1;
916 }
917
918 if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
919 generateColorGlyphImage(glyph);
920 return;
921 }
922
923 const void* bits = this->drawDWMask(glyph, renderingMode, textureType);
924 if (!bits) {
925 sk_bzero(glyph.fImage, glyph.computeImageSize());
926 return;
927 }
928
929 //Copy the mask into the glyph.
930 const uint8_t* src = (const uint8_t*)bits;
931 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
932 bilevel_to_bw(src, glyph);
933 const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
934 } else if (!isLCD(fRec)) {
935 if (textureType == DWRITE_TEXTURE_ALIASED_1x1) {
936 if (fPreBlend.isApplicable()) {
937 grayscale_to_a8<true>(src, glyph, fPreBlend.fG);
938 } else {
939 grayscale_to_a8<false>(src, glyph, fPreBlend.fG);
940 }
941 } else {
942 if (fPreBlend.isApplicable()) {
943 rgb_to_a8<true>(src, glyph, fPreBlend.fG);
944 } else {
945 rgb_to_a8<false>(src, glyph, fPreBlend.fG);
946 }
947 }
948 } else {
949 SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat);
950 if (fPreBlend.isApplicable()) {
951 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
952 rgb_to_lcd16<true, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
953 } else {
954 rgb_to_lcd16<true, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
955 }
956 } else {
957 if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
958 rgb_to_lcd16<false, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
959 } else {
960 rgb_to_lcd16<false, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
961 }
962 }
963 }
964 }
965
generatePath(SkGlyphID glyph,SkPath * path)966 void SkScalerContext_DW::generatePath(SkGlyphID glyph, SkPath* path) {
967 SkASSERT(path);
968
969 path->reset();
970
971 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
972 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
973 "Could not create geometry to path converter.");
974 UINT16 glyphId = SkTo<UINT16>(glyph);
975 {
976 SkAutoExclusive l(DWriteFactoryMutex);
977 //TODO: convert to<->from DIUs? This would make a difference if hinting.
978 //It may not be needed, it appears that DirectWrite only hints at em size.
979 HRVM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
980 SkScalarToFloat(fTextSizeRender),
981 &glyphId,
982 nullptr, //advances
983 nullptr, //offsets
984 1, //num glyphs
985 FALSE, //sideways
986 FALSE, //rtl
987 geometryToPath.get()),
988 "Could not create glyph outline.");
989 }
990
991 path->transform(fSkXform);
992 }
993
994 #endif//defined(SK_BUILD_FOR_WIN32)
995