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