Upstream version 10.39.225.0
[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 #if SK_HAS_DWRITE_1_H
30 #  include <dwrite_1.h>
31 #endif
32
33 static bool isLCD(const SkScalerContext::Rec& rec) {
34     return SkMask::kLCD16_Format == rec.fMaskFormat ||
35            SkMask::kLCD32_Format == rec.fMaskFormat;
36 }
37
38 static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) {
39     AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
40     if (!maxp.fExists) {
41         return false;
42     }
43     if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
44         return false;
45     }
46     if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
47         return false;
48     }
49
50     if (0 == maxp->version.tt.maxSizeOfInstructions) {
51         // No hints.
52         return false;
53     }
54
55     AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
56     return !gasp.fExists;
57 }
58
59 /** A PPEMRange is inclusive, [min, max]. */
60 struct PPEMRange {
61     int min;
62     int max;
63 };
64
65 /** If the rendering mode for the specified 'size' is gridfit, then place
66  *  the gridfit range into 'range'. Otherwise, leave 'range' alone.
67  */
68 static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) {
69     AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
70     if (!gasp.fExists) {
71         return;
72     }
73     if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
74         return;
75     }
76     if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
77         gasp->version != SkOTTableGridAndScanProcedure::version1)
78     {
79         return;
80     }
81
82     uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
83     if (numRanges > 1024 ||
84         gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
85                      sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
86     {
87         return;
88     }
89
90     const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
91             SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
92     int minPPEM = -1;
93     for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) {
94         int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM);
95         // Test that the size is in range and the range is gridfit only.
96         if (minPPEM < size && size <= maxPPEM &&
97             rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask)
98         {
99             range->min = minPPEM + 1;
100             range->max = maxPPEM;
101             return;
102         }
103         minPPEM = maxPPEM;
104     }
105 }
106
107 static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) {
108     {
109         AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
110         if (!eblc.fExists) {
111             return false;
112         }
113         if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
114             return false;
115         }
116         if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
117             return false;
118         }
119
120         uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
121         if (numSizes > 1024 ||
122             eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
123                          sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
124         {
125             return false;
126         }
127
128         const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
129                 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
130         for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
131             if (sizeTable->ppemX == sizeTable->ppemY &&
132                 range.min <= sizeTable->ppemX && sizeTable->ppemX <= range.max)
133             {
134                 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
135                 // to determine the actual number of glyphs with bitmaps.
136
137                 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
138
139                 // TODO: Ensure that the bitmaps are bi-level?
140                 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
141                     return true;
142                 }
143             }
144         }
145     }
146
147     {
148         AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
149         if (!ebsc.fExists) {
150             return false;
151         }
152         if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
153             return false;
154         }
155         if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
156             return false;
157         }
158
159         uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
160         if (numSizes > 1024 ||
161             ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
162                          sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
163         {
164             return false;
165         }
166
167         const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
168                 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
169         for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
170             if (scaleTable->ppemX == scaleTable->ppemY &&
171                 range.min <= scaleTable->ppemX && scaleTable->ppemX <= range.max) {
172                 // EBSC tables are normally only found in bitmap only fonts.
173                 return true;
174             }
175         }
176     }
177
178     return false;
179 }
180
181 static bool both_zero(SkScalar a, SkScalar b) {
182     return 0 == a && 0 == b;
183 }
184
185 // returns false if there is any non-90-rotation or skew
186 static bool is_axis_aligned(const SkScalerContext::Rec& rec) {
187     return 0 == rec.fPreSkewX &&
188            (both_zero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
189             both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
190 }
191
192 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
193                                        const SkDescriptor* desc)
194         : SkScalerContext(typeface, desc)
195         , fTypeface(SkRef(typeface))
196         , fGlyphCount(-1) {
197
198     // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC
199     // except when bi-level rendering is requested or there are embedded
200     // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
201     //
202     // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
203     // this. As a result, determine the actual size of the text and then see if
204     // there are any embedded bi-level bitmaps of that size. If there are, then
205     // force bitmaps by requesting bi-level rendering.
206     //
207     // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
208     // square pixels and only uses ppemY. Therefore the transform must track any
209     // non-uniform x-scale.
210     //
211     // Also, rotated glyphs should have the same absolute advance widths as
212     // horizontal glyphs and the subpixel flag should not affect glyph shapes.
213
214     // A is the total matrix.
215     SkMatrix A;
216     fRec.getSingleMatrix(&A);
217
218     // h is where A maps the horizontal baseline.
219     SkPoint h = SkPoint::Make(SK_Scalar1, 0);
220     A.mapPoints(&h, 1);
221
222     // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
223     SkMatrix G;
224     SkComputeGivensRotation(h, &G);
225
226     // GA is the matrix A with rotation removed.
227     SkMatrix GA(G);
228     GA.preConcat(A);
229
230     // realTextSize is the actual device size we want (as opposed to the size the user requested).
231     // gdiTextSize is the size we request when GDI compatible.
232     // If the scale is negative, this means the matrix will do the flip anyway.
233     SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
234     // Due to floating point math, the lower bits are suspect. Round carefully.
235     SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
236     if (gdiTextSize == 0) {
237         gdiTextSize = SK_Scalar1;
238     }
239
240     bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag);
241     bool treatLikeBitmap = false;
242     bool axisAlignedBitmap = false;
243     if (bitmapRequested) {
244         // When embedded bitmaps are requested, treat the entire range like
245         // a bitmap strike if the range is gridfit only and contains a bitmap.
246         int bitmapPPEM = SkScalarTruncToInt(gdiTextSize);
247         PPEMRange range = { bitmapPPEM, bitmapPPEM };
248         expand_range_if_gridfit_only(typeface, bitmapPPEM, &range);
249         treatLikeBitmap = has_bitmap_strike(typeface, range);
250
251         axisAlignedBitmap = is_axis_aligned(fRec);
252     }
253
254     // If the user requested aliased, do so with aliased compatible metrics.
255     if (SkMask::kBW_Format == fRec.fMaskFormat) {
256         fTextSizeRender = gdiTextSize;
257         fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
258         fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
259         fTextSizeMeasure = gdiTextSize;
260         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
261
262     // If we can use a bitmap, use gdi classic rendering and measurement.
263     // This will not always provide a bitmap, but matches expected behavior.
264     } else if (treatLikeBitmap && axisAlignedBitmap) {
265         fTextSizeRender = gdiTextSize;
266         fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
267         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
268         fTextSizeMeasure = gdiTextSize;
269         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
270
271     // If rotated but the horizontal text could have used a bitmap,
272     // render high quality rotated glyphs but measure using bitmap metrics.
273     } else if (treatLikeBitmap) {
274         fTextSizeRender = gdiTextSize;
275         fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
276         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
277         fTextSizeMeasure = gdiTextSize;
278         fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
279
280     // Fonts that have hints but no gasp table get non-symmetric rendering.
281     // Usually such fonts have low quality hints which were never tested
282     // with anything but GDI ClearType classic. Such fonts often rely on
283     // drop out control in the y direction in order to be legible.
284     } else if (is_hinted_without_gasp(typeface)) {
285         fTextSizeRender = gdiTextSize;
286         fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
287         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
288         fTextSizeMeasure = realTextSize;
289         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
290
291     // The normal case is to use natural symmetric rendering and linear metrics.
292     } else {
293         fTextSizeRender = realTextSize;
294         fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
295         fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
296         fTextSizeMeasure = realTextSize;
297         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
298     }
299
300     if (this->isSubpixel()) {
301         fTextSizeMeasure = realTextSize;
302         fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
303     }
304
305     // Remove the realTextSize, as that is the text height scale currently in A.
306     SkScalar scale = SkScalarInvert(realTextSize);
307
308     // fSkXform is the total matrix A without the text height scale.
309     fSkXform = A;
310     fSkXform.preScale(scale, scale); //remove the text height scale.
311
312     fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
313     fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
314     fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
315     fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
316     fXform.dx = 0;
317     fXform.dy = 0;
318
319     // GsA is the non-rotational part of A without the text height scale.
320     SkMatrix GsA(GA);
321     GsA.preScale(scale, scale); //remove text height scale, G is rotational so reorders with scale.
322
323     fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX));
324     fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
325     fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX));
326     fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY));
327     fGsA.dx = 0;
328     fGsA.dy = 0;
329
330     // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
331     fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
332                   -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
333                   G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
334 }
335
336 SkScalerContext_DW::~SkScalerContext_DW() {
337 }
338
339 unsigned SkScalerContext_DW::generateGlyphCount() {
340     if (fGlyphCount < 0) {
341         fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
342     }
343     return fGlyphCount;
344 }
345
346 uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
347     uint16_t index = 0;
348     fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index);
349     return index;
350 }
351
352 void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
353     //Delta is the difference between the right/left side bearing metric
354     //and where the right/left side bearing ends up after hinting.
355     //DirectWrite does not provide this information.
356     glyph->fRsbDelta = 0;
357     glyph->fLsbDelta = 0;
358
359     glyph->fAdvanceX = 0;
360     glyph->fAdvanceY = 0;
361
362     uint16_t glyphId = glyph->getGlyphID();
363     DWRITE_GLYPH_METRICS gm;
364
365     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
366         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
367     {
368         HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
369                  fTextSizeMeasure,
370                  1.0f, // pixelsPerDip
371                  &fGsA,
372                  DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
373                  &glyphId, 1,
374                  &gm),
375              "Could not get gdi compatible glyph metrics.");
376     } else {
377         HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
378              "Could not get design metrics.");
379     }
380
381     DWRITE_FONT_METRICS dwfm;
382     fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
383     SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
384                                        SkIntToScalar(gm.advanceWidth),
385                                        SkIntToScalar(dwfm.designUnitsPerEm));
386
387     SkVector vecs[1] = { { advanceX, 0 } };
388     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
389         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
390     {
391         // DirectWrite produced 'compatible' metrics, but while close,
392         // the end result is not always an integer as it would be with GDI.
393         vecs[0].fX = SkScalarRoundToScalar(advanceX);
394         fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
395     } else {
396         fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
397     }
398
399     glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
400     glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
401 }
402
403 HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
404                                            DWRITE_RENDERING_MODE renderingMode,
405                                            DWRITE_TEXTURE_TYPE textureType,
406                                            RECT* bbox)
407 {
408     //Measure raster size.
409     fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
410     fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
411
412     FLOAT advance = 0;
413
414     UINT16 glyphId = glyph->getGlyphID();
415
416     DWRITE_GLYPH_OFFSET offset;
417     offset.advanceOffset = 0.0f;
418     offset.ascenderOffset = 0.0f;
419
420     DWRITE_GLYPH_RUN run;
421     run.glyphCount = 1;
422     run.glyphAdvances = &advance;
423     run.fontFace = fTypeface->fDWriteFontFace.get();
424     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
425     run.bidiLevel = 0;
426     run.glyphIndices = &glyphId;
427     run.isSideways = FALSE;
428     run.glyphOffsets = &offset;
429
430     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
431     HRM(fTypeface->fFactory->CreateGlyphRunAnalysis(
432             &run,
433             1.0f, // pixelsPerDip,
434             &fXform,
435             renderingMode,
436             fMeasuringMode,
437             0.0f, // baselineOriginX,
438             0.0f, // baselineOriginY,
439             &glyphRunAnalysis),
440         "Could not create glyph run analysis.");
441
442     HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
443         "Could not get texture bounds.");
444
445     return S_OK;
446 }
447
448 /** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
449  *  { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
450  *  for small, but not quite zero, sized glyphs.
451  *  Only set as non-empty if the returned bounds are non-empty.
452  */
453 static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) {
454     if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
455         return false;
456     }
457     glyph->fWidth = SkToU16(bbox.right - bbox.left);
458     glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
459     glyph->fLeft = SkToS16(bbox.left);
460     glyph->fTop = SkToS16(bbox.top);
461     return true;
462 }
463
464 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
465     glyph->fWidth = 0;
466     glyph->fHeight = 0;
467     glyph->fLeft = 0;
468     glyph->fTop = 0;
469
470     this->generateAdvance(glyph);
471
472     RECT bbox;
473     HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox),
474          "Requested bounding box could not be determined.");
475
476     if (glyph_check_and_set_bounds(glyph, bbox)) {
477         return;
478     }
479
480     // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
481     // glyphs of the specified texture type. When this happens, try with the
482     // alternate texture type.
483     if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) {
484         HRVM(this->getBoundingBox(glyph,
485                                   DWRITE_RENDERING_MODE_ALIASED,
486                                   DWRITE_TEXTURE_ALIASED_1x1,
487                                   &bbox),
488              "Fallback bounding box could not be determined.");
489         if (glyph_check_and_set_bounds(glyph, bbox)) {
490             glyph->fForceBW = 1;
491         }
492     }
493     // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
494     // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
495 }
496
497 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) {
498     if (NULL == metrics) {
499         return;
500     }
501
502     sk_bzero(metrics, sizeof(*metrics));
503
504     DWRITE_FONT_METRICS dwfm;
505     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
506         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
507     {
508         fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
509              fTextSizeRender,
510              1.0f, // pixelsPerDip
511              &fXform,
512              &dwfm);
513     } else {
514         fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
515     }
516
517     SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
518
519     metrics->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
520     metrics->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
521     metrics->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
522     metrics->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
523     metrics->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
524     metrics->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
525
526     metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
527     metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
528
529 #if SK_HAS_DWRITE_1_H
530     if (fTypeface->fDWriteFontFace1.get()) {
531         DWRITE_FONT_METRICS1 dwfm1;
532         fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1);
533         metrics->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
534         metrics->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
535         metrics->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
536         metrics->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
537
538         metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
539         return;
540     }
541 #else
542 #  pragma message("No dwrite_1.h is available, font metrics may be affected.")
543 #endif
544
545     AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get());
546     if (head.fExists &&
547         head.fSize >= sizeof(SkOTTableHead) &&
548         head->version == SkOTTableHead::version1)
549     {
550         metrics->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
551         metrics->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
552         metrics->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
553         metrics->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
554
555         metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
556         return;
557     }
558
559     metrics->fTop = metrics->fAscent;
560     metrics->fBottom = metrics->fDescent;
561 }
562
563 ///////////////////////////////////////////////////////////////////////////////
564
565 #include "SkColorPriv.h"
566
567 static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
568     const int width = glyph.fWidth;
569     const size_t dstRB = (width + 7) >> 3;
570     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
571
572     int byteCount = width >> 3;
573     int bitCount = width & 7;
574
575     for (int y = 0; y < glyph.fHeight; ++y) {
576         if (byteCount > 0) {
577             for (int i = 0; i < byteCount; ++i) {
578                 unsigned byte = 0;
579                 byte |= src[0] & (1 << 7);
580                 byte |= src[1] & (1 << 6);
581                 byte |= src[2] & (1 << 5);
582                 byte |= src[3] & (1 << 4);
583                 byte |= src[4] & (1 << 3);
584                 byte |= src[5] & (1 << 2);
585                 byte |= src[6] & (1 << 1);
586                 byte |= src[7] & (1 << 0);
587                 dst[i] = byte;
588                 src += 8;
589             }
590         }
591         if (bitCount > 0) {
592             unsigned byte = 0;
593             unsigned mask = 0x80;
594             for (int i = 0; i < bitCount; i++) {
595                 byte |= (src[i]) & mask;
596                 mask >>= 1;
597             }
598             dst[byteCount] = byte;
599         }
600         src += bitCount;
601         dst += dstRB;
602     }
603 }
604
605 template<bool APPLY_PREBLEND>
606 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
607     const size_t dstRB = glyph.rowBytes();
608     const U16CPU width = glyph.fWidth;
609     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
610
611     for (U16CPU y = 0; y < glyph.fHeight; y++) {
612         for (U16CPU i = 0; i < width; i++) {
613             U8CPU r = *(src++);
614             U8CPU g = *(src++);
615             U8CPU b = *(src++);
616             dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
617         }
618         dst = (uint8_t*)((char*)dst + dstRB);
619     }
620 }
621
622 template<bool APPLY_PREBLEND>
623 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
624                          const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
625     const size_t dstRB = glyph.rowBytes();
626     const U16CPU width = glyph.fWidth;
627     uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
628
629     for (U16CPU y = 0; y < glyph.fHeight; y++) {
630         for (U16CPU i = 0; i < width; i++) {
631             U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
632             U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
633             U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
634             dst[i] = SkPack888ToRGB16(r, g, b);
635         }
636         dst = (uint16_t*)((char*)dst + dstRB);
637     }
638 }
639
640 template<bool APPLY_PREBLEND>
641 static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
642                          const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
643     const size_t dstRB = glyph.rowBytes();
644     const U16CPU width = glyph.fWidth;
645     SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage);
646
647     for (U16CPU y = 0; y < glyph.fHeight; y++) {
648         for (U16CPU i = 0; i < width; i++) {
649             U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
650             U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
651             U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
652             dst[i] = SkPackARGB32(0xFF, r, g, b);
653         }
654         dst = (SkPMColor*)((char*)dst + dstRB);
655     }
656 }
657
658 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
659                                            DWRITE_RENDERING_MODE renderingMode,
660                                            DWRITE_TEXTURE_TYPE textureType)
661 {
662     int sizeNeeded = glyph.fWidth * glyph.fHeight;
663     if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) {
664         sizeNeeded *= 3;
665     }
666     if (sizeNeeded > fBits.count()) {
667         fBits.setCount(sizeNeeded);
668     }
669
670     // erase
671     memset(fBits.begin(), 0, sizeNeeded);
672
673     fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
674     fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
675
676     FLOAT advance = 0.0f;
677
678     UINT16 index = glyph.getGlyphID();
679
680     DWRITE_GLYPH_OFFSET offset;
681     offset.advanceOffset = 0.0f;
682     offset.ascenderOffset = 0.0f;
683
684     DWRITE_GLYPH_RUN run;
685     run.glyphCount = 1;
686     run.glyphAdvances = &advance;
687     run.fontFace = fTypeface->fDWriteFontFace.get();
688     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
689     run.bidiLevel = 0;
690     run.glyphIndices = &index;
691     run.isSideways = FALSE;
692     run.glyphOffsets = &offset;
693
694     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
695     HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
696                                           1.0f, // pixelsPerDip,
697                                           &fXform,
698                                           renderingMode,
699                                           fMeasuringMode,
700                                           0.0f, // baselineOriginX,
701                                           0.0f, // baselineOriginY,
702                                           &glyphRunAnalysis),
703          "Could not create glyph run analysis.");
704
705     //NOTE: this assumes that the glyph has already been measured
706     //with an exact same glyph run analysis.
707     RECT bbox;
708     bbox.left = glyph.fLeft;
709     bbox.top = glyph.fTop;
710     bbox.right = glyph.fLeft + glyph.fWidth;
711     bbox.bottom = glyph.fTop + glyph.fHeight;
712     HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
713                                               &bbox,
714                                               fBits.begin(),
715                                               sizeNeeded),
716          "Could not draw mask.");
717     return fBits.begin();
718 }
719
720 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
721     //Create the mask.
722     DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
723     DWRITE_TEXTURE_TYPE textureType = fTextureType;
724     if (glyph.fForceBW) {
725         renderingMode = DWRITE_RENDERING_MODE_ALIASED;
726         textureType = DWRITE_TEXTURE_ALIASED_1x1;
727     }
728     const void* bits = this->drawDWMask(glyph, renderingMode, textureType);
729     if (!bits) {
730         sk_bzero(glyph.fImage, glyph.computeImageSize());
731         return;
732     }
733
734     //Copy the mask into the glyph.
735     const uint8_t* src = (const uint8_t*)bits;
736     if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
737         bilevel_to_bw(src, glyph);
738         const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
739     } else if (!isLCD(fRec)) {
740         if (fPreBlend.isApplicable()) {
741             rgb_to_a8<true>(src, glyph, fPreBlend.fG);
742         } else {
743             rgb_to_a8<false>(src, glyph, fPreBlend.fG);
744         }
745     } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
746         if (fPreBlend.isApplicable()) {
747             rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
748         } else {
749             rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
750         }
751     } else {
752         SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
753         if (fPreBlend.isApplicable()) {
754             rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
755         } else {
756             rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
757         }
758     }
759 }
760
761 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
762     SkASSERT(&glyph && path);
763
764     path->reset();
765
766     SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
767     HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
768          "Could not create geometry to path converter.");
769     uint16_t glyphId = glyph.getGlyphID();
770     //TODO: convert to<->from DIUs? This would make a difference if hinting.
771     //It may not be needed, it appears that DirectWrite only hints at em size.
772     HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender),
773                                        &glyphId,
774                                        NULL, //advances
775                                        NULL, //offsets
776                                        1, //num glyphs
777                                        FALSE, //sideways
778                                        FALSE, //rtl
779                                        geometryToPath.get()),
780          "Could not create glyph outline.");
781
782     path->transform(fSkXform);
783 }