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
33static bool isLCD(const SkScalerContext::Rec& rec) {
34    return SkMask::kLCD16_Format == rec.fMaskFormat ||
35           SkMask::kLCD32_Format == rec.fMaskFormat;
36}
37
38static 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]. */
60struct 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 */
68static 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
107static 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
181static 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
186static 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
192SkScalerContext_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
336SkScalerContext_DW::~SkScalerContext_DW() {
337}
338
339unsigned SkScalerContext_DW::generateGlyphCount() {
340    if (fGlyphCount < 0) {
341        fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
342    }
343    return fGlyphCount;
344}
345
346uint16_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
352void 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
403HRESULT 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 */
453static 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
464void 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
497void 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
567static 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
605template<bool APPLY_PREBLEND>
606static 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
622template<bool APPLY_PREBLEND>
623static 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
640template<bool APPLY_PREBLEND>
641static 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
658const 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
720void 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
761void 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}
784