| Index: src/ports/SkScalerContext_win_dw.cpp
|
| diff --git a/src/ports/SkScalerContext_win_dw.cpp b/src/ports/SkScalerContext_win_dw.cpp
|
| index c9ff5d86c35e2f8efd0eb5aec882631b0cd2fb13..5143943e22dfb0c9edfa05a8361355144394c742 100644
|
| --- a/src/ports/SkScalerContext_win_dw.cpp
|
| +++ b/src/ports/SkScalerContext_win_dw.cpp
|
| @@ -34,6 +34,14 @@
|
| #include <dwrite.h>
|
| #if SK_HAS_DWRITE_1_H
|
| # include <dwrite_1.h>
|
| +#else
|
| +# pragma message("No dwrite_1.h is available, font metrics may be affected.")
|
| +#endif
|
| +
|
| +#if SK_HAS_DWRITE_2_H
|
| +# include <dwrite_2.h>
|
| +#else
|
| +# pragma message("No dwrite_2.h is available, pixel antialiased glyph quality may be affected.")
|
| #endif
|
|
|
| /* Note:
|
| @@ -212,11 +220,9 @@ SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
|
| , fGlyphCount(-1) {
|
|
|
| #if SK_HAS_DWRITE_2_H
|
| - fTypeface->fFactory->QueryInterface<IDWriteFactory2>(&fFactory2);
|
| -
|
| - SkTScopedComPtr<IDWriteFontFace2> fontFace2;
|
| - fTypeface->fDWriteFontFace->QueryInterface<IDWriteFontFace2>(&fontFace2);
|
| - fIsColorFont = fFactory2.get() && fontFace2.get() && fontFace2->IsColorFont();
|
| + fIsColorFont = fTypeface->fFactory2 &&
|
| + fTypeface->fDWriteFontFace2 &&
|
| + fTypeface->fDWriteFontFace2->IsColorFont();
|
| #endif
|
|
|
| // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC
|
| @@ -324,6 +330,56 @@ SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
|
| fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
|
| }
|
|
|
| + // DirectWrite2 allows for grayscale hinting.
|
| +#if SK_HAS_DWRITE_2_H
|
| + fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
| +#ifndef SK_IGNORE_DW_GRAY_FIX
|
| + if (fTypeface->fFactory2 && fTypeface->fDWriteFontFace2 &&
|
| + !isLCD(fRec) && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag))
|
| + {
|
| + // DWRITE_TEXTURE_ALIASED_1x1 is now misnamed, it must also be used with grayscale.
|
| + fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
|
| + fAntiAliasMode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE;
|
| + }
|
| +#endif
|
| +#endif
|
| +
|
| + // DirectWrite2 allows hinting to be disabled.
|
| +#if SK_HAS_DWRITE_2_H
|
| + fGridFitMode = DWRITE_GRID_FIT_MODE_ENABLED;
|
| + if (fRec.getHinting() == SkPaint::kNo_Hinting) {
|
| + fGridFitMode = DWRITE_GRID_FIT_MODE_DISABLED;
|
| + } else if (fTypeface->fFactory2 && fTypeface->fDWriteFontFace2) {
|
| + [this]() {
|
| + SkTScopedComPtr<IDWriteRenderingParams2> renderingParams;
|
| + HRVM(fTypeface->fFactory2->CreateCustomRenderingParams(
|
| + 1.0, // gamma
|
| + 0.0, // enhancedContrast
|
| + 0.0, // grayscaleEnhancedContrast
|
| + 1.0, // clearTypeLevel
|
| + DWRITE_PIXEL_GEOMETRY_RGB,
|
| + fRenderingMode,
|
| + DWRITE_GRID_FIT_MODE_DEFAULT,
|
| + &renderingParams),
|
| + "Could not create custom rendering params.");
|
| + DWRITE_RENDERING_MODE ignoredRenderingMode;
|
| + HRVM(fTypeface->fDWriteFontFace2->GetRecommendedRenderingMode(
|
| + SkScalarToFloat(fTextSizeRender),
|
| + 1.0f, //dpiX
|
| + 1.0f, //dpiY
|
| + nullptr, //&fXform,
|
| + FALSE, //isSideways
|
| + fRec.fMaskFormat == SkMask::kBW_Format ? DWRITE_OUTLINE_THRESHOLD_ALIASED
|
| + : DWRITE_OUTLINE_THRESHOLD_ANTIALIASED,
|
| + fMeasuringMode,
|
| + renderingParams.get(),
|
| + &ignoredRenderingMode,
|
| + &fGridFitMode),
|
| + "Could not get reccomended grid fit mode.");
|
| + }();
|
| + }
|
| +#endif
|
| +
|
| if (this->isSubpixel()) {
|
| fTextSizeMeasure = realTextSize;
|
| fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
|
| @@ -432,16 +488,31 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
|
| SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
|
| {
|
| SkAutoExclusive l(DWriteFactoryMutex);
|
| - HRM(fTypeface->fFactory->CreateGlyphRunAnalysis(
|
| - &run,
|
| - 1.0f, // pixelsPerDip,
|
| - &fXform,
|
| - renderingMode,
|
| - fMeasuringMode,
|
| - 0.0f, // baselineOriginX,
|
| - 0.0f, // baselineOriginY,
|
| - &glyphRunAnalysis),
|
| - "Could not create glyph run analysis.");
|
| + if (fTypeface->fFactory2) {
|
| +#if SK_HAS_DWRITE_2_H
|
| + HRM(fTypeface->fFactory2->CreateGlyphRunAnalysis(
|
| + &run,
|
| + &fXform,
|
| + renderingMode,
|
| + fMeasuringMode,
|
| + fGridFitMode,
|
| + fAntiAliasMode,
|
| + 0.0f, // baselineOriginX,
|
| + 0.0f, // baselineOriginY,
|
| + &glyphRunAnalysis),
|
| + "Could not create DW2 glyph run analysis.");
|
| +#endif
|
| + } else {
|
| + HRM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
|
| + 1.0f, // pixelsPerDip,
|
| + &fXform,
|
| + renderingMode,
|
| + fMeasuringMode,
|
| + 0.0f, // baselineOriginX,
|
| + 0.0f, // baselineOriginY,
|
| + &glyphRunAnalysis),
|
| + "Could not create glyph run analysis.");
|
| + }
|
| }
|
| {
|
| Shared l(DWriteFactoryMutex);
|
| @@ -498,7 +569,7 @@ bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph,
|
| run.isSideways = FALSE;
|
| run.glyphOffsets = &offset;
|
|
|
| - HRESULT hr = fFactory2->TranslateColorGlyphRun(
|
| + HRESULT hr = fTypeface->fFactory2->TranslateColorGlyphRun(
|
| 0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph);
|
| if (hr == DWRITE_E_NOCOLOR) {
|
| return false;
|
| @@ -591,8 +662,6 @@ void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) {
|
| metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
|
| return;
|
| }
|
| -#else
|
| -# pragma message("No dwrite_1.h is available, font metrics may be affected.")
|
| #endif
|
|
|
| AutoTDWriteTable<SkOTTableHead> head(fTypeface->fDWriteFontFace.get());
|
| @@ -656,6 +725,22 @@ static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph)
|
| }
|
|
|
| template<bool APPLY_PREBLEND>
|
| +static void grayscale_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
|
| + const uint8_t* table8) {
|
| + const size_t dstRB = glyph.rowBytes();
|
| + const U16CPU width = glyph.fWidth;
|
| + uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
|
| +
|
| + for (U16CPU y = 0; y < glyph.fHeight; y++) {
|
| + for (U16CPU i = 0; i < width; i++) {
|
| + U8CPU a = *(src++);
|
| + dst[i] = sk_apply_lut_if<APPLY_PREBLEND>(a, table8);
|
| + }
|
| + dst = SkTAddOffset<uint8_t>(dst, dstRB);
|
| + }
|
| +}
|
| +
|
| +template<bool APPLY_PREBLEND>
|
| static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
|
| const size_t dstRB = glyph.rowBytes();
|
| const U16CPU width = glyph.fWidth;
|
| @@ -668,7 +753,7 @@ static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, cons
|
| U8CPU b = *(src++);
|
| dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
|
| }
|
| - dst = (uint8_t*)((char*)dst + dstRB);
|
| + dst = SkTAddOffset<uint8_t>(dst, dstRB);
|
| }
|
| }
|
|
|
| @@ -693,7 +778,7 @@ static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
|
| }
|
| dst[i] = SkPack888ToRGB16(r, g, b);
|
| }
|
| - dst = (uint16_t*)((char*)dst + dstRB);
|
| + dst = SkTAddOffset<uint16_t>(dst, dstRB);
|
| }
|
| }
|
|
|
| @@ -702,7 +787,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
|
| DWRITE_TEXTURE_TYPE textureType)
|
| {
|
| int sizeNeeded = glyph.fWidth * glyph.fHeight;
|
| - if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) {
|
| + if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) {
|
| sizeNeeded *= 3;
|
| }
|
| if (sizeNeeded > fBits.count()) {
|
| @@ -733,19 +818,33 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
|
| run.isSideways = FALSE;
|
| run.glyphOffsets = &offset;
|
| {
|
| -
|
| SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
|
| {
|
| SkAutoExclusive l(DWriteFactoryMutex);
|
| - HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
|
| - 1.0f, // pixelsPerDip,
|
| - &fXform,
|
| - renderingMode,
|
| - fMeasuringMode,
|
| - 0.0f, // baselineOriginX,
|
| - 0.0f, // baselineOriginY,
|
| - &glyphRunAnalysis),
|
| - "Could not create glyph run analysis.");
|
| + if (fTypeface->fFactory2) {
|
| +#if SK_HAS_DWRITE_2_H
|
| + HRNM(fTypeface->fFactory2->CreateGlyphRunAnalysis(&run,
|
| + &fXform,
|
| + renderingMode,
|
| + fMeasuringMode,
|
| + fGridFitMode,
|
| + fAntiAliasMode,
|
| + 0.0f, // baselineOriginX,
|
| + 0.0f, // baselineOriginY,
|
| + &glyphRunAnalysis),
|
| + "Could not create DW2 glyph run analysis.");
|
| +#endif
|
| + } else {
|
| + HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
|
| + 1.0f, // pixelsPerDip,
|
| + &fXform,
|
| + renderingMode,
|
| + 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.
|
| @@ -865,10 +964,18 @@ void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
|
| bilevel_to_bw(src, glyph);
|
| const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
|
| } else if (!isLCD(fRec)) {
|
| - if (fPreBlend.isApplicable()) {
|
| - rgb_to_a8<true>(src, glyph, fPreBlend.fG);
|
| + if (textureType == DWRITE_TEXTURE_ALIASED_1x1) {
|
| + if (fPreBlend.isApplicable()) {
|
| + grayscale_to_a8<true>(src, glyph, fPreBlend.fG);
|
| + } else {
|
| + grayscale_to_a8<false>(src, glyph, fPreBlend.fG);
|
| + }
|
| } else {
|
| - rgb_to_a8<false>(src, glyph, fPreBlend.fG);
|
| + if (fPreBlend.isApplicable()) {
|
| + rgb_to_a8<true>(src, glyph, fPreBlend.fG);
|
| + } else {
|
| + rgb_to_a8<false>(src, glyph, fPreBlend.fG);
|
| + }
|
| }
|
| } else {
|
| SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat);
|
|
|