Home | History | Annotate | Download | only in ports
      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 }
    784