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 #include <dwrite_1.h>
     30 
     31 static bool isLCD(const SkScalerContext::Rec& rec) {
     32     return SkMask::kLCD16_Format == rec.fMaskFormat ||
     33            SkMask::kLCD32_Format == rec.fMaskFormat;
     34 }
     35 
     36 static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) {
     37     AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
     38     if (!maxp.fExists) {
     39         return false;
     40     }
     41     if (maxp.fSize < sizeof(SkOTTableMaximumProfile::Version::TT)) {
     42         return false;
     43     }
     44     if (maxp->version.version != SkOTTableMaximumProfile::Version::TT::VERSION) {
     45         return false;
     46     }
     47 
     48     if (0 == maxp->version.tt.maxSizeOfInstructions) {
     49         // No hints.
     50         return false;
     51     }
     52 
     53     AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
     54     return !gasp.fExists;
     55 }
     56 
     57 /** A PPEMRange is inclusive, [min, max]. */
     58 struct PPEMRange {
     59     int min;
     60     int max;
     61 };
     62 
     63 /** If the rendering mode for the specified 'size' is gridfit, then place
     64  *  the gridfit range into 'range'. Otherwise, leave 'range' alone.
     65  */
     66 static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, PPEMRange* range) {
     67     AutoTDWriteTable<SkOTTableGridAndScanProcedure> gasp(typeface->fDWriteFontFace.get());
     68     if (!gasp.fExists) {
     69         return;
     70     }
     71     if (gasp.fSize < sizeof(SkOTTableGridAndScanProcedure)) {
     72         return;
     73     }
     74     if (gasp->version != SkOTTableGridAndScanProcedure::version0 &&
     75         gasp->version != SkOTTableGridAndScanProcedure::version1)
     76     {
     77         return ;
     78     }
     79 
     80     uint16_t numRanges = SkEndianSwap16(gasp->numRanges);
     81     if (numRanges > 1024 ||
     82         gasp.fSize < sizeof(SkOTTableGridAndScanProcedure) +
     83                      sizeof(SkOTTableGridAndScanProcedure::GaspRange) * numRanges)
     84     {
     85         return;
     86     }
     87 
     88     const SkOTTableGridAndScanProcedure::GaspRange* rangeTable =
     89             SkTAfter<const SkOTTableGridAndScanProcedure::GaspRange>(gasp.get());
     90     int minPPEM = -1;
     91     for (uint16_t i = 0; i < numRanges; ++i, ++rangeTable) {
     92         int maxPPEM = SkEndianSwap16(rangeTable->maxPPEM);
     93         // Test that the size is in range and the range is gridfit only.
     94         if (minPPEM < size && size <= maxPPEM &&
     95             rangeTable->flags.raw.value == SkOTTableGridAndScanProcedure::GaspRange::behavior::Raw::GridfitMask)
     96         {
     97             range->min = minPPEM + 1;
     98             range->max = maxPPEM;
     99             return;
    100         }
    101         minPPEM = maxPPEM;
    102     }
    103 
    104     return;
    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 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
    404     glyph->fWidth = 0;
    405 
    406     this->generateAdvance(glyph);
    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     HRVM(fTypeface->fFactory->CreateGlyphRunAnalysis(
    432              &run,
    433              1.0f, // pixelsPerDip,
    434              &fXform,
    435              fRenderingMode,
    436              fMeasuringMode,
    437              0.0f, // baselineOriginX,
    438              0.0f, // baselineOriginY,
    439              &glyphRunAnalysis),
    440          "Could not create glyph run analysis.");
    441 
    442     RECT bbox;
    443     HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox),
    444          "Could not get texture bounds.");
    445 
    446     glyph->fWidth = SkToU16(bbox.right - bbox.left);
    447     glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
    448     glyph->fLeft = SkToS16(bbox.left);
    449     glyph->fTop = SkToS16(bbox.top);
    450 }
    451 
    452 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx,
    453                                              SkPaint::FontMetrics* my) {
    454     if (!(mx || my))
    455       return;
    456 
    457     if (mx) {
    458         sk_bzero(mx, sizeof(*mx));
    459     }
    460     if (my) {
    461         sk_bzero(my, sizeof(*my));
    462     }
    463 
    464     DWRITE_FONT_METRICS dwfm;
    465     if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
    466         DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
    467     {
    468         fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
    469              fTextSizeRender,
    470              1.0f, // pixelsPerDip
    471              &fXform,
    472              &dwfm);
    473     } else {
    474         fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
    475     }
    476 
    477     SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
    478     if (mx) {
    479         mx->fTop = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
    480         mx->fAscent = mx->fTop;
    481         mx->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
    482         mx->fBottom = mx->fDescent;
    483         mx->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
    484         mx->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
    485         mx->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
    486         mx->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
    487 
    488         mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
    489         mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
    490     }
    491 
    492     if (my) {
    493         my->fAscent = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
    494         my->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
    495         my->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
    496         my->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
    497         my->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
    498         my->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
    499 
    500         my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
    501         my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
    502 
    503         if (NULL != fTypeface->fDWriteFontFace1.get()) {
    504             DWRITE_FONT_METRICS1 dwfm1;
    505             fTypeface->fDWriteFontFace1->GetMetrics(&dwfm1);
    506             my->fTop = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxTop) / upem;
    507             my->fBottom = -fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxBottom) / upem;
    508             my->fXMin = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxLeft) / upem;
    509             my->fXMax = fTextSizeRender * SkIntToScalar(dwfm1.glyphBoxRight) / upem;
    510 
    511             my->fMaxCharWidth = my->fXMax - my->fXMin;
    512         } else {
    513             AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get());
    514             if (head.fExists &&
    515                 head.fSize >= sizeof(SkOTTableHead) &&
    516                 head->version == SkOTTableHead::version1)
    517             {
    518                 my->fTop = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMax) / upem;
    519                 my->fBottom = -fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->yMin) / upem;
    520                 my->fXMin = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMin) / upem;
    521                 my->fXMax = fTextSizeRender * (int16_t)SkEndian_SwapBE16(head->xMax) / upem;
    522 
    523                 my->fMaxCharWidth = my->fXMax - my->fXMin;
    524             } else {
    525                 my->fTop = my->fAscent;
    526                 my->fBottom = my->fDescent;
    527             }
    528         }
    529     }
    530 }
    531 
    532 ///////////////////////////////////////////////////////////////////////////////
    533 
    534 #include "SkColorPriv.h"
    535 
    536 static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
    537     const int width = glyph.fWidth;
    538     const size_t dstRB = (width + 7) >> 3;
    539     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
    540 
    541     int byteCount = width >> 3;
    542     int bitCount = width & 7;
    543 
    544     for (int y = 0; y < glyph.fHeight; ++y) {
    545         if (byteCount > 0) {
    546             for (int i = 0; i < byteCount; ++i) {
    547                 unsigned byte = 0;
    548                 byte |= src[0] & (1 << 7);
    549                 byte |= src[1] & (1 << 6);
    550                 byte |= src[2] & (1 << 5);
    551                 byte |= src[3] & (1 << 4);
    552                 byte |= src[4] & (1 << 3);
    553                 byte |= src[5] & (1 << 2);
    554                 byte |= src[6] & (1 << 1);
    555                 byte |= src[7] & (1 << 0);
    556                 dst[i] = byte;
    557                 src += 8;
    558             }
    559         }
    560         if (bitCount > 0) {
    561             unsigned byte = 0;
    562             unsigned mask = 0x80;
    563             for (int i = 0; i < bitCount; i++) {
    564                 byte |= (src[i]) & mask;
    565                 mask >>= 1;
    566             }
    567             dst[byteCount] = byte;
    568         }
    569         src += bitCount;
    570         dst += dstRB;
    571     }
    572 }
    573 
    574 template<bool APPLY_PREBLEND>
    575 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
    576     const size_t dstRB = glyph.rowBytes();
    577     const U16CPU width = glyph.fWidth;
    578     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
    579 
    580     for (U16CPU y = 0; y < glyph.fHeight; y++) {
    581         for (U16CPU i = 0; i < width; i++) {
    582             U8CPU r = *(src++);
    583             U8CPU g = *(src++);
    584             U8CPU b = *(src++);
    585             dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
    586         }
    587         dst = (uint8_t*)((char*)dst + dstRB);
    588     }
    589 }
    590 
    591 template<bool APPLY_PREBLEND>
    592 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
    593                          const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
    594     const size_t dstRB = glyph.rowBytes();
    595     const U16CPU width = glyph.fWidth;
    596     uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
    597 
    598     for (U16CPU y = 0; y < glyph.fHeight; y++) {
    599         for (U16CPU i = 0; i < width; i++) {
    600             U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
    601             U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
    602             U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
    603             dst[i] = SkPack888ToRGB16(r, g, b);
    604         }
    605         dst = (uint16_t*)((char*)dst + dstRB);
    606     }
    607 }
    608 
    609 template<bool APPLY_PREBLEND>
    610 static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
    611                          const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
    612     const size_t dstRB = glyph.rowBytes();
    613     const U16CPU width = glyph.fWidth;
    614     SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage);
    615 
    616     for (U16CPU y = 0; y < glyph.fHeight; y++) {
    617         for (U16CPU i = 0; i < width; i++) {
    618             U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
    619             U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
    620             U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
    621             dst[i] = SkPackARGB32(0xFF, r, g, b);
    622         }
    623         dst = (SkPMColor*)((char*)dst + dstRB);
    624     }
    625 }
    626 
    627 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
    628     int sizeNeeded = glyph.fWidth * glyph.fHeight;
    629     if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) {
    630         sizeNeeded *= 3;
    631     }
    632     if (sizeNeeded > fBits.count()) {
    633         fBits.setCount(sizeNeeded);
    634     }
    635 
    636     // erase
    637     memset(fBits.begin(), 0, sizeNeeded);
    638 
    639     fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
    640     fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
    641 
    642     FLOAT advance = 0.0f;
    643 
    644     UINT16 index = glyph.getGlyphID();
    645 
    646     DWRITE_GLYPH_OFFSET offset;
    647     offset.advanceOffset = 0.0f;
    648     offset.ascenderOffset = 0.0f;
    649 
    650     DWRITE_GLYPH_RUN run;
    651     run.glyphCount = 1;
    652     run.glyphAdvances = &advance;
    653     run.fontFace = fTypeface->fDWriteFontFace.get();
    654     run.fontEmSize = SkScalarToFloat(fTextSizeRender);
    655     run.bidiLevel = 0;
    656     run.glyphIndices = &index;
    657     run.isSideways = FALSE;
    658     run.glyphOffsets = &offset;
    659 
    660     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
    661     HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
    662                                           1.0f, // pixelsPerDip,
    663                                           &fXform,
    664                                           fRenderingMode,
    665                                           fMeasuringMode,
    666                                           0.0f, // baselineOriginX,
    667                                           0.0f, // baselineOriginY,
    668                                           &glyphRunAnalysis),
    669          "Could not create glyph run analysis.");
    670 
    671     //NOTE: this assumes that the glyph has already been measured
    672     //with an exact same glyph run analysis.
    673     RECT bbox;
    674     bbox.left = glyph.fLeft;
    675     bbox.top = glyph.fTop;
    676     bbox.right = glyph.fLeft + glyph.fWidth;
    677     bbox.bottom = glyph.fTop + glyph.fHeight;
    678     HRNM(glyphRunAnalysis->CreateAlphaTexture(fTextureType,
    679                                               &bbox,
    680                                               fBits.begin(),
    681                                               sizeNeeded),
    682          "Could not draw mask.");
    683     return fBits.begin();
    684 }
    685 
    686 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
    687     //Create the mask.
    688     const void* bits = this->drawDWMask(glyph);
    689     if (!bits) {
    690         sk_bzero(glyph.fImage, glyph.computeImageSize());
    691         return;
    692     }
    693 
    694     //Copy the mask into the glyph.
    695     const uint8_t* src = (const uint8_t*)bits;
    696     if (DWRITE_RENDERING_MODE_ALIASED == fRenderingMode) {
    697         bilevel_to_bw(src, glyph);
    698         const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
    699     } else if (!isLCD(fRec)) {
    700         if (fPreBlend.isApplicable()) {
    701             rgb_to_a8<true>(src, glyph, fPreBlend.fG);
    702         } else {
    703             rgb_to_a8<false>(src, glyph, fPreBlend.fG);
    704         }
    705     } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
    706         if (fPreBlend.isApplicable()) {
    707             rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
    708         } else {
    709             rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
    710         }
    711     } else {
    712         SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
    713         if (fPreBlend.isApplicable()) {
    714             rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
    715         } else {
    716             rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
    717         }
    718     }
    719 }
    720 
    721 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
    722     SkASSERT(&glyph && path);
    723 
    724     path->reset();
    725 
    726     SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
    727     HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
    728          "Could not create geometry to path converter.");
    729     uint16_t glyphId = glyph.getGlyphID();
    730     //TODO: convert to<->from DIUs? This would make a difference if hinting.
    731     //It may not be needed, it appears that DirectWrite only hints at em size.
    732     HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender),
    733                                        &glyphId,
    734                                        NULL, //advances
    735                                        NULL, //offsets
    736                                        1, //num glyphs
    737                                        FALSE, //sideways
    738                                        FALSE, //rtl
    739                                        geometryToPath.get()),
    740          "Could not create glyph outline.");
    741 
    742     path->transform(fSkXform);
    743 }
    744