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