diff options
-rw-r--r-- | external/skia/UnpackedTarball_skia.mk | 1 | ||||
-rw-r--r-- | external/skia/windows-text-gamma.patch.0 | 42 | ||||
-rw-r--r-- | external/skia/windows-typeface-directwrite.patch.0 | 48 | ||||
-rw-r--r-- | vcl/inc/skia/win/gdiimpl.hxx | 13 | ||||
-rw-r--r-- | vcl/inc/win/wingdiimpl.hxx | 2 | ||||
-rw-r--r-- | vcl/skia/win/gdiimpl.cxx | 91 | ||||
-rw-r--r-- | vcl/win/gdi/salfont.cxx | 4 |
7 files changed, 191 insertions, 10 deletions
diff --git a/external/skia/UnpackedTarball_skia.mk b/external/skia/UnpackedTarball_skia.mk index da0a2a7a0547..82fdbc433ece 100644 --- a/external/skia/UnpackedTarball_skia.mk +++ b/external/skia/UnpackedTarball_skia.mk @@ -33,6 +33,7 @@ skia_patches := \ operator-eq-bool.patch.0 \ fix-without-gl.patch.0 \ extend-rgb-to-rgba.patch.0 \ + windows-typeface-directwrite.patch.0 \ $(eval $(call gb_UnpackedTarball_set_patchlevel,skia,1)) diff --git a/external/skia/windows-text-gamma.patch.0 b/external/skia/windows-text-gamma.patch.0 index 366b67f15a65..624636b7da99 100644 --- a/external/skia/windows-text-gamma.patch.0 +++ b/external/skia/windows-text-gamma.patch.0 @@ -26,3 +26,45 @@ RGBToLcd16<false>(src, srcRB, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); } } +--- ./src/ports/SkScalerContext_win_dw.cpp ++++ ./src/ports/SkScalerContext_win_dw.cpp +@@ -1132,27 +1132,36 @@ void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { + BilevelToBW(src, glyph); + } else if (!isLCD(fRec)) { + if (textureType == DWRITE_TEXTURE_ALIASED_1x1) { ++#if defined(SK_GAMMA_APPLY_TO_A8) + if (fPreBlend.isApplicable()) { + GrayscaleToA8<true>(src, glyph, fPreBlend.fG); +- } else { ++ } else ++#endif ++ { + GrayscaleToA8<false>(src, glyph, fPreBlend.fG); + } + } else { ++#if defined(SK_GAMMA_APPLY_TO_A8) + if (fPreBlend.isApplicable()) { + RGBToA8<true>(src, glyph, fPreBlend.fG); +- } else { ++ } else ++#endif ++ { + RGBToA8<false>(src, glyph, fPreBlend.fG); + } + } + } else { + SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat); ++#if defined(SK_GAMMA_APPLY_TO_A8) + if (fPreBlend.isApplicable()) { + if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) { + RGBToLcd16<true, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); + } else { + RGBToLcd16<true, true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); + } +- } else { ++ } else ++#endif ++ { + if (fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag) { + RGBToLcd16<false, false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); + } else { diff --git a/external/skia/windows-typeface-directwrite.patch.0 b/external/skia/windows-typeface-directwrite.patch.0 new file mode 100644 index 000000000000..56e8209cedb4 --- /dev/null +++ b/external/skia/windows-typeface-directwrite.patch.0 @@ -0,0 +1,48 @@ +--- ./include/ports/SkTypeface_win.h ++++ ./include/ports/SkTypeface_win.h +@@ -75,5 +75,13 @@ SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWriteRenderer(sk_sp<SkRemotableFontM + */ + SK_API sk_sp<SkRemotableFontMgr> SkRemotableFontMgr_New_DirectWrite(); + ++struct IDWriteFontFace; ++struct IDWriteFont; ++struct IDWriteFontFamily; ++SK_API SkTypeface* SkCreateTypefaceDirectWrite(sk_sp<SkFontMgr> fontMgr, ++ IDWriteFontFace* fontFace, ++ IDWriteFont* font, ++ IDWriteFontFamily* fontFamily); ++ + #endif // SK_BUILD_FOR_WIN + #endif // SkTypeface_win_DEFINED +--- ./src/ports/SkFontMgr_win_dw.cpp ++++ ./src/ports/SkFontMgr_win_dw.cpp +@@ -320,6 +320,10 @@ private: + + friend class SkFontStyleSet_DirectWrite; + friend class FontFallbackRenderer; ++ friend SK_API SkTypeface* SkCreateTypefaceDirectWrite(sk_sp<SkFontMgr> fontMgr, ++ IDWriteFontFace* fontFace, ++ IDWriteFont* font, ++ IDWriteFontFamily* fontFamily); + }; + + class SkFontStyleSet_DirectWrite : public SkFontStyleSet { +@@ -1215,6 +1219,18 @@ SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory, + defaultFamilyName, defaultFamilyNameLen); + } + ++SkTypeface* SkCreateTypefaceDirectWrite(sk_sp<SkFontMgr> fontMgr, ++ IDWriteFontFace* fontFace, ++ IDWriteFont* font, ++ IDWriteFontFamily* fontFamily) ++{ ++ SkFontMgr_DirectWrite* mgr = dynamic_cast<SkFontMgr_DirectWrite*>(fontMgr.get()); ++ if(!mgr) ++ return nullptr; ++ sk_sp<SkTypeface> typeface = mgr->makeTypefaceFromDWriteFont(fontFace, font, fontFamily); ++ return typeface.release(); ++} ++ + #include "include/ports/SkFontMgr_indirect.h" + SK_API sk_sp<SkFontMgr> SkFontMgr_New_DirectWriteRenderer(sk_sp<SkRemotableFontMgr> proxy) { + sk_sp<SkFontMgr> impl(SkFontMgr_New_DirectWrite()); diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx index 3d6c680f2af4..c16981abcb23 100644 --- a/vcl/inc/skia/win/gdiimpl.hxx +++ b/vcl/inc/skia/win/gdiimpl.hxx @@ -21,6 +21,10 @@ #include <ControlCacheKey.hxx> #include <svdata.hxx> +#include <SkFont.h> + +class SkTypeface; +class SkFontMgr; class ControlCacheKey; class SkiaCompatibleDC : public CompatibleDC @@ -83,12 +87,21 @@ public: const SalTwoRect& rPosAry) override; virtual void DeferredTextDraw(const CompatibleDC::Texture* pTexture, Color nMaskColor, const SalTwoRect& rPosAry) override; + virtual void ClearDevFontCache() override; static void prepareSkia(); protected: virtual void createWindowContext() override; virtual void performFlush() override; + sk_sp<SkTypeface> createDirectWriteTypeface(const LOGFONTW& logFont); + SkFont::Edging getFontEdging(); + IDWriteFactory* dwriteFactory; + IDWriteGdiInterop* dwriteGdiInterop; + sk_sp<SkFontMgr> dwriteFontMgr; + bool dwriteDone = false; + SkFont::Edging fontEdging; + bool fontEdgingDone = false; }; typedef std::pair<ControlCacheKey, sk_sp<SkImage>> SkiaControlCachePair; diff --git a/vcl/inc/win/wingdiimpl.hxx b/vcl/inc/win/wingdiimpl.hxx index e81e35201413..679be2c36588 100644 --- a/vcl/inc/win/wingdiimpl.hxx +++ b/vcl/inc/win/wingdiimpl.hxx @@ -35,6 +35,8 @@ public: abort(); }; + virtual void ClearDevFontCache(){}; + // Implementation for WinSalGraphics::DrawTextLayout(). // Returns true if handled, if false, then WinSalGraphics will handle it itself. virtual bool DrawTextLayout(const GenericSalLayout&) { return false; } diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx index 42c9078316f2..7bf150a6ccee 100644 --- a/vcl/skia/win/gdiimpl.cxx +++ b/vcl/skia/win/gdiimpl.cxx @@ -14,6 +14,7 @@ #include <skia/utils.hxx> #include <skia/zone.hxx> #include <win/winlayout.hxx> +#include <comphelper/windowserrorstring.hxx> #include <SkCanvas.h> #include <SkColorFilter.h> @@ -21,6 +22,7 @@ #include <SkPixelRef.h> #include <SkTypeface_win.h> #include <SkFont.h> +#include <SkFontMgr.h> #include <tools/sk_app/win/WindowContextFactory_win.h> #include <tools/sk_app/WindowContext.h> @@ -111,6 +113,55 @@ bool WinSkiaSalGraphicsImpl::RenderAndCacheNativeControl(CompatibleDC& rWhite, C return true; } +#ifdef SAL_LOG_WARN +HRESULT checkResult(HRESULT hr, const char* file, size_t line) +{ + if (FAILED(hr)) + { + OUString sLocationString + = OUString::createFromAscii(file) + ":" + OUString::number(line) + " "; + SAL_DETAIL_LOG_STREAM(SAL_DETAIL_ENABLE_LOG_WARN, ::SAL_DETAIL_LOG_LEVEL_WARN, "vcl.skia", + sLocationString.toUtf8().getStr(), + "HRESULT failed with: 0x" << OUString::number(hr, 16) << ": " + << WindowsErrorStringFromHRESULT(hr)); + } + return hr; +} + +#define CHECKHR(funct) checkResult(funct, __FILE__, __LINE__) +#else +#define CHECKHR(funct) (funct) +#endif + +sk_sp<SkTypeface> WinSkiaSalGraphicsImpl::createDirectWriteTypeface(const LOGFONTW& logFont) +{ + if (!dwriteDone) + { + IDWriteFactory* factory; + if (SUCCEEDED( + CHECKHR(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), + reinterpret_cast<IUnknown**>(&factory))))) + { + if (SUCCEEDED(CHECKHR(factory->GetGdiInterop(&dwriteGdiInterop)))) + dwriteFontMgr = SkFontMgr_New_DirectWrite(dwriteFactory); + else + factory->Release(); + } + dwriteDone = true; + } + IDWriteFont* font = nullptr; + IDWriteFontFace* fontFace; + IDWriteFontFamily* fontFamily; + if (FAILED(CHECKHR(dwriteGdiInterop->CreateFontFromLOGFONT(&logFont, &font)))) + return nullptr; + if (FAILED(CHECKHR(font->CreateFontFace(&fontFace)))) + return nullptr; + if (FAILED(CHECKHR(font->GetFontFamily(&fontFamily)))) + return nullptr; + return sk_sp<SkTypeface>( + SkCreateTypefaceDirectWrite(dwriteFontMgr, fontFace, font, fontFamily)); +} + bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) { const WinFontInstance& rWinFont = static_cast<const WinFontInstance&>(rLayout.GetFont()); @@ -125,7 +176,9 @@ bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) assert(false); return false; } - sk_sp<SkTypeface> typeface(SkCreateTypefaceFromLOGFONT(logFont)); + sk_sp<SkTypeface> typeface = createDirectWriteTypeface(logFont); + if (!typeface) // fall back to GDI text rendering + typeface.reset(SkCreateTypefaceFromLOGFONT(logFont)); // lfHeight actually depends on DPI, so it's not really font height as such, // but for LOGFONT-based typefaces Skia simply sets lfHeight back to this value // directly. @@ -133,6 +186,20 @@ bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) if (fontHeight < 0) fontHeight = -fontHeight; SkFont font(typeface, fontHeight, fHScale, 0); + font.setEdging(getFontEdging()); + assert(dynamic_cast<SkiaSalGraphicsImpl*>(mWinParent.GetImpl())); + SkiaSalGraphicsImpl* impl = static_cast<SkiaSalGraphicsImpl*>(mWinParent.GetImpl()); + COLORREF color = ::GetTextColor(mWinParent.getHDC()); + Color salColor(GetRValue(color), GetGValue(color), GetBValue(color)); + // The font already is set up to have glyphs rotated as needed. + impl->drawGenericLayout(rLayout, salColor, font, SkiaSalGraphicsImpl::GlyphOrientation::Ignore); + return true; +} + +SkFont::Edging WinSkiaSalGraphicsImpl::getFontEdging() +{ + if (fontEdgingDone) + return fontEdging; // Skia needs to be explicitly told what kind of antialiasing should be used, // get it from system settings. This does not actually matter for the text // rendering itself, since Skia has been patched to simply use the setting @@ -141,23 +208,27 @@ bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) // the appropriate AA setting. But Skia internally chooses the format to which // the glyphs will be rendered based on this setting (subpixel AA requires colors, // others do not). + fontEdging = SkFont::Edging::kAlias; BOOL set; if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &set, 0) && set) { UINT set2; if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &set2, 0) && set2 == FE_FONTSMOOTHINGCLEARTYPE) - font.setEdging(SkFont::Edging::kSubpixelAntiAlias); + fontEdging = SkFont::Edging::kSubpixelAntiAlias; else - font.setEdging(SkFont::Edging::kAntiAlias); + fontEdging = SkFont::Edging::kAntiAlias; } - assert(dynamic_cast<SkiaSalGraphicsImpl*>(mWinParent.GetImpl())); - SkiaSalGraphicsImpl* impl = static_cast<SkiaSalGraphicsImpl*>(mWinParent.GetImpl()); - COLORREF color = ::GetTextColor(mWinParent.getHDC()); - Color salColor(GetRValue(color), GetGValue(color), GetBValue(color)); - // The font already is set up to have glyphs rotated as needed. - impl->drawGenericLayout(rLayout, salColor, font, SkiaSalGraphicsImpl::GlyphOrientation::Ignore); - return true; + // Cache this, it is actually visible a little bit when profiling. + fontEdgingDone = true; + return fontEdging; +} + +void WinSkiaSalGraphicsImpl::ClearDevFontCache() +{ + dwriteFontMgr.reset(); + dwriteDone = false; + fontEdgingDone = false; } void WinSkiaSalGraphicsImpl::PreDrawText() { preDraw(); } diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx index 774178b683f8..cd7ca435e807 100644 --- a/vcl/win/gdi/salfont.cxx +++ b/vcl/win/gdi/salfont.cxx @@ -58,6 +58,7 @@ #include <win/saldata.hxx> #include <win/salgdi.h> #include <win/winlayout.hxx> +#include <win/wingdiimpl.hxx> #include <impfontcharmap.hxx> #include <impfontmetricdata.hxx> #include <impglyphitem.hxx> @@ -1272,6 +1273,9 @@ void WinSalGraphics::GetDevFontList( PhysicalFontCollection* pFontCollection ) void WinSalGraphics::ClearDevFontCache() { + WinSalGraphicsImplBase* pImpl = dynamic_cast<WinSalGraphicsImplBase*>(GetImpl()); + assert(pImpl != nullptr); + pImpl->ClearDevFontCache(); ImplReleaseTempFonts(*GetSalData(), false); } |