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"
22 #include "SkScalerContext.h"
23 #include "SkScalerContext_win_dw.h"
24 #include "SkTScopedComPtr.h"
25 #include "SkTypeface_win_dw.h"
29 static bool isLCD(const SkScalerContext::Rec& rec) {
30 return SkMask::kLCD16_Format == rec.fMaskFormat ||
31 SkMask::kLCD32_Format == rec.fMaskFormat;
34 /** A PPEMRange is inclusive, [min, max]. */
40 /** If the rendering mode for the specified 'size' is gridfit, then place
41 * the gridfit range into 'range'. Otherwise, leave 'range' alone.
43 static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) {
44 AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
48 if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
51 if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
52 gasp->version != SkOTTableGridAndScanProcedure::version1)
57 uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
58 if (numRanges > 1024 ||
59 gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
60 sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
65 const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
66 SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
68 for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) {
69 int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM);
70 // Test that the size is in range and the range is gridfit only.
71 if (minPPEM < size && size <= maxPPEM &&
72 rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask)
74 range->min = minPPEM + 1;
84 static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) {
86 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
90 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
93 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
97 uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
98 if (numSizes > 1024 ||
99 eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
100 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
105 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
106 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
107 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
108 if (sizeTable->ppemX == sizeTable->ppemY &&
109 range.min <= sizeTable->ppemX && sizeTable->ppemX <= range.max)
111 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
112 // to determine the actual number of glyphs with bitmaps.
114 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
116 // TODO: Ensure that the bitmaps are bi-level?
117 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
125 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
129 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
132 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
136 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
137 if (numSizes > 1024 ||
138 ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
139 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
144 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
145 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
146 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
147 if (scaleTable->ppemX == scaleTable->ppemY &&
148 range.min <= scaleTable->ppemX && scaleTable->ppemX <= range.max) {
149 // EBSC tables are normally only found in bitmap only fonts.
158 static bool both_zero(SkScalar a, SkScalar b) {
159 return 0 == a && 0 == b;
162 // returns false if there is any non-90-rotation or skew
163 static bool is_axis_aligned(const SkScalerContext::Rec& rec) {
164 return 0 == rec.fPreSkewX &&
165 (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
166 both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
169 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
170 const SkDescriptor* desc)
171 : SkScalerContext(typeface, desc)
172 , fTypeface(SkRef(typeface))
175 // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC
176 // except when bi-level rendering is requested or there are embedded
177 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
179 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
180 // this. As a result, determine the actual size of the text and then see if
181 // there are any embedded bi-level bitmaps of that size. If there are, then
182 // force bitmaps by requesting bi-level rendering.
184 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
185 // square pixels and only uses ppemY. Therefore the transform must track any
186 // non-uniform x-scale.
188 // Also, rotated glyphs should have the same absolute advance widths as
189 // horizontal glyphs and the subpixel flag should not affect glyph shapes.
191 // A is the total matrix.
193 fRec.getSingleMatrix(&A);
195 // h is where A maps the horizontal baseline.
196 SkPoint h = SkPoint::Make(SK_Scalar1, 0);
199 // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
201 SkComputeGivensRotation(h, &G);
203 // GA is the matrix A with rotation removed.
207 // realTextSize is the actual device size we want (as opposed to the size the user requested).
208 // gdiTextSize is the size we request when GDI compatible.
209 // If the scale is negative, this means the matrix will do the flip anyway.
210 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
211 // Due to floating point math, the lower bits are suspect. Round carefully.
212 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
213 if (gdiTextSize == 0) {
214 gdiTextSize = SK_Scalar1;
217 bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
218 bool treatLikeBitmap = false;
219 bool axisAlignedBitmap = false;
220 if (bitmapRequested) {
221 // When embedded bitmaps are requested, treat the entire range like
222 // a bitmap strike if the range is gridfit only and contains a bitmap.
223 int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
224 PPEMRange range = { bitmapPPEM, bitmapPPEM };
225 expand_range_if_gridfit_only(typeface, bitmapPPEM, &range);
226 treatLikeBitmap = has_bitmap_strike(typeface, range);
228 axisAlignedBitmap = is_axis_aligned(fRec);
231 // If the user requested aliased, do so with aliased compatible metrics.
232 if (SkMask::kBW_Format == fRec.fMaskFormat) {
233 fTextSizeRender = gdiTextSize;
234 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
235 fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
236 fTextSizeMeasure = gdiTextSize;
237 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
239 // If we can use a bitmap, use gdi classic rendering and measurement.
240 // This will not always provide a bitmap, but matches expected behavior.
241 } else if (treatLikeBitmap && axisAlignedBitmap) {
242 fTextSizeRender = gdiTextSize;
243 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
244 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
245 fTextSizeMeasure = gdiTextSize;
246 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
248 // If rotated but the horizontal text could have used a bitmap,
249 // render high quality rotated glyphs but measure using bitmap metrics.
250 } else if (treatLikeBitmap) {
251 fTextSizeRender = gdiTextSize;
252 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
253 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
254 fTextSizeMeasure = gdiTextSize;
255 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
257 // The normal case is to use natural symmetric rendering and linear metrics.
259 fTextSizeRender = realTextSize;
260 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
261 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
262 fTextSizeMeasure = realTextSize;
263 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
266 if (this->isSubpixel()) {
267 fTextSizeMeasure = realTextSize;
268 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
271 // Remove the realTextSize, as that is the text height scale currently in A.
272 SkScalar scale = SkScalarInvert(realTextSize);
274 // fSkXform is the total matrix A without the text height scale.
276 fSkXform.preScale(scale, scale); //remove the text height scale.
278 fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
279 fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
280 fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
281 fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
285 // GsA is the non-rotational part of A without the text height scale.
287 GsA.preScale(scale, scale); //remove text height scale, G is rotational so reorders with scale.
289 fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX));
290 fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
291 fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX));
292 fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY));
296 // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
297 fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
298 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
299 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
302 SkScalerContext_DW::~SkScalerContext_DW() {
305 unsigned SkScalerContext_DW::generateGlyphCount() {
306 if (fGlyphCount < 0) {
307 fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
312 uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
314 fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index);
318 void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
319 //Delta is the difference between the right/left side bearing metric
320 //and where the right/left side bearing ends up after hinting.
321 //DirectWrite does not provide this information.
322 glyph->fRsbDelta = 0;
323 glyph->fLsbDelta = 0;
325 glyph->fAdvanceX = 0;
326 glyph->fAdvanceY = 0;
328 uint16_t glyphId = glyph->getGlyphID();
329 DWRITE_GLYPH_METRICS gm;
331 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
332 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
334 HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
336 1.0f, // pixelsPerDip
338 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
341 "Could not get gdi compatible glyph metrics.");
343 HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
344 "Could not get design metrics.");
347 DWRITE_FONT_METRICS dwfm;
348 fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
349 SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
350 SkIntToScalar(gm.advanceWidth),
351 SkIntToScalar(dwfm.designUnitsPerEm));
353 if (!this->isSubpixel()) {
354 advanceX = SkScalarRoundToScalar(advanceX);
357 SkVector vecs[1] = { { advanceX, 0 } };
358 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
359 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
361 fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
363 fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
366 glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
367 glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
370 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
373 this->generateAdvance(glyph);
375 //Measure raster size.
376 fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
377 fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
381 UINT16 glyphId = glyph->getGlyphID();
383 DWRITE_GLYPH_OFFSET offset;
384 offset.advanceOffset = 0.0f;
385 offset.ascenderOffset = 0.0f;
387 DWRITE_GLYPH_RUN run;
389 run.glyphAdvances = &advance;
390 run.fontFace = fTypeface->fDWriteFontFace.get();
391 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
393 run.glyphIndices = &glyphId;
394 run.isSideways = FALSE;
395 run.glyphOffsets = &offset;
397 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
398 HRVM(fTypeface->fFactory->CreateGlyphRunAnalysis(
400 1.0f, // pixelsPerDip,
404 0.0f, // baselineOriginX,
405 0.0f, // baselineOriginY,
407 "Could not create glyph run analysis.");
410 HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox),
411 "Could not get texture bounds.");
413 glyph->fWidth = SkToU16(bbox.right - bbox.left);
414 glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
415 glyph->fLeft = SkToS16(bbox.left);
416 glyph->fTop = SkToS16(bbox.top);
419 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx,
420 SkPaint::FontMetrics* my) {
425 sk_bzero(mx, sizeof(*mx));
428 sk_bzero(my, sizeof(*my));
431 DWRITE_FONT_METRICS dwfm;
432 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
433 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
435 fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
437 1.0f, // pixelsPerDip
441 fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
444 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
446 mx->fTop = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
447 mx->fAscent = mx->fTop;
448 mx->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
449 mx->fBottom = mx->fDescent;
450 mx->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
451 mx->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
452 mx->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
453 mx->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
455 mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
456 mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
460 my->fTop = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
461 my->fAscent = my->fTop;
462 my->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
463 my->fBottom = my->fDescent;
464 my->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
465 my->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
466 my->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
467 my->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
469 my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
470 my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
474 ///////////////////////////////////////////////////////////////////////////////
476 #include "SkColorPriv.h"
478 static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
479 const int width = glyph.fWidth;
480 const size_t dstRB = (width + 7) >> 3;
481 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
483 int byteCount = width >> 3;
484 int bitCount = width & 7;
486 for (int y = 0; y < glyph.fHeight; ++y) {
488 for (int i = 0; i < byteCount; ++i) {
490 byte |= src[0] & (1 << 7);
491 byte |= src[1] & (1 << 6);
492 byte |= src[2] & (1 << 5);
493 byte |= src[3] & (1 << 4);
494 byte |= src[4] & (1 << 3);
495 byte |= src[5] & (1 << 2);
496 byte |= src[6] & (1 << 1);
497 byte |= src[7] & (1 << 0);
504 unsigned mask = 0x80;
505 for (int i = 0; i < bitCount; i++) {
506 byte |= (src[i]) & mask;
509 dst[byteCount] = byte;
516 template<bool APPLY_PREBLEND>
517 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
518 const size_t dstRB = glyph.rowBytes();
519 const U16CPU width = glyph.fWidth;
520 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
522 for (U16CPU y = 0; y < glyph.fHeight; y++) {
523 for (U16CPU i = 0; i < width; i++) {
527 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
529 dst = (uint8_t*)((char*)dst + dstRB);
533 template<bool APPLY_PREBLEND>
534 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
535 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
536 const size_t dstRB = glyph.rowBytes();
537 const U16CPU width = glyph.fWidth;
538 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
540 for (U16CPU y = 0; y < glyph.fHeight; y++) {
541 for (U16CPU i = 0; i < width; i++) {
542 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
543 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
544 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
545 dst[i] = SkPack888ToRGB16(r, g, b);
547 dst = (uint16_t*)((char*)dst + dstRB);
551 template<bool APPLY_PREBLEND>
552 static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
553 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
554 const size_t dstRB = glyph.rowBytes();
555 const U16CPU width = glyph.fWidth;
556 SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage);
558 for (U16CPU y = 0; y < glyph.fHeight; y++) {
559 for (U16CPU i = 0; i < width; i++) {
560 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
561 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
562 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
563 dst[i] = SkPackARGB32(0xFF, r, g, b);
565 dst = (SkPMColor*)((char*)dst + dstRB);
569 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
570 int sizeNeeded = glyph.fWidth * glyph.fHeight;
571 if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) {
574 if (sizeNeeded > fBits.count()) {
575 fBits.setCount(sizeNeeded);
579 memset(fBits.begin(), 0, sizeNeeded);
581 fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
582 fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
584 FLOAT advance = 0.0f;
586 UINT16 index = glyph.getGlyphID();
588 DWRITE_GLYPH_OFFSET offset;
589 offset.advanceOffset = 0.0f;
590 offset.ascenderOffset = 0.0f;
592 DWRITE_GLYPH_RUN run;
594 run.glyphAdvances = &advance;
595 run.fontFace = fTypeface->fDWriteFontFace.get();
596 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
598 run.glyphIndices = &index;
599 run.isSideways = FALSE;
600 run.glyphOffsets = &offset;
602 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
603 HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
604 1.0f, // pixelsPerDip,
608 0.0f, // baselineOriginX,
609 0.0f, // baselineOriginY,
611 "Could not create glyph run analysis.");
613 //NOTE: this assumes that the glyph has already been measured
614 //with an exact same glyph run analysis.
616 bbox.left = glyph.fLeft;
617 bbox.top = glyph.fTop;
618 bbox.right = glyph.fLeft + glyph.fWidth;
619 bbox.bottom = glyph.fTop + glyph.fHeight;
620 HRNM(glyphRunAnalysis->CreateAlphaTexture(fTextureType,
624 "Could not draw mask.");
625 return fBits.begin();
628 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
630 const void* bits = this->drawDWMask(glyph);
632 sk_bzero(glyph.fImage, glyph.computeImageSize());
636 //Copy the mask into the glyph.
637 const uint8_t* src = (const uint8_t*)bits;
638 if (DWRITE_RENDERING_MODE_ALIASED == fRenderingMode) {
639 bilevel_to_bw(src, glyph);
640 const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
641 } else if (!isLCD(fRec)) {
642 if (fPreBlend.isApplicable()) {
643 rgb_to_a8<true>(src, glyph, fPreBlend.fG);
645 rgb_to_a8<false>(src, glyph, fPreBlend.fG);
647 } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
648 if (fPreBlend.isApplicable()) {
649 rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
651 rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
654 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
655 if (fPreBlend.isApplicable()) {
656 rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
658 rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
663 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
664 SkASSERT(&glyph && path);
668 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
669 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
670 "Could not create geometry to path converter.");
671 uint16_t glyphId = glyph.getGlyphID();
672 //TODO: convert to<->from DIUs? This would make a difference if hinting.
673 //It may not be needed, it appears that DirectWrite only hints at em size.
674 HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender),
681 geometryToPath.get()),
682 "Could not create glyph outline.");
684 path->transform(fSkXform);