f27497be62ef7e40fdc88fede12c183624cbb227
[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 "SkOTTable_maxp.h"
22 #include "SkPath.h"
23 #include "SkScalerContext.h"
24 #include "SkScalerContext_win_dw.h"
25 #include "SkTScopedComPtr.h"
26 #include "SkTypeface_win_dw.h"
27
28 #include <dwrite.h>
29 #include <dwrite_1.h>
30
31 static bool isLCD(const SkScalerContext::Rec& rec) {
32     return SkMask::kLCD16_Format == rec.fMaskFormat ||
33            SkMask::kLCD32_Format == rec.fMaskFormat;
34 }
35
36 static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) {
37     AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
38     if (!maxp.fExists) {
39         return false;
40     }
41     if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
42         return false;
43     }
44     if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
45         return false;
46     }
47
48     if (0 == maxp->version.tt.maxSizeOfInstructions) {
49         // No hints.
50         return false;
51     }
52
53     AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
54     return !gasp.fExists;
55 }
56
57 /** A PPEMRange is inclusive, [min, max]. */
58 struct PPEMRange {
59     int min;
60     int max;
61 };
62
63 /** If the rendering mode for the specified 'size' is gridfit, then place
64  *  the gridfit range into 'range'. Otherwise, leave 'range' alone.
65  */
66 static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) {
67     AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
68     if (!gasp.fExists) {
69         return;
70     }
71     if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
72         return;
73     }
74     if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
75         gasp->version != SkOTTableGridAndScanProcedure::version1)
76     {
77         return;
78     }
79
80     uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
81     if (numRanges > 1024 ||
82         gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
83                      sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
84     {
85         return;
86     }
87
88     const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
89             SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
90     int minPPEM = -1;
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)
96         {
97             range->min = minPPEM + 1;
98             range->max = maxPPEM;
99             return;
100         }
101         minPPEM = maxPPEM;
102     }
103 }
104
105 static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) {
106     {
107         AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
108         if (!eblc.fExists) {
109             return false;
110         }
111         if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
112             return false;
113         }
114         if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
115             return false;
116         }
117
118         uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
119         if (numSizes > 1024 ||
120             eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
121                          sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
122         {
123             return false;
124         }
125
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)
131             {
132                 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
133                 // to determine the actual number of glyphs with bitmaps.
134
135                 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
136
137                 // TODO: Ensure that the bitmaps are bi-level?
138                 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
139                     return true;
140                 }
141             }
142         }
143     }
144
145     {
146         AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
147         if (!ebsc.fExists) {
148             return false;
149         }
150         if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
151             return false;
152         }
153         if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
154             return false;
155         }
156
157         uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
158         if (numSizes > 1024 ||
159             ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
160                          sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
161         {
162             return false;
163         }
164
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.
171                 return true;
172             }
173         }
174     }
175
176     return false;
177 }
178
179 static bool both_zero(SkScalar a, SkScalar b) {
180     return 0 == a && 0 == b;
181 }
182
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]));
188 }
189
190 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
191                                        const SkDescriptor* desc)
192         : SkScalerContext(typeface, desc)
193         , fTypeface(SkRef(typeface))
194         , fGlyphCount(-1) {
195
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).
199     //
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.
204     //
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.
208     //
209     // Also, rotated glyphs should have the same absolute advance widths as
210     // horizontal glyphs and the subpixel flag should not affect glyph shapes.
211
212     // A is the total matrix.
213     SkMatrix A;
214     fRec.getSingleMatrix(&A);
215
216     // h is where A maps the horizontal baseline.
217     SkPoint h = SkPoint::Make(SK_Scalar1, 0);
218     A.mapPoints(&h, 1);
219
220     // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
221     SkMatrix G;
222     SkComputeGivensRotation(h, &G);
223
224     // GA is the matrix A with rotation removed.
225     SkMatrix GA(G);
226     GA.preConcat(A);
227
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;
236     }
237
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);
248
249         axisAlignedBitmap = is_axis_aligned(fRec);
250     }
251
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;
259
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;
268
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;
277
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;
288
289     // The normal case is to use natural symmetric rendering and linear metrics.
290     } else {
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;
296     }
297
298     if (this->isSubpixel()) {
299         fTextSizeMeasure = realTextSize;
300         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
301     }
302
303     // Remove the realTextSize, as that is the text height scale currently in A.
304     SkScalar scale = SkScalarInvert(realTextSize);
305
306     // fSkXform is the total matrix A without the text height scale.
307     fSkXform = A;
308     fSkXform.preScale(scale, scale); //remove the text height scale.
309
310     fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
311     fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
312     fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
313     fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
314     fXform.dx = 0;
315     fXform.dy = 0;
316
317     // GsA is the non-rotational part of A without the text height scale.
318     SkMatrix GsA(GA);
319     GsA.preScale(scale, scale); //remove text height scale, G is rotational so reorders with scale.
320
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));
325     fGsA.dx = 0;
326     fGsA.dy = 0;
327
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));
332 }
333
334 SkScalerContext_DW::~SkScalerContext_DW() {
335 }
336
337 unsigned SkScalerContext_DW::generateGlyphCount() {
338     if (fGlyphCount < 0) {
339         fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
340     }
341     return fGlyphCount;
342 }
343
344 uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
345     uint16_t index = 0;
346     fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index);
347     return index;
348 }
349
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;
356
357     glyph->fAdvanceX = 0;
358     glyph->fAdvanceY = 0;
359
360     uint16_t glyphId = glyph->getGlyphID();
361     DWRITE_GLYPH_METRICS gm;
362
363     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
364         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
365     {
366         HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
367                  fTextSizeMeasure,
368                  1.0f, // pixelsPerDip
369                  &fGsA,
370                  DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
371                  &glyphId, 1,
372                  &gm),
373              "Could not get gdi compatible glyph metrics.");
374     } else {
375         HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
376              "Could not get design metrics.");
377     }
378
379     DWRITE_FONT_METRICS dwfm;
380     fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
381     SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
382                                        SkIntToScalar(gm.advanceWidth),
383                                        SkIntToScalar(dwfm.designUnitsPerEm));
384
385     SkVector vecs[1] = { { advanceX, 0 } };
386     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
387         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
388     {
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));
393     } else {
394         fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
395     }
396
397     glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
398     glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
399 }
400
401 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
402     glyph->fWidth = 0;
403
404     this->generateAdvance(glyph);
405
406     //Measure raster size.
407     fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
408     fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
409
410     FLOAT advance = 0;
411
412     UINT16 glyphId = glyph->getGlyphID();
413
414     DWRITE_GLYPH_OFFSET offset;
415     offset.advanceOffset = 0.0f;
416     offset.ascenderOffset = 0.0f;
417
418     DWRITE_GLYPH_RUN run;
419     run.glyphCount = 1;
420     run.glyphAdvances = &advance;
421     run.fontFace = fTypeface->fDWriteFontFace.get();
422     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
423     run.bidiLevel = 0;
424     run.glyphIndices = &glyphId;
425     run.isSideways = FALSE;
426     run.glyphOffsets = &offset;
427
428     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
429     HRVM(fTypeface->fFactory->CreateGlyphRunAnalysis(
430              &run,
431              1.0f, // pixelsPerDip,
432              &fXform,
433              fRenderingMode,
434              fMeasuringMode,
435              0.0f, // baselineOriginX,
436              0.0f, // baselineOriginY,
437              &glyphRunAnalysis),
438          "Could not create glyph run analysis.");
439
440     RECT bbox;
441     HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox),
442          "Could not get texture bounds.");
443
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);
448 }
449
450 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) {
451     if (NULL == metrics) {
452         return;
453     }
454
455     sk_bzero(metrics, sizeof(*metrics));
456
457     DWRITE_FONT_METRICS dwfm;
458     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
459         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
460     {
461         fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
462              fTextSizeRender,
463              1.0f, // pixelsPerDip
464              &fXform,
465              &dwfm);
466     } else {
467         fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
468     }
469
470     SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
471
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);
478
479     metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
480     metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
481
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;
489
490         metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
491     } else {
492         AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get());
493         if (head.fExists &&
494             head.fSize >= sizeof(SkOTTableHead) &&
495             head->version == SkOTTableHead::version1)
496         {
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;
501
502             metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
503         } else {
504             metrics->fTop = metrics->fAscent;
505             metrics->fBottom = metrics->fDescent;
506         }
507     }
508 }
509
510 ///////////////////////////////////////////////////////////////////////////////
511
512 #include "SkColorPriv.h"
513
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);
518
519     int byteCount = width >> 3;
520     int bitCount = width & 7;
521
522     for (int y = 0; y < glyph.fHeight; ++y) {
523         if (byteCount > 0) {
524             for (int i = 0; i < byteCount; ++i) {
525                 unsigned byte = 0;
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);
534                 dst[i] = byte;
535                 src += 8;
536             }
537         }
538         if (bitCount > 0) {
539             unsigned byte = 0;
540             unsigned mask = 0x80;
541             for (int i = 0; i < bitCount; i++) {
542                 byte |= (src[i]) & mask;
543                 mask >>= 1;
544             }
545             dst[byteCount] = byte;
546         }
547         src += bitCount;
548         dst += dstRB;
549     }
550 }
551
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);
557
558     for (U16CPU y = 0; y < glyph.fHeight; y++) {
559         for (U16CPU i = 0; i < width; i++) {
560             U8CPU r = *(src++);
561             U8CPU g = *(src++);
562             U8CPU b = *(src++);
563             dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
564         }
565         dst = (uint8_t*)((char*)dst + dstRB);
566     }
567 }
568
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);
575
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);
582         }
583         dst = (uint16_t*)((char*)dst + dstRB);
584     }
585 }
586
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);
593
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);
600         }
601         dst = (SkPMColor*)((char*)dst + dstRB);
602     }
603 }
604
605 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
606     int sizeNeeded = glyph.fWidth * glyph.fHeight;
607     if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) {
608         sizeNeeded *= 3;
609     }
610     if (sizeNeeded > fBits.count()) {
611         fBits.setCount(sizeNeeded);
612     }
613
614     // erase
615     memset(fBits.begin(), 0, sizeNeeded);
616
617     fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
618     fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
619
620     FLOAT advance = 0.0f;
621
622     UINT16 index = glyph.getGlyphID();
623
624     DWRITE_GLYPH_OFFSET offset;
625     offset.advanceOffset = 0.0f;
626     offset.ascenderOffset = 0.0f;
627
628     DWRITE_GLYPH_RUN run;
629     run.glyphCount = 1;
630     run.glyphAdvances = &advance;
631     run.fontFace = fTypeface->fDWriteFontFace.get();
632     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
633     run.bidiLevel = 0;
634     run.glyphIndices = &index;
635     run.isSideways = FALSE;
636     run.glyphOffsets = &offset;
637
638     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
639     HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
640                                           1.0f, // pixelsPerDip,
641                                           &fXform,
642                                           fRenderingMode,
643                                           fMeasuringMode,
644                                           0.0f, // baselineOriginX,
645                                           0.0f, // baselineOriginY,
646                                           &glyphRunAnalysis),
647          "Could not create glyph run analysis.");
648
649     //NOTE: this assumes that the glyph has already been measured
650     //with an exact same glyph run analysis.
651     RECT bbox;
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,
657                                               &bbox,
658                                               fBits.begin(),
659                                               sizeNeeded),
660          "Could not draw mask.");
661     return fBits.begin();
662 }
663
664 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
665     //Create the mask.
666     const void* bits = this->drawDWMask(glyph);
667     if (!bits) {
668         sk_bzero(glyph.fImage, glyph.computeImageSize());
669         return;
670     }
671
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);
680         } else {
681             rgb_to_a8<false>(src, glyph, fPreBlend.fG);
682         }
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);
686         } else {
687             rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
688         }
689     } else {
690         SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
691         if (fPreBlend.isApplicable()) {
692             rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
693         } else {
694             rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
695         }
696     }
697 }
698
699 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
700     SkASSERT(&glyph && path);
701
702     path->reset();
703
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),
711                                        &glyphId,
712                                        NULL, //advances
713                                        NULL, //offsets
714                                        1, //num glyphs
715                                        FALSE, //sideways
716                                        FALSE, //rtl
717                                        geometryToPath.get()),
718          "Could not create glyph outline.");
719
720     path->transform(fSkXform);
721 }