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"
31 static bool isLCD(const SkScalerContext::Rec& rec) {
32 return SkMask::kLCD16_Format == rec.fMaskFormat ||
33 SkMask::kLCD32_Format == rec.fMaskFormat;
36 static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) {
37 AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
41 if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
44 if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
48 if (0 == maxp->version.tt.maxSizeOfInstructions) {
53 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
57 /** A PPEMRange is inclusive, [min, max]. */
63 /** If the rendering mode for the specified 'size' is gridfit, then place
64 * the gridfit range into 'range'. Otherwise, leave 'range' alone.
66 static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) {
67 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
71 if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
74 if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
75 gasp->version != SkOTTableGridAndScanProcedure::version1)
80 uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
81 if (numRanges > 1024 ||
82 gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
83 sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
88 const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
89 SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
91 for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) {
92 int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM);
93 // Test that the size is in range and the range is gridfit only.
94 if (minPPEM < size && size <= maxPPEM &&
95 rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask)
97 range->min = minPPEM + 1;
105 static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) {
107 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
111 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
114 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
118 uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
119 if (numSizes > 1024 ||
120 eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
121 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
126 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
127 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
128 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
129 if (sizeTable->ppemX == sizeTable->ppemY &&
130 range.min <= sizeTable->ppemX && sizeTable->ppemX <= range.max)
132 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
133 // to determine the actual number of glyphs with bitmaps.
135 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
137 // TODO: Ensure that the bitmaps are bi-level?
138 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
146 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
150 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
153 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
157 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
158 if (numSizes > 1024 ||
159 ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
160 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
165 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
166 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
167 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
168 if (scaleTable->ppemX == scaleTable->ppemY &&
169 range.min <= scaleTable->ppemX && scaleTable->ppemX <= range.max) {
170 // EBSC tables are normally only found in bitmap only fonts.
179 static bool both_zero(SkScalar a, SkScalar b) {
180 return 0 == a && 0 == b;
183 // returns false if there is any non-90-rotation or skew
184 static bool is_axis_aligned(const SkScalerContext::Rec& rec) {
185 return 0 == rec.fPreSkewX &&
186 (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
187 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
190 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
191 const SkDescriptor* desc)
192 : SkScalerContext(typeface, desc)
193 , fTypeface(SkRef(typeface))
196 // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC
197 // except when bi-level rendering is requested or there are embedded
198 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
200 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
201 // this. As a result, determine the actual size of the text and then see if
202 // there are any embedded bi-level bitmaps of that size. If there are, then
203 // force bitmaps by requesting bi-level rendering.
205 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
206 // square pixels and only uses ppemY. Therefore the transform must track any
207 // non-uniform x-scale.
209 // Also, rotated glyphs should have the same absolute advance widths as
210 // horizontal glyphs and the subpixel flag should not affect glyph shapes.
212 // A is the total matrix.
214 fRec.getSingleMatrix(&A);
216 // h is where A maps the horizontal baseline.
217 SkPoint h = SkPoint::Make(SK_Scalar1, 0);
220 // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
222 SkComputeGivensRotation(h, &G);
224 // GA is the matrix A with rotation removed.
228 // realTextSize is the actual device size we want (as opposed to the size the user requested).
229 // gdiTextSize is the size we request when GDI compatible.
230 // If the scale is negative, this means the matrix will do the flip anyway.
231 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
232 // Due to floating point math, the lower bits are suspect. Round carefully.
233 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
234 if (gdiTextSize == 0) {
235 gdiTextSize = SK_Scalar1;
238 bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
239 bool treatLikeBitmap = false;
240 bool axisAlignedBitmap = false;
241 if (bitmapRequested) {
242 // When embedded bitmaps are requested, treat the entire range like
243 // a bitmap strike if the range is gridfit only and contains a bitmap.
244 int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
245 PPEMRange range = { bitmapPPEM, bitmapPPEM };
246 expand_range_if_gridfit_only(typeface, bitmapPPEM, &range);
247 treatLikeBitmap = has_bitmap_strike(typeface, range);
249 axisAlignedBitmap = is_axis_aligned(fRec);
252 // If the user requested aliased, do so with aliased compatible metrics.
253 if (SkMask::kBW_Format == fRec.fMaskFormat) {
254 fTextSizeRender = gdiTextSize;
255 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
256 fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
257 fTextSizeMeasure = gdiTextSize;
258 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
260 // If we can use a bitmap, use gdi classic rendering and measurement.
261 // This will not always provide a bitmap, but matches expected behavior.
262 } else if (treatLikeBitmap && axisAlignedBitmap) {
263 fTextSizeRender = gdiTextSize;
264 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
265 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
266 fTextSizeMeasure = gdiTextSize;
267 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
269 // If rotated but the horizontal text could have used a bitmap,
270 // render high quality rotated glyphs but measure using bitmap metrics.
271 } else if (treatLikeBitmap) {
272 fTextSizeRender = gdiTextSize;
273 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
274 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
275 fTextSizeMeasure = gdiTextSize;
276 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
278 // Fonts that have hints but no gasp table get non-symmetric rendering.
279 // Usually such fonts have low quality hints which were never tested
280 // with anything but GDI ClearType classic. Such fonts often rely on
281 // drop out control in the y direction in order to be legible.
282 } else if (is_hinted_without_gasp(typeface)) {
283 fTextSizeRender = gdiTextSize;
284 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
285 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
286 fTextSizeMeasure = realTextSize;
287 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
289 // The normal case is to use natural symmetric rendering and linear metrics.
291 fTextSizeRender = realTextSize;
292 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
293 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
294 fTextSizeMeasure = realTextSize;
295 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
298 if (this->isSubpixel()) {
299 fTextSizeMeasure = realTextSize;
300 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
303 // Remove the realTextSize, as that is the text height scale currently in A.
304 SkScalar scale = SkScalarInvert(realTextSize);
306 // fSkXform is the total matrix A without the text height scale.
308 fSkXform.preScale(scale, scale); //remove the text height scale.
310 fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
311 fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
312 fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
313 fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
317 // GsA is the non-rotational part of A without the text height scale.
319 GsA.preScale(scale, scale); //remove text height scale, G is rotational so reorders with scale.
321 fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX));
322 fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
323 fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX));
324 fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY));
328 // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
329 fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
330 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
331 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
334 SkScalerContext_DW::~SkScalerContext_DW() {
337 unsigned SkScalerContext_DW::generateGlyphCount() {
338 if (fGlyphCount < 0) {
339 fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
344 uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
346 fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index);
350 void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
351 //Delta is the difference between the right/left side bearing metric
352 //and where the right/left side bearing ends up after hinting.
353 //DirectWrite does not provide this information.
354 glyph->fRsbDelta = 0;
355 glyph->fLsbDelta = 0;
357 glyph->fAdvanceX = 0;
358 glyph->fAdvanceY = 0;
360 uint16_t glyphId = glyph->getGlyphID();
361 DWRITE_GLYPH_METRICS gm;
363 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
364 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
366 HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
368 1.0f, // pixelsPerDip
370 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
373 "Could not get gdi compatible glyph metrics.");
375 HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
376 "Could not get design metrics.");
379 DWRITE_FONT_METRICS dwfm;
380 fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
381 SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
382 SkIntToScalar(gm.advanceWidth),
383 SkIntToScalar(dwfm.designUnitsPerEm));
385 SkVector vecs[1] = { { advanceX, 0 } };
386 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
387 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
389 // DirectWrite produced 'compatible' metrics, but while close,
390 // the end result is not always an integer as it would be with GDI.
391 vecs[0].fX = SkScalarRoundToScalar(advanceX);
392 fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
394 fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
397 glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
398 glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
401 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
404 this->generateAdvance(glyph);
406 //Measure raster size.
407 fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
408 fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
412 UINT16 glyphId = glyph->getGlyphID();
414 DWRITE_GLYPH_OFFSET offset;
415 offset.advanceOffset = 0.0f;
416 offset.ascenderOffset = 0.0f;
418 DWRITE_GLYPH_RUN run;
420 run.glyphAdvances = &advance;
421 run.fontFace = fTypeface->fDWriteFontFace.get();
422 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
424 run.glyphIndices = &glyphId;
425 run.isSideways = FALSE;
426 run.glyphOffsets = &offset;
428 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
429 HRVM(fTypeface->fFactory->CreateGlyphRunAnalysis(
431 1.0f, // pixelsPerDip,
435 0.0f, // baselineOriginX,
436 0.0f, // baselineOriginY,
438 "Could not create glyph run analysis.");
441 HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox),
442 "Could not get texture bounds.");
444 glyph->fWidth = SkToU16(bbox.right - bbox.left);
445 glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
446 glyph->fLeft = SkToS16(bbox.left);
447 glyph->fTop = SkToS16(bbox.top);
450 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) {
451 if (NULL == metrics) {
455 sk_bzero(metrics, sizeof(*metrics));
457 DWRITE_FONT_METRICS dwfm;
458 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
459 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
461 fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
463 1.0f, // pixelsPerDip
467 fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
470 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
472 metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
473 metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
474 metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
475 metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
476 metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
477 metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
479 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
480 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
482 if (NULL != fTypeface->fDWriteFontFace1.get()) {
483 DWRITE_FONT_METRICS1 dwfm1;
484 fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1);
485 metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
486 metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
487 metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
488 metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
490 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
492 AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get());
494 head.fSize >= sizeof(SkOTTableHead) &&
495 head->version == SkOTTableHead::version1)
497 metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
498 metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
499 metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
500 metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
502 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
504 metrics->fTop = metrics->fAscent;
505 metrics->fBottom = metrics->fDescent;
510 ///////////////////////////////////////////////////////////////////////////////
512 #include "SkColorPriv.h"
514 static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
515 const int width = glyph.fWidth;
516 const size_t dstRB = (width + 7) >> 3;
517 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
519 int byteCount = width >> 3;
520 int bitCount = width & 7;
522 for (int y = 0; y < glyph.fHeight; ++y) {
524 for (int i = 0; i < byteCount; ++i) {
526 byte |= src[0] & (1 << 7);
527 byte |= src[1] & (1 << 6);
528 byte |= src[2] & (1 << 5);
529 byte |= src[3] & (1 << 4);
530 byte |= src[4] & (1 << 3);
531 byte |= src[5] & (1 << 2);
532 byte |= src[6] & (1 << 1);
533 byte |= src[7] & (1 << 0);
540 unsigned mask = 0x80;
541 for (int i = 0; i < bitCount; i++) {
542 byte |= (src[i]) & mask;
545 dst[byteCount] = byte;
552 template<bool APPLY_PREBLEND>
553 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
554 const size_t dstRB = glyph.rowBytes();
555 const U16CPU width = glyph.fWidth;
556 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
558 for (U16CPU y = 0; y < glyph.fHeight; y++) {
559 for (U16CPU i = 0; i < width; i++) {
563 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
565 dst = (uint8_t*)((char*)dst + dstRB);
569 template<bool APPLY_PREBLEND>
570 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
571 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
572 const size_t dstRB = glyph.rowBytes();
573 const U16CPU width = glyph.fWidth;
574 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
576 for (U16CPU y = 0; y < glyph.fHeight; y++) {
577 for (U16CPU i = 0; i < width; i++) {
578 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
579 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
580 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
581 dst[i] = SkPack888ToRGB16(r, g, b);
583 dst = (uint16_t*)((char*)dst + dstRB);
587 template<bool APPLY_PREBLEND>
588 static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
589 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
590 const size_t dstRB = glyph.rowBytes();
591 const U16CPU width = glyph.fWidth;
592 SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage);
594 for (U16CPU y = 0; y < glyph.fHeight; y++) {
595 for (U16CPU i = 0; i < width; i++) {
596 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
597 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
598 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
599 dst[i] = SkPackARGB32(0xFF, r, g, b);
601 dst = (SkPMColor*)((char*)dst + dstRB);
605 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
606 int sizeNeeded = glyph.fWidth * glyph.fHeight;
607 if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) {
610 if (sizeNeeded > fBits.count()) {
611 fBits.setCount(sizeNeeded);
615 memset(fBits.begin(), 0, sizeNeeded);
617 fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
618 fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
620 FLOAT advance = 0.0f;
622 UINT16 index = glyph.getGlyphID();
624 DWRITE_GLYPH_OFFSET offset;
625 offset.advanceOffset = 0.0f;
626 offset.ascenderOffset = 0.0f;
628 DWRITE_GLYPH_RUN run;
630 run.glyphAdvances = &advance;
631 run.fontFace = fTypeface->fDWriteFontFace.get();
632 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
634 run.glyphIndices = &index;
635 run.isSideways = FALSE;
636 run.glyphOffsets = &offset;
638 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
639 HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
640 1.0f, // pixelsPerDip,
644 0.0f, // baselineOriginX,
645 0.0f, // baselineOriginY,
647 "Could not create glyph run analysis.");
649 //NOTE: this assumes that the glyph has already been measured
650 //with an exact same glyph run analysis.
652 bbox.left = glyph.fLeft;
653 bbox.top = glyph.fTop;
654 bbox.right = glyph.fLeft + glyph.fWidth;
655 bbox.bottom = glyph.fTop + glyph.fHeight;
656 HRNM(glyphRunAnalysis->CreateAlphaTexture(fTextureType,
660 "Could not draw mask.");
661 return fBits.begin();
664 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
666 const void* bits = this->drawDWMask(glyph);
668 sk_bzero(glyph.fImage, glyph.computeImageSize());
672 //Copy the mask into the glyph.
673 const uint8_t* src = (const uint8_t*)bits;
674 if (DWRITE_RENDERING_MODE_ALIASED == fRenderingMode) {
675 bilevel_to_bw(src, glyph);
676 const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
677 } else if (!isLCD(fRec)) {
678 if (fPreBlend.isApplicable()) {
679 rgb_to_a8<true>(src, glyph, fPreBlend.fG);
681 rgb_to_a8<false>(src, glyph, fPreBlend.fG);
683 } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
684 if (fPreBlend.isApplicable()) {
685 rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
687 rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
690 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
691 if (fPreBlend.isApplicable()) {
692 rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
694 rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
699 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
700 SkASSERT(&glyph && path);
704 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
705 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
706 "Could not create geometry to path converter.");
707 uint16_t glyphId = glyph.getGlyphID();
708 //TODO: convert to<->from DIUs? This would make a difference if hinting.
709 //It may not be needed, it appears that DirectWrite only hints at em size.
710 HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender),
717 geometryToPath.get()),
718 "Could not create glyph outline.");
720 path->transform(fSkXform);