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