diff options
author | 2014-04-09 15:35:03 +0000 | |
---|---|---|
committer | 2014-04-09 15:35:03 +0000 | |
commit | d715aaa33fc52d36f566caf941787a2cca24d85b (patch) | |
tree | 06b16b90c8e87981cc5592aa3b3f6db89a88f842 /src | |
parent | cb1926cc7a3dbbffca267da07ddb3eaa6789d5d5 (diff) |
Measure DirectWrite BW consistently with rendering.
Also move DirectWrite glyph drawing into the scaler context, as this
reduces duplication.
R=reed@google.com
Review URL: https://codereview.chromium.org/225283021
git-svn-id: http://skia.googlecode.com/svn/trunk@14106 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r-- | src/ports/SkFontHost_win_dw.cpp | 241 |
1 files changed, 114 insertions, 127 deletions
diff --git a/src/ports/SkFontHost_win_dw.cpp b/src/ports/SkFontHost_win_dw.cpp index 199aff5049..36ed4d4f06 100644 --- a/src/ports/SkFontHost_win_dw.cpp +++ b/src/ports/SkFontHost_win_dw.cpp @@ -123,104 +123,6 @@ private: /////////////////////////////////////////////////////////////////////////////// -class DWriteOffscreen { -public: - DWriteOffscreen() : fWidth(0), fHeight(0) { } - - void init(IDWriteFactory* factory, IDWriteFontFace* fontFace, - const DWRITE_MATRIX& xform, FLOAT fontSize) - { - fFactory = factory; - fFontFace = fontFace; - fFontSize = fontSize; - fXform = xform; - } - - const void* draw(const SkGlyph&, bool isBW); - -private: - uint16_t fWidth; - uint16_t fHeight; - IDWriteFactory* fFactory; - IDWriteFontFace* fFontFace; - FLOAT fFontSize; - DWRITE_MATRIX fXform; - SkTDArray<uint8_t> fBits; -}; - -const void* DWriteOffscreen::draw(const SkGlyph& glyph, bool isBW) { - if (fWidth < glyph.fWidth || fHeight < glyph.fHeight) { - fWidth = SkMax32(fWidth, glyph.fWidth); - fHeight = SkMax32(fHeight, glyph.fHeight); - - if (isBW) { - fBits.setCount(fWidth * fHeight); - } else { - fBits.setCount(fWidth * fHeight * 3); - } - } - - // erase - memset(fBits.begin(), 0, fBits.count()); - - fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); - fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); - - FLOAT advance = 0.0f; - - UINT16 index = glyph.getGlyphID(); - - DWRITE_GLYPH_OFFSET offset; - offset.advanceOffset = 0.0f; - offset.ascenderOffset = 0.0f; - - DWRITE_GLYPH_RUN run; - run.glyphCount = 1; - run.glyphAdvances = &advance; - run.fontFace = fFontFace; - run.fontEmSize = fFontSize; - run.bidiLevel = 0; - run.glyphIndices = &index; - run.isSideways = FALSE; - run.glyphOffsets = &offset; - - DWRITE_RENDERING_MODE renderingMode; - DWRITE_TEXTURE_TYPE textureType; - if (isBW) { - renderingMode = DWRITE_RENDERING_MODE_ALIASED; - textureType = DWRITE_TEXTURE_ALIASED_1x1; - } else { - renderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; - textureType = DWRITE_TEXTURE_CLEARTYPE_3x1; - } - SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; - HRNM(fFactory->CreateGlyphRunAnalysis(&run, - 1.0f, // pixelsPerDip, - &fXform, - renderingMode, - DWRITE_MEASURING_MODE_NATURAL, - 0.0f, // baselineOriginX, - 0.0f, // baselineOriginY, - &glyphRunAnalysis), - "Could not create glyph run analysis."); - - //NOTE: this assumes that the glyph has already been measured - //with an exact same glyph run analysis. - RECT bbox; - bbox.left = glyph.fLeft; - bbox.top = glyph.fTop; - bbox.right = glyph.fLeft + glyph.fWidth; - bbox.bottom = glyph.fTop + glyph.fHeight; - HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, - &bbox, - fBits.begin(), - fBits.count()), - "Could not draw mask."); - return fBits.begin(); -} - -/////////////////////////////////////////////////////////////////////////////// - class StreamFontFileLoader : public IDWriteFontFileLoader { public: // IUnknown methods @@ -544,10 +446,15 @@ protected: SkPaint::FontMetrics* mY) SK_OVERRIDE; private: - DWriteOffscreen fOffscreen; + const void* drawDWMask(const SkGlyph& glyph); + + SkTDArray<uint8_t> fBits; DWRITE_MATRIX fXform; SkAutoTUnref<DWriteFontTypeface> fTypeface; int fGlyphCount; + DWRITE_RENDERING_MODE fRenderingMode; + DWRITE_TEXTURE_TYPE fTextureType; + DWRITE_MEASURING_MODE fMeasuringMode; }; static bool are_same(IUnknown* a, IUnknown* b) { @@ -676,8 +583,19 @@ SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, fXform.dx = 0; fXform.dy = 0; - fOffscreen.init(fTypeface->fFactory.get(), fTypeface->fDWriteFontFace.get(), - fXform, SkScalarToFloat(fRec.fTextSize)); + if (SkMask::kBW_Format == fRec.fMaskFormat) { + fRenderingMode = DWRITE_RENDERING_MODE_ALIASED; + fTextureType = DWRITE_TEXTURE_ALIASED_1x1; + fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; + } else { + fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; + fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; + fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; + } + + if (this->isSubpixel()) { + fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; + } } SkScalerContext_DW::~SkScalerContext_DW() { @@ -708,17 +626,30 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { uint16_t glyphId = glyph->getGlyphID(); DWRITE_GLYPH_METRICS gm; - HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), - "Could not get design metrics."); + + if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || + DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) + { + HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( + fRec.fTextSize, + 1.0f, // pixelsPerDip + &fXform, + DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode, + &glyphId, 1, + &gm), + "Could not get gdi compatible glyph metrics."); + } else { + HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), + "Could not get design metrics."); + } DWRITE_FONT_METRICS dwfm; fTypeface->fDWriteFontFace->GetMetrics(&dwfm); - SkScalar advanceX = SkScalarMulDiv(fRec.fTextSize, SkIntToScalar(gm.advanceWidth), SkIntToScalar(dwfm.designUnitsPerEm)); - if (!(fRec.fFlags & kSubpixelPositioning_Flag)) { + if (!this->isSubpixel()) { advanceX = SkScalarRoundToScalar(advanceX); } @@ -758,31 +689,20 @@ void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { run.isSideways = FALSE; run.glyphOffsets = &offset; - const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; - DWRITE_RENDERING_MODE renderingMode; - DWRITE_TEXTURE_TYPE textureType; - if (isBW) { - renderingMode = DWRITE_RENDERING_MODE_ALIASED; - textureType = DWRITE_TEXTURE_ALIASED_1x1; - } else { - renderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; - textureType = DWRITE_TEXTURE_CLEARTYPE_3x1; - } - SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; HRVM(fTypeface->fFactory->CreateGlyphRunAnalysis( &run, 1.0f, // pixelsPerDip, &fXform, - renderingMode, - DWRITE_MEASURING_MODE_NATURAL, + fRenderingMode, + fMeasuringMode, 0.0f, // baselineOriginX, 0.0f, // baselineOriginY, &glyphRunAnalysis), "Could not create glyph run analysis."); RECT bbox; - HRVM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, &bbox), + HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox), "Could not get texture bounds."); glyph->fWidth = SkToU16(bbox.right - bbox.left); @@ -792,7 +712,7 @@ void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { } void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx, - SkPaint::FontMetrics* my) { + SkPaint::FontMetrics* my) { if (!(mx || my)) return; @@ -804,7 +724,17 @@ void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx, } DWRITE_FONT_METRICS dwfm; - fTypeface->fDWriteFontFace->GetMetrics(&dwfm); + if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || + DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) + { + fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics( + fRec.fTextSize, + 1.0f, // pixelsPerDip + &fXform, + &dwfm); + } else { + fTypeface->fDWriteFontFace->GetMetrics(&dwfm); + } SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm); if (mx) { @@ -931,12 +861,68 @@ static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, } } -void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { - const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; - const bool isAA = !isLCD(fRec); +const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) { + int sizeNeeded = glyph.fWidth * glyph.fHeight; + if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) { + sizeNeeded *= 3; + } + if (sizeNeeded > fBits.count()) { + fBits.setCount(sizeNeeded); + } + + // erase + memset(fBits.begin(), 0, sizeNeeded); + + fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); + fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); + + FLOAT advance = 0.0f; + + UINT16 index = glyph.getGlyphID(); + + DWRITE_GLYPH_OFFSET offset; + offset.advanceOffset = 0.0f; + offset.ascenderOffset = 0.0f; + DWRITE_GLYPH_RUN run; + run.glyphCount = 1; + run.glyphAdvances = &advance; + run.fontFace = fTypeface->fDWriteFontFace.get(); + run.fontEmSize = SkScalarToFloat(fRec.fTextSize); + run.bidiLevel = 0; + run.glyphIndices = &index; + run.isSideways = FALSE; + run.glyphOffsets = &offset; + + SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; + HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, + 1.0f, // pixelsPerDip, + &fXform, + fRenderingMode, + fMeasuringMode, + 0.0f, // baselineOriginX, + 0.0f, // baselineOriginY, + &glyphRunAnalysis), + "Could not create glyph run analysis."); + + //NOTE: this assumes that the glyph has already been measured + //with an exact same glyph run analysis. + RECT bbox; + bbox.left = glyph.fLeft; + bbox.top = glyph.fTop; + bbox.right = glyph.fLeft + glyph.fWidth; + bbox.bottom = glyph.fTop + glyph.fHeight; + HRNM(glyphRunAnalysis->CreateAlphaTexture(fTextureType, + &bbox, + fBits.begin(), + sizeNeeded), + "Could not draw mask."); + return fBits.begin(); +} + +void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { //Create the mask. - const void* bits = fOffscreen.draw(glyph, isBW); + const void* bits = this->drawDWMask(glyph); if (!bits) { sk_bzero(glyph.fImage, glyph.computeImageSize()); return; @@ -944,9 +930,10 @@ void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { //Copy the mask into the glyph. const uint8_t* src = (const uint8_t*)bits; - if (isBW) { + if (DWRITE_RENDERING_MODE_ALIASED == fRenderingMode) { bilevel_to_bw(src, glyph); - } else if (isAA) { + const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format; + } else if (!isLCD(fRec)) { if (fPreBlend.isApplicable()) { rgb_to_a8<true>(src, glyph, fPreBlend.fG); } else { |