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 "SkDWrite.h"
14 #include "SkDWriteGeometrySink.h"
15 #include "SkEndian.h"
16 #include "SkGlyph.h"
17 #include "SkHRESULT.h"
18 #include "SkMaskGamma.h"
19 #include "SkMatrix22.h"
20 #include "SkMutex.h"
21 #include "SkOTTable_EBLC.h"
22 #include "SkOTTable_EBSC.h"
23 #include "SkOTTable_gasp.h"
24 #include "SkOTTable_maxp.h"
25 #include "SkPath.h"
26 #include "SkScalerContext.h"
27 #include "SkScalerContext_win_dw.h"
28 #include "SkSharedMutex.h"
29 #include "SkTScopedComPtr.h"
30 #include "SkTypeface_win_dw.h"
31 
32 #include <dwrite.h>
33 #if SK_HAS_DWRITE_1_H
34 #  include <dwrite_1.h>
35 #endif
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 SkAutoTExclusive<SkSharedMutex> Exclusive;
44 typedef SkAutoSharedMutexShared Shared;
45 
isLCD(const SkScalerContext::Rec & rec)46 static bool isLCD(const SkScalerContext::Rec& rec) {
47     return SkMask::kLCD16_Format == rec.fMaskFormat;
48 }
49 
is_hinted_without_gasp(DWriteFontTypeface * typeface)50 static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) {
51     Exclusive l(DWriteFactoryMutex);
52     AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
53     if (!maxp.fExists) {
54         return false;
55     }
56     if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
57         return false;
58     }
59     if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
60         return false;
61     }
62 
63     if (0 == maxp->version.tt.maxSizeOfInstructions) {
64         // No hints.
65         return false;
66     }
67 
68     AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
69     return !gasp.fExists;
70 }
71 
72 /** A PPEMRange is inclusive, [min, max]. */
73 struct PPEMRange {
74     int min;
75     int max;
76 };
77 
78 /** If the rendering mode for the specified 'size' is gridfit, then place
79  *  the gridfit range into 'range'. Otherwise, leave 'range' alone.
80  */
expand_range_if_gridfit_only(DWriteFontTypeface * typeface,int size,PPEMRange * range)81 static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) {
82     AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
83     if (!gasp.fExists) {
84         return;
85     }
86     if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
87         return;
88     }
89     if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
90         gasp->version != SkOTTableGridAndScanProcedure::version1)
91     {
92         return;
93     }
94 
95     uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
96     if (numRanges > 1024 ||
97         gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
98                      sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
99     {
100         return;
101     }
102 
103     const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
104             SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
105     int minPPEM = -1;
106     for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) {
107         int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM);
108         // Test that the size is in range and the range is gridfit only.
109         if (minPPEM < size && size <= maxPPEM &&
110             rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask)
111         {
112             range->min = minPPEM + 1;
113             range->max = maxPPEM;
114             return;
115         }
116         minPPEM = maxPPEM;
117     }
118 }
119 
has_bitmap_strike(DWriteFontTypeface * typeface,PPEMRange range)120 static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) {
121     Exclusive l(DWriteFactoryMutex);
122     {
123         AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
124         if (!eblc.fExists) {
125             return false;
126         }
127         if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
128             return false;
129         }
130         if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
131             return false;
132         }
133 
134         uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
135         if (numSizes > 1024 ||
136             eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
137                          sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
138         {
139             return false;
140         }
141 
142         const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
143                 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
144         for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
145             if (sizeTable->ppemX == sizeTable->ppemY &&
146                 range.min <= sizeTable->ppemX && sizeTable->ppemX <= range.max)
147             {
148                 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
149                 // to determine the actual number of glyphs with bitmaps.
150 
151                 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
152 
153                 // TODO: Ensure that the bitmaps are bi-level?
154                 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
155                     return true;
156                 }
157             }
158         }
159     }
160 
161     {
162         AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
163         if (!ebsc.fExists) {
164             return false;
165         }
166         if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
167             return false;
168         }
169         if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
170             return false;
171         }
172 
173         uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
174         if (numSizes > 1024 ||
175             ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
176                          sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
177         {
178             return false;
179         }
180 
181         const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
182                 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
183         for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
184             if (scaleTable->ppemX == scaleTable->ppemY &&
185                 range.min <= scaleTable->ppemX && scaleTable->ppemX <= range.max) {
186                 // EBSC tables are normally only found in bitmap only fonts.
187                 return true;
188             }
189         }
190     }
191 
192     return false;
193 }
194 
both_zero(SkScalar a,SkScalar b)195 static bool both_zero(SkScalar a, SkScalar b) {
196     return 0 == a && 0 == b;
197 }
198 
199 // returns false if there is any non-90-rotation or skew
is_axis_aligned(const SkScalerContext::Rec & rec)200 static bool is_axis_aligned(const SkScalerContext::Rec& rec) {
201     return 0 == rec.fPreSkewX &&
202            (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
203             both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
204 }
205 
SkScalerContext_DW(DWriteFontTypeface * typeface,const SkDescriptor * desc)206 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
207                                        const SkDescriptor* desc)
208         : SkScalerContext(typeface, desc)
209         , fTypeface(SkRef(typeface))
210         , fGlyphCount(-1) {
211 
212     // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC
213     // except when bi-level rendering is requested or there are embedded
214     // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
215     //
216     // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
217     // this. As a result, determine the actual size of the text and then see if
218     // there are any embedded bi-level bitmaps of that size. If there are, then
219     // force bitmaps by requesting bi-level rendering.
220     //
221     // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
222     // square pixels and only uses ppemY. Therefore the transform must track any
223     // non-uniform x-scale.
224     //
225     // Also, rotated glyphs should have the same absolute advance widths as
226     // horizontal glyphs and the subpixel flag should not affect glyph shapes.
227 
228     SkVector scale;
229     SkMatrix GsA;
230     fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale,
231                          &scale, &fSkXform, &GsA, &fG_inv);
232 
233     fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
234     fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
235     fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
236     fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
237     fXform.dx = 0;
238     fXform.dy = 0;
239 
240     fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX));
241     fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
242     fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX));
243     fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY));
244     fGsA.dx = 0;
245     fGsA.dy = 0;
246 
247     // realTextSize is the actual device size we want (as opposed to the size the user requested).
248     // gdiTextSize is the size we request when GDI compatible.
249     // If the scale is negative, this means the matrix will do the flip anyway.
250     const SkScalar realTextSize = scale.fY;
251     // Due to floating point math, the lower bits are suspect. Round carefully.
252     SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
253     if (gdiTextSize == 0) {
254         gdiTextSize = SK_Scalar1;
255     }
256 
257     bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
258     bool treatLikeBitmap = false;
259     bool axisAlignedBitmap = false;
260     if (bitmapRequested) {
261         // When embedded bitmaps are requested, treat the entire range like
262         // a bitmap strike if the range is gridfit only and contains a bitmap.
263         int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
264         PPEMRange range = { bitmapPPEM, bitmapPPEM };
265         expand_range_if_gridfit_only(typeface, bitmapPPEM, &range);
266         treatLikeBitmap = has_bitmap_strike(typeface, range);
267 
268         axisAlignedBitmap = is_axis_aligned(fRec);
269     }
270 
271     // If the user requested aliased, do so with aliased compatible metrics.
272     if (SkMask::kBW_Format == fRec.fMaskFormat) {
273         fTextSizeRender = gdiTextSize;
274         fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
275         fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
276         fTextSizeMeasure = gdiTextSize;
277         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
278 
279     // If we can use a bitmap, use gdi classic rendering and measurement.
280     // This will not always provide a bitmap, but matches expected behavior.
281     } else if (treatLikeBitmap && axisAlignedBitmap) {
282         fTextSizeRender = gdiTextSize;
283         fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
284         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
285         fTextSizeMeasure = gdiTextSize;
286         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
287 
288     // If rotated but the horizontal text could have used a bitmap,
289     // render high quality rotated glyphs but measure using bitmap metrics.
290     } else if (treatLikeBitmap) {
291         fTextSizeRender = gdiTextSize;
292         fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
293         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
294         fTextSizeMeasure = gdiTextSize;
295         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
296 
297     // Fonts that have hints but no gasp table get non-symmetric rendering.
298     // Usually such fonts have low quality hints which were never tested
299     // with anything but GDI ClearType classic. Such fonts often rely on
300     // drop out control in the y direction in order to be legible.
301     } else if (is_hinted_without_gasp(typeface)) {
302         fTextSizeRender = gdiTextSize;
303         fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
304         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
305         fTextSizeMeasure = realTextSize;
306         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
307 
308     // The normal case is to use natural symmetric rendering and linear metrics.
309     } else {
310         fTextSizeRender = realTextSize;
311         fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
312         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
313         fTextSizeMeasure = realTextSize;
314         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
315     }
316 
317     if (this->isSubpixel()) {
318         fTextSizeMeasure = realTextSize;
319         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
320     }
321 }
322 
~SkScalerContext_DW()323 SkScalerContext_DW::~SkScalerContext_DW() {
324 }
325 
generateGlyphCount()326 unsigned SkScalerContext_DW::generateGlyphCount() {
327     if (fGlyphCount < 0) {
328         fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
329     }
330     return fGlyphCount;
331 }
332 
generateCharToGlyph(SkUnichar uni)333 uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
334     uint16_t index = 0;
335     fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index);
336     return index;
337 }
338 
generateAdvance(SkGlyph * glyph)339 void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
340     //Delta is the difference between the right/left side bearing metric
341     //and where the right/left side bearing ends up after hinting.
342     //DirectWrite does not provide this information.
343     glyph->fRsbDelta = 0;
344     glyph->fLsbDelta = 0;
345 
346     glyph->fAdvanceX = 0;
347     glyph->fAdvanceY = 0;
348 
349     uint16_t glyphId = glyph->getGlyphID();
350     DWRITE_GLYPH_METRICS gm;
351 
352     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
353         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
354     {
355         Exclusive l(DWriteFactoryMutex);
356         HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
357                  fTextSizeMeasure,
358                  1.0f, // pixelsPerDip
359                  &fGsA,
360                  DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
361                  &glyphId, 1,
362                  &gm),
363              "Could not get gdi compatible glyph metrics.");
364     } else {
365         Exclusive l(DWriteFactoryMutex);
366         HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
367              "Could not get design metrics.");
368     }
369 
370     DWRITE_FONT_METRICS dwfm;
371     {
372         Shared l(DWriteFactoryMutex);
373         fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
374     }
375     SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
376                                        SkIntToScalar(gm.advanceWidth),
377                                        SkIntToScalar(dwfm.designUnitsPerEm));
378 
379     SkVector vecs[1] = { { advanceX, 0 } };
380     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
381         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
382     {
383         // DirectWrite produced 'compatible' metrics, but while close,
384         // the end result is not always an integer as it would be with GDI.
385         vecs[0].fX = SkScalarRoundToScalar(advanceX);
386         fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
387     } else {
388         fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
389     }
390 
391     glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
392     glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
393 }
394 
getBoundingBox(SkGlyph * glyph,DWRITE_RENDERING_MODE renderingMode,DWRITE_TEXTURE_TYPE textureType,RECT * bbox)395 HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
396                                            DWRITE_RENDERING_MODE renderingMode,
397                                            DWRITE_TEXTURE_TYPE textureType,
398                                            RECT* bbox)
399 {
400     //Measure raster size.
401     fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
402     fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
403 
404     FLOAT advance = 0;
405 
406     UINT16 glyphId = glyph->getGlyphID();
407 
408     DWRITE_GLYPH_OFFSET offset;
409     offset.advanceOffset = 0.0f;
410     offset.ascenderOffset = 0.0f;
411 
412     DWRITE_GLYPH_RUN run;
413     run.glyphCount = 1;
414     run.glyphAdvances = &advance;
415     run.fontFace = fTypeface->fDWriteFontFace.get();
416     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
417     run.bidiLevel = 0;
418     run.glyphIndices = &glyphId;
419     run.isSideways = FALSE;
420     run.glyphOffsets = &offset;
421 
422     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
423     {
424         Exclusive l(DWriteFactoryMutex);
425         HRM(fTypeface->fFactory->CreateGlyphRunAnalysis(
426             &run,
427             1.0f, // pixelsPerDip,
428             &fXform,
429             renderingMode,
430             fMeasuringMode,
431             0.0f, // baselineOriginX,
432             0.0f, // baselineOriginY,
433             &glyphRunAnalysis),
434             "Could not create glyph run analysis.");
435     }
436     {
437         Shared l(DWriteFactoryMutex);
438         HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
439             "Could not get texture bounds.");
440     }
441     return S_OK;
442 }
443 
444 /** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
445  *  { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
446  *  for small, but not quite zero, sized glyphs.
447  *  Only set as non-empty if the returned bounds are non-empty.
448  */
glyph_check_and_set_bounds(SkGlyph * glyph,const RECT & bbox)449 static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) {
450     if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
451         return false;
452     }
453     glyph->fWidth = SkToU16(bbox.right - bbox.left);
454     glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
455     glyph->fLeft = SkToS16(bbox.left);
456     glyph->fTop = SkToS16(bbox.top);
457     return true;
458 }
459 
generateMetrics(SkGlyph * glyph)460 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
461     glyph->fWidth = 0;
462     glyph->fHeight = 0;
463     glyph->fLeft = 0;
464     glyph->fTop = 0;
465 
466     this->generateAdvance(glyph);
467 
468     RECT bbox;
469     HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox),
470          "Requested bounding box could not be determined.");
471 
472     if (glyph_check_and_set_bounds(glyph, bbox)) {
473         return;
474     }
475 
476     // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
477     // glyphs of the specified texture type. When this happens, try with the
478     // alternate texture type.
479     if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) {
480         HRVM(this->getBoundingBox(glyph,
481                                   DWRITE_RENDERING_MODE_ALIASED,
482                                   DWRITE_TEXTURE_ALIASED_1x1,
483                                   &bbox),
484              "Fallback bounding box could not be determined.");
485         if (glyph_check_and_set_bounds(glyph, bbox)) {
486             glyph->fForceBW = 1;
487         }
488     }
489     // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
490     // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
491 }
492 
generateFontMetrics(SkPaint::FontMetrics * metrics)493 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) {
494     if (nullptr == metrics) {
495         return;
496     }
497 
498     sk_bzero(metrics, sizeof(*metrics));
499 
500     DWRITE_FONT_METRICS dwfm;
501     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
502         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
503     {
504         fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
505              fTextSizeRender,
506              1.0f, // pixelsPerDip
507              &fXform,
508              &dwfm);
509     } else {
510         fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
511     }
512 
513     SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
514 
515     metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
516     metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
517     metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
518     metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
519     metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
520     metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
521 
522     metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
523     metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
524 
525 #if SK_HAS_DWRITE_1_H
526     if (fTypeface->fDWriteFontFace1.get()) {
527         DWRITE_FONT_METRICS1 dwfm1;
528         fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1);
529         metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
530         metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
531         metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
532         metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
533 
534         metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
535         return;
536     }
537 #else
538 #  pragma message("No dwrite_1.h is available, font metrics may be affected.")
539 #endif
540 
541     AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get());
542     if (head.fExists &&
543         head.fSize >= sizeof(SkOTTableHead) &&
544         head->version == SkOTTableHead::version1)
545     {
546         metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
547         metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
548         metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
549         metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
550 
551         metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
552         return;
553     }
554 
555     metrics->fTop = metrics->fAscent;
556     metrics->fBottom = metrics->fDescent;
557 }
558 
559 ///////////////////////////////////////////////////////////////////////////////
560 
561 #include "SkColorPriv.h"
562 
bilevel_to_bw(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph)563 static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
564     const int width = glyph.fWidth;
565     const size_t dstRB = (width + 7) >> 3;
566     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
567 
568     int byteCount = width >> 3;
569     int bitCount = width & 7;
570 
571     for (int y = 0; y < glyph.fHeight; ++y) {
572         if (byteCount > 0) {
573             for (int i = 0; i < byteCount; ++i) {
574                 unsigned byte = 0;
575                 byte |= src[0] & (1 << 7);
576                 byte |= src[1] & (1 << 6);
577                 byte |= src[2] & (1 << 5);
578                 byte |= src[3] & (1 << 4);
579                 byte |= src[4] & (1 << 3);
580                 byte |= src[5] & (1 << 2);
581                 byte |= src[6] & (1 << 1);
582                 byte |= src[7] & (1 << 0);
583                 dst[i] = byte;
584                 src += 8;
585             }
586         }
587         if (bitCount > 0) {
588             unsigned byte = 0;
589             unsigned mask = 0x80;
590             for (int i = 0; i < bitCount; i++) {
591                 byte |= (src[i]) & mask;
592                 mask >>= 1;
593             }
594             dst[byteCount] = byte;
595         }
596         src += bitCount;
597         dst += dstRB;
598     }
599 }
600 
601 template<bool APPLY_PREBLEND>
rgb_to_a8(const uint8_t * SK_RESTRICT src,const SkGlyph & glyph,const uint8_t * table8)602 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
603     const size_t dstRB = glyph.rowBytes();
604     const U16CPU width = glyph.fWidth;
605     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
606 
607     for (U16CPU y = 0; y < glyph.fHeight; y++) {
608         for (U16CPU i = 0; i < width; i++) {
609             U8CPU r = *(src++);
610             U8CPU g = *(src++);
611             U8CPU b = *(src++);
612             dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
613         }
614         dst = (uint8_t*)((char*)dst + dstRB);
615     }
616 }
617 
618 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)619 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
620                          const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
621     const size_t dstRB = glyph.rowBytes();
622     const U16CPU width = glyph.fWidth;
623     uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
624 
625     for (U16CPU y = 0; y < glyph.fHeight; y++) {
626         for (U16CPU i = 0; i < width; i++) {
627             U8CPU r, g, b;
628             if (RGB) {
629                 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
630                 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
631                 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
632             } else {
633                 b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
634                 g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
635                 r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
636             }
637             dst[i] = SkPack888ToRGB16(r, g, b);
638         }
639         dst = (uint16_t*)((char*)dst + dstRB);
640     }
641 }
642 
drawDWMask(const SkGlyph & glyph,DWRITE_RENDERING_MODE renderingMode,DWRITE_TEXTURE_TYPE textureType)643 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
644                                            DWRITE_RENDERING_MODE renderingMode,
645                                            DWRITE_TEXTURE_TYPE textureType)
646 {
647     int sizeNeeded = glyph.fWidth * glyph.fHeight;
648     if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) {
649         sizeNeeded *= 3;
650     }
651     if (sizeNeeded > fBits.count()) {
652         fBits.setCount(sizeNeeded);
653     }
654 
655     // erase
656     memset(fBits.begin(), 0, sizeNeeded);
657 
658     fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
659     fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
660 
661     FLOAT advance = 0.0f;
662 
663     UINT16 index = glyph.getGlyphID();
664 
665     DWRITE_GLYPH_OFFSET offset;
666     offset.advanceOffset = 0.0f;
667     offset.ascenderOffset = 0.0f;
668 
669     DWRITE_GLYPH_RUN run;
670     run.glyphCount = 1;
671     run.glyphAdvances = &advance;
672     run.fontFace = fTypeface->fDWriteFontFace.get();
673     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
674     run.bidiLevel = 0;
675     run.glyphIndices = &index;
676     run.isSideways = FALSE;
677     run.glyphOffsets = &offset;
678     {
679 
680         SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
681         {
682             Exclusive l(DWriteFactoryMutex);
683             HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
684                 1.0f, // pixelsPerDip,
685                 &fXform,
686                 renderingMode,
687                 fMeasuringMode,
688                 0.0f, // baselineOriginX,
689                 0.0f, // baselineOriginY,
690                 &glyphRunAnalysis),
691                 "Could not create glyph run analysis.");
692         }
693         //NOTE: this assumes that the glyph has already been measured
694         //with an exact same glyph run analysis.
695         RECT bbox;
696         bbox.left = glyph.fLeft;
697         bbox.top = glyph.fTop;
698         bbox.right = glyph.fLeft + glyph.fWidth;
699         bbox.bottom = glyph.fTop + glyph.fHeight;
700         {
701             Shared l(DWriteFactoryMutex);
702             HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
703                 &bbox,
704                 fBits.begin(),
705                 sizeNeeded),
706                 "Could not draw mask.");
707         }
708     }
709     return fBits.begin();
710 }
711 
generateImage(const SkGlyph & glyph)712 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
713     //Create the mask.
714     DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
715     DWRITE_TEXTURE_TYPE textureType = fTextureType;
716     if (glyph.fForceBW) {
717         renderingMode = DWRITE_RENDERING_MODE_ALIASED;
718         textureType = DWRITE_TEXTURE_ALIASED_1x1;
719     }
720     const void* bits = this->drawDWMask(glyph, renderingMode, textureType);
721     if (!bits) {
722         sk_bzero(glyph.fImage, glyph.computeImageSize());
723         return;
724     }
725 
726     //Copy the mask into the glyph.
727     const uint8_t* src = (const uint8_t*)bits;
728     if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
729         bilevel_to_bw(src, glyph);
730         const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
731     } else if (!isLCD(fRec)) {
732         if (fPreBlend.isApplicable()) {
733             rgb_to_a8<true>(src, glyph, fPreBlend.fG);
734         } else {
735             rgb_to_a8<false>(src, glyph, fPreBlend.fG);
736         }
737     } else {
738         SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat);
739         if (fPreBlend.isApplicable()) {
740             if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
741                 rgb_to_lcd16<true, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
742             } else {
743                 rgb_to_lcd16<true, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
744             }
745         } else {
746             if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) {
747                 rgb_to_lcd16<false, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
748             } else {
749                 rgb_to_lcd16<false, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
750             }
751         }
752     }
753 }
754 
generatePath(const SkGlyph & glyph,SkPath * path)755 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
756     SkASSERT(path);
757 
758     path->reset();
759 
760     SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
761     HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
762          "Could not create geometry to path converter.");
763     uint16_t glyphId = glyph.getGlyphID();
764     {
765         Exclusive l(DWriteFactoryMutex);
766         //TODO: convert to<->from DIUs? This would make a difference if hinting.
767         //It may not be needed, it appears that DirectWrite only hints at em size.
768         HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender),
769             &glyphId,
770             nullptr, //advances
771             nullptr, //offsets
772             1, //num glyphs
773             FALSE, //sideways
774             FALSE, //rtl
775             geometryToPath.get()),
776             "Could not create glyph outline.");
777     }
778 
779     path->transform(fSkXform);
780 }
781 
782 #endif//defined(SK_BUILD_FOR_WIN32)
783