2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
12 #include "SkDWriteGeometrySink.h"
15 #include "SkHRESULT.h"
16 #include "SkMaskGamma.h"
17 #include "SkMatrix22.h"
18 #include "SkOTTable_EBLC.h"
19 #include "SkOTTable_EBSC.h"
20 #include "SkOTTable_gasp.h"
21 #include "SkOTTable_maxp.h"
23 #include "SkScalerContext.h"
24 #include "SkScalerContext_win_dw.h"
25 #include "SkTScopedComPtr.h"
26 #include "SkTypeface_win_dw.h"
30 # include <dwrite_1.h>
33 static bool isLCD(const SkScalerContext::Rec& rec) {
34 return SkMask::kLCD16_Format == rec.fMaskFormat ||
35 SkMask::kLCD32_Format == rec.fMaskFormat;
38 static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) {
39 AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
43 if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
46 if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
50 if (0 == maxp->version.tt.maxSizeOfInstructions) {
55 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
59 /** A PPEMRange is inclusive, [min, max]. */
65 /** If the rendering mode for the specified 'size' is gridfit, then place
66 * the gridfit range into 'range'. Otherwise, leave 'range' alone.
68 static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) {
69 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
73 if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
76 if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
77 gasp->version != SkOTTableGridAndScanProcedure::version1)
82 uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
83 if (numRanges > 1024 ||
84 gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
85 sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
90 const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
91 SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
93 for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) {
94 int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM);
95 // Test that the size is in range and the range is gridfit only.
96 if (minPPEM < size && size <= maxPPEM &&
97 rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask)
99 range->min = minPPEM + 1;
100 range->max = maxPPEM;
107 static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) {
109 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
113 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
116 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
120 uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
121 if (numSizes > 1024 ||
122 eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
123 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
128 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
129 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
130 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
131 if (sizeTable->ppemX == sizeTable->ppemY &&
132 range.min <= sizeTable->ppemX && sizeTable->ppemX <= range.max)
134 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
135 // to determine the actual number of glyphs with bitmaps.
137 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
139 // TODO: Ensure that the bitmaps are bi-level?
140 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
148 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
152 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
155 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
159 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
160 if (numSizes > 1024 ||
161 ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
162 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
167 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
168 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
169 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
170 if (scaleTable->ppemX == scaleTable->ppemY &&
171 range.min <= scaleTable->ppemX && scaleTable->ppemX <= range.max) {
172 // EBSC tables are normally only found in bitmap only fonts.
181 static bool both_zero(SkScalar a, SkScalar b) {
182 return 0 == a && 0 == b;
185 // returns false if there is any non-90-rotation or skew
186 static bool is_axis_aligned(const SkScalerContext::Rec& rec) {
187 return 0 == rec.fPreSkewX &&
188 (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
189 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
192 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
193 const SkDescriptor* desc)
194 : SkScalerContext(typeface, desc)
195 , fTypeface(SkRef(typeface))
198 // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC
199 // except when bi-level rendering is requested or there are embedded
200 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
202 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
203 // this. As a result, determine the actual size of the text and then see if
204 // there are any embedded bi-level bitmaps of that size. If there are, then
205 // force bitmaps by requesting bi-level rendering.
207 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
208 // square pixels and only uses ppemY. Therefore the transform must track any
209 // non-uniform x-scale.
211 // Also, rotated glyphs should have the same absolute advance widths as
212 // horizontal glyphs and the subpixel flag should not affect glyph shapes.
214 // A is the total matrix.
216 fRec.getSingleMatrix(&A);
218 // h is where A maps the horizontal baseline.
219 SkPoint h = SkPoint::Make(SK_Scalar1, 0);
222 // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
224 SkComputeGivensRotation(h, &G);
226 // GA is the matrix A with rotation removed.
230 // realTextSize is the actual device size we want (as opposed to the size the user requested).
231 // gdiTextSize is the size we request when GDI compatible.
232 // If the scale is negative, this means the matrix will do the flip anyway.
233 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
234 // Due to floating point math, the lower bits are suspect. Round carefully.
235 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
236 if (gdiTextSize == 0) {
237 gdiTextSize = SK_Scalar1;
240 bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
241 bool treatLikeBitmap = false;
242 bool axisAlignedBitmap = false;
243 if (bitmapRequested) {
244 // When embedded bitmaps are requested, treat the entire range like
245 // a bitmap strike if the range is gridfit only and contains a bitmap.
246 int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
247 PPEMRange range = { bitmapPPEM, bitmapPPEM };
248 expand_range_if_gridfit_only(typeface, bitmapPPEM, &range);
249 treatLikeBitmap = has_bitmap_strike(typeface, range);
251 axisAlignedBitmap = is_axis_aligned(fRec);
254 // If the user requested aliased, do so with aliased compatible metrics.
255 if (SkMask::kBW_Format == fRec.fMaskFormat) {
256 fTextSizeRender = gdiTextSize;
257 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
258 fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
259 fTextSizeMeasure = gdiTextSize;
260 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
262 // If we can use a bitmap, use gdi classic rendering and measurement.
263 // This will not always provide a bitmap, but matches expected behavior.
264 } else if (treatLikeBitmap && axisAlignedBitmap) {
265 fTextSizeRender = gdiTextSize;
266 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
267 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
268 fTextSizeMeasure = gdiTextSize;
269 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
271 // If rotated but the horizontal text could have used a bitmap,
272 // render high quality rotated glyphs but measure using bitmap metrics.
273 } else if (treatLikeBitmap) {
274 fTextSizeRender = gdiTextSize;
275 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
276 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
277 fTextSizeMeasure = gdiTextSize;
278 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
280 // Fonts that have hints but no gasp table get non-symmetric rendering.
281 // Usually such fonts have low quality hints which were never tested
282 // with anything but GDI ClearType classic. Such fonts often rely on
283 // drop out control in the y direction in order to be legible.
284 } else if (is_hinted_without_gasp(typeface)) {
285 fTextSizeRender = gdiTextSize;
286 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
287 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
288 fTextSizeMeasure = realTextSize;
289 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
291 // The normal case is to use natural symmetric rendering and linear metrics.
293 fTextSizeRender = realTextSize;
294 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
295 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
296 fTextSizeMeasure = realTextSize;
297 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
300 if (this->isSubpixel()) {
301 fTextSizeMeasure = realTextSize;
302 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
305 // Remove the realTextSize, as that is the text height scale currently in A.
306 SkScalar scale = SkScalarInvert(realTextSize);
308 // fSkXform is the total matrix A without the text height scale.
310 fSkXform.preScale(scale, scale); //remove the text height scale.
312 fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
313 fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
314 fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
315 fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
319 // GsA is the non-rotational part of A without the text height scale.
321 GsA.preScale(scale, scale); //remove text height scale, G is rotational so reorders with scale.
323 fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX));
324 fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
325 fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX));
326 fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY));
330 // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
331 fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
332 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
333 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
336 SkScalerContext_DW::~SkScalerContext_DW() {
339 unsigned SkScalerContext_DW::generateGlyphCount() {
340 if (fGlyphCount < 0) {
341 fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
346 uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
348 fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index);
352 void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
353 //Delta is the difference between the right/left side bearing metric
354 //and where the right/left side bearing ends up after hinting.
355 //DirectWrite does not provide this information.
356 glyph->fRsbDelta = 0;
357 glyph->fLsbDelta = 0;
359 glyph->fAdvanceX = 0;
360 glyph->fAdvanceY = 0;
362 uint16_t glyphId = glyph->getGlyphID();
363 DWRITE_GLYPH_METRICS gm;
365 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
366 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
368 HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
370 1.0f, // pixelsPerDip
372 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
375 "Could not get gdi compatible glyph metrics.");
377 HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
378 "Could not get design metrics.");
381 DWRITE_FONT_METRICS dwfm;
382 fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
383 SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
384 SkIntToScalar(gm.advanceWidth),
385 SkIntToScalar(dwfm.designUnitsPerEm));
387 SkVector vecs[1] = { { advanceX, 0 } };
388 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
389 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
391 // DirectWrite produced 'compatible' metrics, but while close,
392 // the end result is not always an integer as it would be with GDI.
393 vecs[0].fX = SkScalarRoundToScalar(advanceX);
394 fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
396 fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
399 glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
400 glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
403 HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
404 DWRITE_RENDERING_MODE renderingMode,
405 DWRITE_TEXTURE_TYPE textureType,
408 //Measure raster size.
409 fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
410 fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
414 UINT16 glyphId = glyph->getGlyphID();
416 DWRITE_GLYPH_OFFSET offset;
417 offset.advanceOffset = 0.0f;
418 offset.ascenderOffset = 0.0f;
420 DWRITE_GLYPH_RUN run;
422 run.glyphAdvances = &advance;
423 run.fontFace = fTypeface->fDWriteFontFace.get();
424 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
426 run.glyphIndices = &glyphId;
427 run.isSideways = FALSE;
428 run.glyphOffsets = &offset;
430 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
431 HRM(fTypeface->fFactory->CreateGlyphRunAnalysis(
433 1.0f, // pixelsPerDip,
437 0.0f, // baselineOriginX,
438 0.0f, // baselineOriginY,
440 "Could not create glyph run analysis.");
442 HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
443 "Could not get texture bounds.");
448 /** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
449 * { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
450 * for small, but not quite zero, sized glyphs.
451 * Only set as non-empty if the returned bounds are non-empty.
453 static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) {
454 if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
457 glyph->fWidth = SkToU16(bbox.right - bbox.left);
458 glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
459 glyph->fLeft = SkToS16(bbox.left);
460 glyph->fTop = SkToS16(bbox.top);
464 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
470 this->generateAdvance(glyph);
473 HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox),
474 "Requested bounding box could not be determined.");
476 if (glyph_check_and_set_bounds(glyph, bbox)) {
480 // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
481 // glyphs of the specified texture type. When this happens, try with the
482 // alternate texture type.
483 if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) {
484 HRVM(this->getBoundingBox(glyph,
485 DWRITE_RENDERING_MODE_ALIASED,
486 DWRITE_TEXTURE_ALIASED_1x1,
488 "Fallback bounding box could not be determined.");
489 if (glyph_check_and_set_bounds(glyph, bbox)) {
493 // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
494 // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
497 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) {
498 if (NULL == metrics) {
502 sk_bzero(metrics, sizeof(*metrics));
504 DWRITE_FONT_METRICS dwfm;
505 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
506 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
508 fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
510 1.0f, // pixelsPerDip
514 fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
517 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
519 metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
520 metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
521 metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
522 metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
523 metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
524 metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
526 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
527 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
529 #if SK_HAS_DWRITE_1_H
530 if (fTypeface->fDWriteFontFace1.get()) {
531 DWRITE_FONT_METRICS1 dwfm1;
532 fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1);
533 metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
534 metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
535 metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
536 metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
538 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
542 # pragma message("No dwrite_1.h is available, font metrics may be affected.")
545 AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get());
547 head.fSize >= sizeof(SkOTTableHead) &&
548 head->version == SkOTTableHead::version1)
550 metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
551 metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
552 metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
553 metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
555 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
559 metrics->fTop = metrics->fAscent;
560 metrics->fBottom = metrics->fDescent;
563 ///////////////////////////////////////////////////////////////////////////////
565 #include "SkColorPriv.h"
567 static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
568 const int width = glyph.fWidth;
569 const size_t dstRB = (width + 7) >> 3;
570 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
572 int byteCount = width >> 3;
573 int bitCount = width & 7;
575 for (int y = 0; y < glyph.fHeight; ++y) {
577 for (int i = 0; i < byteCount; ++i) {
579 byte |= src[0] & (1 << 7);
580 byte |= src[1] & (1 << 6);
581 byte |= src[2] & (1 << 5);
582 byte |= src[3] & (1 << 4);
583 byte |= src[4] & (1 << 3);
584 byte |= src[5] & (1 << 2);
585 byte |= src[6] & (1 << 1);
586 byte |= src[7] & (1 << 0);
593 unsigned mask = 0x80;
594 for (int i = 0; i < bitCount; i++) {
595 byte |= (src[i]) & mask;
598 dst[byteCount] = byte;
605 template<bool APPLY_PREBLEND>
606 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
607 const size_t dstRB = glyph.rowBytes();
608 const U16CPU width = glyph.fWidth;
609 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
611 for (U16CPU y = 0; y < glyph.fHeight; y++) {
612 for (U16CPU i = 0; i < width; i++) {
616 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
618 dst = (uint8_t*)((char*)dst + dstRB);
622 template<bool APPLY_PREBLEND>
623 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
624 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
625 const size_t dstRB = glyph.rowBytes();
626 const U16CPU width = glyph.fWidth;
627 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
629 for (U16CPU y = 0; y < glyph.fHeight; y++) {
630 for (U16CPU i = 0; i < width; i++) {
631 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
632 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
633 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
634 dst[i] = SkPack888ToRGB16(r, g, b);
636 dst = (uint16_t*)((char*)dst + dstRB);
640 template<bool APPLY_PREBLEND>
641 static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
642 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
643 const size_t dstRB = glyph.rowBytes();
644 const U16CPU width = glyph.fWidth;
645 SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage);
647 for (U16CPU y = 0; y < glyph.fHeight; y++) {
648 for (U16CPU i = 0; i < width; i++) {
649 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
650 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
651 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
652 dst[i] = SkPackARGB32(0xFF, r, g, b);
654 dst = (SkPMColor*)((char*)dst + dstRB);
658 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
659 DWRITE_RENDERING_MODE renderingMode,
660 DWRITE_TEXTURE_TYPE textureType)
662 int sizeNeeded = glyph.fWidth * glyph.fHeight;
663 if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) {
666 if (sizeNeeded > fBits.count()) {
667 fBits.setCount(sizeNeeded);
671 memset(fBits.begin(), 0, sizeNeeded);
673 fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
674 fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
676 FLOAT advance = 0.0f;
678 UINT16 index = glyph.getGlyphID();
680 DWRITE_GLYPH_OFFSET offset;
681 offset.advanceOffset = 0.0f;
682 offset.ascenderOffset = 0.0f;
684 DWRITE_GLYPH_RUN run;
686 run.glyphAdvances = &advance;
687 run.fontFace = fTypeface->fDWriteFontFace.get();
688 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
690 run.glyphIndices = &index;
691 run.isSideways = FALSE;
692 run.glyphOffsets = &offset;
694 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
695 HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
696 1.0f, // pixelsPerDip,
700 0.0f, // baselineOriginX,
701 0.0f, // baselineOriginY,
703 "Could not create glyph run analysis.");
705 //NOTE: this assumes that the glyph has already been measured
706 //with an exact same glyph run analysis.
708 bbox.left = glyph.fLeft;
709 bbox.top = glyph.fTop;
710 bbox.right = glyph.fLeft + glyph.fWidth;
711 bbox.bottom = glyph.fTop + glyph.fHeight;
712 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
716 "Could not draw mask.");
717 return fBits.begin();
720 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
722 DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
723 DWRITE_TEXTURE_TYPE textureType = fTextureType;
724 if (glyph.fForceBW) {
725 renderingMode = DWRITE_RENDERING_MODE_ALIASED;
726 textureType = DWRITE_TEXTURE_ALIASED_1x1;
728 const void* bits = this->drawDWMask(glyph, renderingMode, textureType);
730 sk_bzero(glyph.fImage, glyph.computeImageSize());
734 //Copy the mask into the glyph.
735 const uint8_t* src = (const uint8_t*)bits;
736 if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
737 bilevel_to_bw(src, glyph);
738 const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
739 } else if (!isLCD(fRec)) {
740 if (fPreBlend.isApplicable()) {
741 rgb_to_a8<true>(src, glyph, fPreBlend.fG);
743 rgb_to_a8<false>(src, glyph, fPreBlend.fG);
745 } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
746 if (fPreBlend.isApplicable()) {
747 rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
749 rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
752 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
753 if (fPreBlend.isApplicable()) {
754 rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
756 rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
761 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
762 SkASSERT(&glyph && path);
766 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
767 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
768 "Could not create geometry to path converter.");
769 uint16_t glyphId = glyph.getGlyphID();
770 //TODO: convert to<->from DIUs? This would make a difference if hinting.
771 //It may not be needed, it appears that DirectWrite only hints at em size.
772 HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender),
779 geometryToPath.get()),
780 "Could not create glyph outline.");
782 path->transform(fSkXform);