42f98418377e5426ffd46449df3e3d89c8fd6faa
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / ports / SkScalerContext_win_dw.cpp
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 #undef GetGlyphIndices
10
11 #include "SkDWrite.h"
12 #include "SkDWriteGeometrySink.h"
13 #include "SkEndian.h"
14 #include "SkGlyph.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 "SkPath.h"
22 #include "SkScalerContext.h"
23 #include "SkScalerContext_win_dw.h"
24 #include "SkTScopedComPtr.h"
25 #include "SkTypeface_win_dw.h"
26
27 #include <dwrite.h>
28
29 static bool isLCD(const SkScalerContext::Rec& rec) {
30     return SkMask::kLCD16_Format == rec.fMaskFormat ||
31            SkMask::kLCD32_Format == rec.fMaskFormat;
32 }
33
34 /** A PPEMRange is inclusive, [min, max]. */
35 struct PPEMRange {
36     int min;
37     int max;
38 };
39
40 /** If the rendering mode for the specified 'size' is gridfit, then place
41  *  the gridfit range into 'range'. Otherwise, leave 'range' alone.
42  */
43 static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) {
44     AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
45     if (!gasp.fExists) {
46         return;
47     }
48     if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
49         return;
50     }
51     if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
52         gasp->version != SkOTTableGridAndScanProcedure::version1)
53     {
54         return ;
55     }
56
57     uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
58     if (numRanges > 1024 ||
59         gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
60                      sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
61     {
62         return;
63     }
64
65     const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
66             SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
67     int minPPEM = -1;
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)
73         {
74             range->min = minPPEM + 1;
75             range->max = maxPPEM;
76             return;
77         }
78         minPPEM = maxPPEM;
79     }
80
81     return;
82 }
83
84 static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) {
85     {
86         AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
87         if (!eblc.fExists) {
88             return false;
89         }
90         if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
91             return false;
92         }
93         if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
94             return false;
95         }
96
97         uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
98         if (numSizes > 1024 ||
99             eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
100                          sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
101         {
102             return false;
103         }
104
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)
110             {
111                 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
112                 // to determine the actual number of glyphs with bitmaps.
113
114                 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
115
116                 // TODO: Ensure that the bitmaps are bi-level?
117                 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
118                     return true;
119                 }
120             }
121         }
122     }
123
124     {
125         AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
126         if (!ebsc.fExists) {
127             return false;
128         }
129         if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
130             return false;
131         }
132         if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
133             return false;
134         }
135
136         uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
137         if (numSizes > 1024 ||
138             ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
139                          sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
140         {
141             return false;
142         }
143
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.
150                 return true;
151             }
152         }
153     }
154
155     return false;
156 }
157
158 static bool both_zero(SkScalar a, SkScalar b) {
159     return 0 == a && 0 == b;
160 }
161
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]));
167 }
168
169 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
170                                        const SkDescriptor* desc)
171         : SkScalerContext(typeface, desc)
172         , fTypeface(SkRef(typeface))
173         , fGlyphCount(-1) {
174
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).
178     //
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.
183     //
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.
187     //
188     // Also, rotated glyphs should have the same absolute advance widths as
189     // horizontal glyphs and the subpixel flag should not affect glyph shapes.
190
191     // A is the total matrix.
192     SkMatrix A;
193     fRec.getSingleMatrix(&A);
194
195     // h is where A maps the horizontal baseline.
196     SkPoint h = SkPoint::Make(SK_Scalar1, 0);
197     A.mapPoints(&h, 1);
198
199     // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
200     SkMatrix G;
201     SkComputeGivensRotation(h, &G);
202
203     // GA is the matrix A with rotation removed.
204     SkMatrix GA(G);
205     GA.preConcat(A);
206
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;
215     }
216
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);
227
228         axisAlignedBitmap = is_axis_aligned(fRec);
229     }
230
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;
238
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;
247
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;
256
257     // The normal case is to use natural symmetric rendering and linear metrics.
258     } else {
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;
264     }
265
266     if (this->isSubpixel()) {
267         fTextSizeMeasure = realTextSize;
268         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
269     }
270
271     // Remove the realTextSize, as that is the text height scale currently in A.
272     SkScalar scale = SkScalarInvert(realTextSize);
273
274     // fSkXform is the total matrix A without the text height scale.
275     fSkXform = A;
276     fSkXform.preScale(scale, scale); //remove the text height scale.
277
278     fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
279     fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
280     fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
281     fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
282     fXform.dx = 0;
283     fXform.dy = 0;
284
285     // GsA is the non-rotational part of A without the text height scale.
286     SkMatrix GsA(GA);
287     GsA.preScale(scale, scale); //remove text height scale, G is rotational so reorders with scale.
288
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));
293     fGsA.dx = 0;
294     fGsA.dy = 0;
295
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));
300 }
301
302 SkScalerContext_DW::~SkScalerContext_DW() {
303 }
304
305 unsigned SkScalerContext_DW::generateGlyphCount() {
306     if (fGlyphCount < 0) {
307         fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
308     }
309     return fGlyphCount;
310 }
311
312 uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
313     uint16_t index = 0;
314     fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index);
315     return index;
316 }
317
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;
324
325     glyph->fAdvanceX = 0;
326     glyph->fAdvanceY = 0;
327
328     uint16_t glyphId = glyph->getGlyphID();
329     DWRITE_GLYPH_METRICS gm;
330
331     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
332         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
333     {
334         HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
335                  fTextSizeMeasure,
336                  1.0f, // pixelsPerDip
337                  &fGsA,
338                  DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
339                  &glyphId, 1,
340                  &gm),
341              "Could not get gdi compatible glyph metrics.");
342     } else {
343         HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
344              "Could not get design metrics.");
345     }
346
347     DWRITE_FONT_METRICS dwfm;
348     fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
349     SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
350                                        SkIntToScalar(gm.advanceWidth),
351                                        SkIntToScalar(dwfm.designUnitsPerEm));
352
353     if (!this->isSubpixel()) {
354         advanceX = SkScalarRoundToScalar(advanceX);
355     }
356
357     SkVector vecs[1] = { { advanceX, 0 } };
358     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
359         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
360     {
361         fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
362     } else {
363         fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
364     }
365
366     glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
367     glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
368 }
369
370 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
371     glyph->fWidth = 0;
372
373     this->generateAdvance(glyph);
374
375     //Measure raster size.
376     fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
377     fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
378
379     FLOAT advance = 0;
380
381     UINT16 glyphId = glyph->getGlyphID();
382
383     DWRITE_GLYPH_OFFSET offset;
384     offset.advanceOffset = 0.0f;
385     offset.ascenderOffset = 0.0f;
386
387     DWRITE_GLYPH_RUN run;
388     run.glyphCount = 1;
389     run.glyphAdvances = &advance;
390     run.fontFace = fTypeface->fDWriteFontFace.get();
391     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
392     run.bidiLevel = 0;
393     run.glyphIndices = &glyphId;
394     run.isSideways = FALSE;
395     run.glyphOffsets = &offset;
396
397     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
398     HRVM(fTypeface->fFactory->CreateGlyphRunAnalysis(
399              &run,
400              1.0f, // pixelsPerDip,
401              &fXform,
402              fRenderingMode,
403              fMeasuringMode,
404              0.0f, // baselineOriginX,
405              0.0f, // baselineOriginY,
406              &glyphRunAnalysis),
407          "Could not create glyph run analysis.");
408
409     RECT bbox;
410     HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox),
411          "Could not get texture bounds.");
412
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);
417 }
418
419 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx,
420                                              SkPaint::FontMetrics* my) {
421     if (!(mx || my))
422       return;
423
424     if (mx) {
425         sk_bzero(mx, sizeof(*mx));
426     }
427     if (my) {
428         sk_bzero(my, sizeof(*my));
429     }
430
431     DWRITE_FONT_METRICS dwfm;
432     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
433         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
434     {
435         fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
436              fTextSizeRender,
437              1.0f, // pixelsPerDip
438              &fXform,
439              &dwfm);
440     } else {
441         fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
442     }
443
444     SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
445     if (mx) {
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);
454
455         mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
456         mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
457     }
458
459     if (my) {
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);
468
469         my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
470         my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
471     }
472 }
473
474 ///////////////////////////////////////////////////////////////////////////////
475
476 #include "SkColorPriv.h"
477
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);
482
483     int byteCount = width >> 3;
484     int bitCount = width & 7;
485
486     for (int y = 0; y < glyph.fHeight; ++y) {
487         if (byteCount > 0) {
488             for (int i = 0; i < byteCount; ++i) {
489                 unsigned byte = 0;
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);
498                 dst[i] = byte;
499                 src += 8;
500             }
501         }
502         if (bitCount > 0) {
503             unsigned byte = 0;
504             unsigned mask = 0x80;
505             for (int i = 0; i < bitCount; i++) {
506                 byte |= (src[i]) & mask;
507                 mask >>= 1;
508             }
509             dst[byteCount] = byte;
510         }
511         src += bitCount;
512         dst += dstRB;
513     }
514 }
515
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);
521
522     for (U16CPU y = 0; y < glyph.fHeight; y++) {
523         for (U16CPU i = 0; i < width; i++) {
524             U8CPU r = *(src++);
525             U8CPU g = *(src++);
526             U8CPU b = *(src++);
527             dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
528         }
529         dst = (uint8_t*)((char*)dst + dstRB);
530     }
531 }
532
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);
539
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);
546         }
547         dst = (uint16_t*)((char*)dst + dstRB);
548     }
549 }
550
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);
557
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);
564         }
565         dst = (SkPMColor*)((char*)dst + dstRB);
566     }
567 }
568
569 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
570     int sizeNeeded = glyph.fWidth * glyph.fHeight;
571     if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) {
572         sizeNeeded *= 3;
573     }
574     if (sizeNeeded > fBits.count()) {
575         fBits.setCount(sizeNeeded);
576     }
577
578     // erase
579     memset(fBits.begin(), 0, sizeNeeded);
580
581     fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
582     fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
583
584     FLOAT advance = 0.0f;
585
586     UINT16 index = glyph.getGlyphID();
587
588     DWRITE_GLYPH_OFFSET offset;
589     offset.advanceOffset = 0.0f;
590     offset.ascenderOffset = 0.0f;
591
592     DWRITE_GLYPH_RUN run;
593     run.glyphCount = 1;
594     run.glyphAdvances = &advance;
595     run.fontFace = fTypeface->fDWriteFontFace.get();
596     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
597     run.bidiLevel = 0;
598     run.glyphIndices = &index;
599     run.isSideways = FALSE;
600     run.glyphOffsets = &offset;
601
602     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
603     HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
604                                           1.0f, // pixelsPerDip,
605                                           &fXform,
606                                           fRenderingMode,
607                                           fMeasuringMode,
608                                           0.0f, // baselineOriginX,
609                                           0.0f, // baselineOriginY,
610                                           &glyphRunAnalysis),
611          "Could not create glyph run analysis.");
612
613     //NOTE: this assumes that the glyph has already been measured
614     //with an exact same glyph run analysis.
615     RECT bbox;
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,
621                                               &bbox,
622                                               fBits.begin(),
623                                               sizeNeeded),
624          "Could not draw mask.");
625     return fBits.begin();
626 }
627
628 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
629     //Create the mask.
630     const void* bits = this->drawDWMask(glyph);
631     if (!bits) {
632         sk_bzero(glyph.fImage, glyph.computeImageSize());
633         return;
634     }
635
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);
644         } else {
645             rgb_to_a8<false>(src, glyph, fPreBlend.fG);
646         }
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);
650         } else {
651             rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
652         }
653     } else {
654         SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
655         if (fPreBlend.isApplicable()) {
656             rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
657         } else {
658             rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
659         }
660     }
661 }
662
663 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
664     SkASSERT(&glyph && path);
665
666     path->reset();
667
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),
675                                        &glyphId,
676                                        NULL, //advances
677                                        NULL, //offsets
678                                        1, //num glyphs
679                                        FALSE, //sideways
680                                        FALSE, //rtl
681                                        geometryToPath.get()),
682          "Could not create glyph outline.");
683
684     path->transform(fSkXform);
685 }