vcl/inc/skia/win/gdiimpl.hxx | 38 ++++++++++++++++++++--- vcl/inc/win/salgdi.h | 45 --------------------------- vcl/inc/win/wingdiimpl.hxx | 5 +-- vcl/skia/win/gdiimpl.cxx | 45 +++++++++++++++++++++------ vcl/win/gdi/salgdi.cxx | 56 ---------------------------------- vcl/win/gdi/salnativewidgets-luna.cxx | 32 ++++++++++++------- 6 files changed, 94 insertions(+), 127 deletions(-)
New commits: commit 4a4d388e17ae7490ed36f4bb0dd21fbefcdda124 Author: Noel Grandin <noelgran...@gmail.com> AuthorDate: Wed May 7 01:58:16 2025 +0200 Commit: Noel Grandin <noelgran...@gmail.com> CommitDate: Wed May 7 08:40:48 2025 +0200 simplify CompatibleDC This class is only really used by the skia case. The non-skia (i.e. GDI) case completely bypasses it. So we can remove the hierarchy and just make it into a skia focused class, simplifying the code structure in the process. Change-Id: I97f8160126bc5f823c882f3b338c0b2bec2160cb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185005 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx index d8428d395029..1dcb33fb693c 100644 --- a/vcl/inc/skia/win/gdiimpl.hxx +++ b/vcl/inc/skia/win/gdiimpl.hxx @@ -29,10 +29,39 @@ class SkTypeface; class ControlCacheKey; -class SkiaCompatibleDC : public CompatibleDC +/** Class that creates (and destroys) a compatible Device Context. + +This is to be used for GDI drawing into a DIB that we later use for a different +drawing method, such as a texture for OpenGL drawing or surface for Skia drawing. +*/ +class SkiaCompatibleDC { + /// The compatible DC that we create for our purposes. + HDC mhCompatibleDC; + + /// Mapping between the GDI position and OpenGL, to use for OpenGL drawing. + SalTwoRect maRects; + + /// DIBSection that we use for the GDI drawing, and later obtain. + HBITMAP mhBitmap; + + /// Return the previous bitmap to undo the SelectObject. + HBITMAP mhOrigBitmap; + + /// DIBSection data. + sal_uInt32* mpData; + + /// The SalGraphicsImpl where we will draw. If null, we ignore the drawing, it means it happened directly to the DC... + WinSalGraphicsImplBase* mpImpl; + public: - SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int width, int height); + SkiaCompatibleDC(WinSalGraphics& rGraphics, int x, int y, int width, int height); + ~SkiaCompatibleDC(); + + HDC getCompatibleHDC() const { return mhCompatibleDC; } + + /// Reset the DC with the defined color. + void fill(sal_uInt32 color); sk_sp<SkImage> getAsImageDiff(const SkiaCompatibleDC& white) const; }; @@ -48,8 +77,9 @@ public: virtual bool UseRenderNativeControl() const override { return true; } virtual bool TryRenderCachedNativeControl(ControlCacheKey const& rControlCacheKey, int nX, int nY) override; - virtual bool RenderAndCacheNativeControl(CompatibleDC& rWhite, CompatibleDC& rBlack, int nX, - int nY, ControlCacheKey& aControlCacheKey) override; + virtual bool RenderAndCacheNativeControl(SkiaCompatibleDC& rWhite, SkiaCompatibleDC& rBlack, + int nX, int nY, + ControlCacheKey& aControlCacheKey) override; virtual bool DrawTextLayout(const GenericSalLayout& layout) override; virtual void ClearDevFontCache() override; diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index c80f78e20569..65988c2867d4 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -85,51 +85,6 @@ private: mutable sal::systools::COMReference<IDWriteFontFace> mxDWFontFace; }; -/** Class that creates (and destroys) a compatible Device Context. - -This is to be used for GDI drawing into a DIB that we later use for a different -drawing method, such as a texture for OpenGL drawing or surface for Skia drawing. -*/ -class CompatibleDC -{ -protected: - /// The compatible DC that we create for our purposes. - HDC mhCompatibleDC; - - /// DIBSection that we use for the GDI drawing, and later obtain. - HBITMAP mhBitmap; - - /// Return the previous bitmap to undo the SelectObject. - HBITMAP mhOrigBitmap; - - /// DIBSection data. - sal_uInt32 *mpData; - - /// Mapping between the GDI position and OpenGL, to use for OpenGL drawing. - SalTwoRect maRects; - - /// The SalGraphicsImpl where we will draw. If null, we ignore the drawing, it means it happened directly to the DC... - WinSalGraphicsImplBase *mpImpl; - - // If 'disable' is true, this class is a simple wrapper for drawing directly. Subclasses should use true. - CompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height, bool disable=true); - -public: - static std::unique_ptr< CompatibleDC > create(SalGraphics &rGraphics, int x, int y, int width, int height); - - virtual ~CompatibleDC(); - - HDC getCompatibleHDC() { return mhCompatibleDC; } - - SalTwoRect getTwoRect() const { return maRects; } - - tools::Long getBitmapWidth() const { return maRects.mnSrcWidth; } - tools::Long getBitmapHeight() const { return maRects.mnSrcHeight; } - - /// Reset the DC with the defined color. - void fill(sal_uInt32 color); -}; - /** * WinSalGraphics never owns the HDC it uses to draw, because the HDC can have * various origins with different ways to correctly free it. And WinSalGraphics diff --git a/vcl/inc/win/wingdiimpl.hxx b/vcl/inc/win/wingdiimpl.hxx index 94a1ec8f84f4..e2482606cd1f 100644 --- a/vcl/inc/win/wingdiimpl.hxx +++ b/vcl/inc/win/wingdiimpl.hxx @@ -13,6 +13,7 @@ #include <ControlCacheKey.hxx> class ControlCacheKey; +class SkiaCompatibleDC; // Base class for some functionality that OpenGL/Skia/GDI backends must each implement. class WinSalGraphicsImplBase @@ -27,8 +28,8 @@ public: { abort(); } - virtual bool RenderAndCacheNativeControl(CompatibleDC& /*rWhite*/, CompatibleDC& /*rBlack*/, - int /*nX*/, int /*nY*/, + virtual bool RenderAndCacheNativeControl(SkiaCompatibleDC& /*rWhite*/, + SkiaCompatibleDC& /*rBlack*/, int /*nX*/, int /*nY*/, ControlCacheKey& /*aControlCacheKey*/) { abort(); diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx index e315eb0f7234..f26d37fcf491 100644 --- a/vcl/skia/win/gdiimpl.cxx +++ b/vcl/skia/win/gdiimpl.cxx @@ -12,6 +12,7 @@ #include <skia/win/gdiimpl.hxx> #include <win/saldata.hxx> +#include <win/salvd.h> #include <vcl/skia/SkiaHelper.hxx> #include <skia/utils.hxx> #include <skia/zone.hxx> @@ -154,15 +155,11 @@ bool WinSkiaSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey const& return true; } -bool WinSkiaSalGraphicsImpl::RenderAndCacheNativeControl(CompatibleDC& rWhite, CompatibleDC& rBlack, - int nX, int nY, +bool WinSkiaSalGraphicsImpl::RenderAndCacheNativeControl(SkiaCompatibleDC& rWhite, + SkiaCompatibleDC& rBlack, int nX, int nY, ControlCacheKey& aControlCacheKey) { - assert(dynamic_cast<SkiaCompatibleDC*>(&rWhite)); - assert(dynamic_cast<SkiaCompatibleDC*>(&rBlack)); - - sk_sp<SkImage> image = static_cast<SkiaCompatibleDC&>(rBlack).getAsImageDiff( - static_cast<SkiaCompatibleDC&>(rWhite)); + sk_sp<SkImage> image = rBlack.getAsImageDiff(rWhite); preDraw(); SAL_INFO("vcl.skia.trace", "renderandcachednativecontrol(" @@ -346,9 +343,39 @@ void WinSkiaSalGraphicsImpl::ClearDevFontCache() initFontInfo(); // get font info again, just in case } -SkiaCompatibleDC::SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int width, int height) - : CompatibleDC(rGraphics, x, y, width, height, false) +SkiaCompatibleDC::SkiaCompatibleDC(WinSalGraphics& rGraphics, int x, int y, int width, int height) + : maRects(0, 0, width, height, x, y, width, height) +{ + mpImpl = rGraphics.getWinSalGraphicsImplBase(); + mhCompatibleDC = CreateCompatibleDC(rGraphics.getHDC()); + + // move the origin so that we always paint at 0,0 - to keep the bitmap small + OffsetViewportOrgEx(mhCompatibleDC, -x, -y, nullptr); + + mhBitmap = WinSalVirtualDevice::ImplCreateVirDevBitmap(mhCompatibleDC, width, height, 32, + reinterpret_cast<void**>(&mpData)); + + mhOrigBitmap = static_cast<HBITMAP>(SelectObject(mhCompatibleDC, mhBitmap)); +} + +SkiaCompatibleDC::~SkiaCompatibleDC() { + if (mpImpl) + { + SelectObject(mhCompatibleDC, mhOrigBitmap); + DeleteObject(mhBitmap); + DeleteDC(mhCompatibleDC); + } +} + +void SkiaCompatibleDC::fill(sal_uInt32 color) +{ + if (!mpData) + return; + + sal_uInt32* p = mpData; + for (int i = maRects.mnSrcWidth * maRects.mnSrcHeight; i > 0; --i) + *p++ = color; } sk_sp<SkImage> SkiaCompatibleDC::getAsImageDiff(const SkiaCompatibleDC& white) const diff --git a/vcl/win/gdi/salgdi.cxx b/vcl/win/gdi/salgdi.cxx index 31993e7e5957..3bd595699f1b 100644 --- a/vcl/win/gdi/salgdi.cxx +++ b/vcl/win/gdi/salgdi.cxx @@ -242,62 +242,6 @@ void ImplClearHDCCache( SalData* pData ) } } -std::unique_ptr< CompatibleDC > CompatibleDC::create(SalGraphics &rGraphics, int x, int y, int width, int height) -{ -#if HAVE_FEATURE_SKIA - if (SkiaHelper::isVCLSkiaEnabled()) - return std::make_unique< SkiaCompatibleDC >( rGraphics, x, y, width, height ); -#endif - return std::unique_ptr< CompatibleDC >( new CompatibleDC( rGraphics, x, y, width, height )); -} - -CompatibleDC::CompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height, bool disable) - : mhBitmap(nullptr) - , mpData(nullptr) - , maRects(0, 0, width, height, x, y, width, height) - , mpImpl(nullptr) -{ - WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics); - - if( disable ) - { - // we avoid the OpenGL drawing, instead we draw directly to the DC - mhCompatibleDC = rWinGraphics.getHDC(); - return; - } - - mpImpl = rWinGraphics.getWinSalGraphicsImplBase(); - mhCompatibleDC = CreateCompatibleDC(rWinGraphics.getHDC()); - - // move the origin so that we always paint at 0,0 - to keep the bitmap - // small - OffsetViewportOrgEx(mhCompatibleDC, -x, -y, nullptr); - - mhBitmap = WinSalVirtualDevice::ImplCreateVirDevBitmap(mhCompatibleDC, width, height, 32, reinterpret_cast<void **>(&mpData)); - - mhOrigBitmap = static_cast<HBITMAP>(SelectObject(mhCompatibleDC, mhBitmap)); -} - -CompatibleDC::~CompatibleDC() -{ - if (mpImpl) - { - SelectObject(mhCompatibleDC, mhOrigBitmap); - DeleteObject(mhBitmap); - DeleteDC(mhCompatibleDC); - } -} - -void CompatibleDC::fill(sal_uInt32 color) -{ - if (!mpData) - return; - - sal_uInt32 *p = mpData; - for (int i = maRects.mnSrcWidth * maRects.mnSrcHeight; i > 0; --i) - *p++ = color; -} - WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, [[maybe_unused]] SalGeometryProvider *pProvider): mhLocalDC(nullptr), mbPrinter(eType == WinSalGraphics::PRINTER), diff --git a/vcl/win/gdi/salnativewidgets-luna.cxx b/vcl/win/gdi/salnativewidgets-luna.cxx index 7c442ab8cda3..b375a60b4e69 100644 --- a/vcl/win/gdi/salnativewidgets-luna.cxx +++ b/vcl/win/gdi/salnativewidgets-luna.cxx @@ -40,6 +40,7 @@ #include <vcl/svapp.hxx> #include <vcl/settings.hxx> #include <vcl/themecolors.hxx> +#include <vcl/skia/skiahelper.hxx> #include <salinst.hxx> #include <toolbarvalue.hxx> #include <menubarvalue.hxx> @@ -51,6 +52,7 @@ #include <win/salinst.h> #include <win/scoped_gdi.hxx> #include <win/wingdiimpl.hxx> +#include <skia/win/gdiimpl.hxx> #include <uxtheme.h> #include <vssym32.h> @@ -1653,23 +1655,31 @@ bool WinSalGraphics::drawNativeControl( ControlType nType, // restore alignment SetTextAlign(getHDC(), ta); } - else +#if HAVE_FEATURE_SKIA + else if (SkiaHelper::isVCLSkiaEnabled()) { - // We can do OpenGL/Skia - std::unique_ptr<CompatibleDC> aBlackDC(CompatibleDC::create(*this, cacheRect.Left(), cacheRect.Top(), cacheRect.GetWidth()+1, cacheRect.GetHeight()+1)); - SetTextAlign(aBlackDC->getCompatibleHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP); - aBlackDC->fill(RGB(0, 0, 0)); + // We can do Skia + SkiaCompatibleDC aBlackDC( *this, cacheRect.Left(), cacheRect.Top(), cacheRect.GetWidth()+1, cacheRect.GetHeight()+1 ); + SetTextAlign(aBlackDC.getCompatibleHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP); + aBlackDC.fill(RGB(0, 0, 0)); - std::unique_ptr<CompatibleDC> aWhiteDC(CompatibleDC::create(*this, cacheRect.Left(), cacheRect.Top(), cacheRect.GetWidth()+1, cacheRect.GetHeight()+1)); - SetTextAlign(aWhiteDC->getCompatibleHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP); - aWhiteDC->fill(RGB(0xff, 0xff, 0xff)); + SkiaCompatibleDC aWhiteDC(*this, cacheRect.Left(), cacheRect.Top(), cacheRect.GetWidth()+1, cacheRect.GetHeight()+1); + SetTextAlign(aWhiteDC.getCompatibleHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP); + aWhiteDC.fill(RGB(0xff, 0xff, 0xff)); - if (ImplDrawNativeControl(aBlackDC->getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr, bUseDarkMode) && - ImplDrawNativeControl(aWhiteDC->getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr, bUseDarkMode)) + if (ImplDrawNativeControl(aBlackDC.getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr, bUseDarkMode) && + ImplDrawNativeControl(aWhiteDC.getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr, bUseDarkMode)) { - bOk = pImpl->RenderAndCacheNativeControl(*aWhiteDC, *aBlackDC, cacheRect.Left(), cacheRect.Top(), aControlCacheKey); + bOk = pImpl->RenderAndCacheNativeControl(aWhiteDC, aBlackDC, cacheRect.Left(), cacheRect.Top(), aControlCacheKey); } } +#endif + else + { + // Use normal GDI + SetTextAlign(getHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP); + ImplDrawNativeControl(getHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr, bUseDarkMode); + } if (bUseDarkMode) SetWindowTheme(mhWnd, nullptr, nullptr);