diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2019-10-31 11:47:18 +0100 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2019-11-27 09:55:13 +0100 |
commit | 31b2c10484fc265ff0f05ce405c2ed5b982f8714 (patch) | |
tree | c2417156e30bff34610ca49943a73794d21adea4 | |
parent | 840f55c0f6e21d00b51e4a52824c7eb7f938122f (diff) |
implement Skia native controls drawing/caching for Windows
This actually fixes a number of drawing problems (e.g. highlight
in popup menus), it seems the other code path is buggy.
Change-Id: Iea697f577d08d20e338224d5ff5b3bf7b653f8d1
-rw-r--r-- | vcl/inc/ControlCacheKey.hxx | 15 | ||||
-rw-r--r-- | vcl/inc/opengl/win/gdiimpl.hxx | 26 | ||||
-rw-r--r-- | vcl/inc/skia/win/gdiimpl.hxx | 19 | ||||
-rw-r--r-- | vcl/inc/win/saldata.hxx | 6 | ||||
-rw-r--r-- | vcl/opengl/win/gdiimpl.cxx | 18 | ||||
-rw-r--r-- | vcl/skia/win/gdiimpl.cxx | 85 | ||||
-rw-r--r-- | vcl/win/app/salinst.cxx | 1 | ||||
-rw-r--r-- | vcl/win/gdi/salnativewidgets-luna.cxx | 20 |
8 files changed, 138 insertions, 52 deletions
diff --git a/vcl/inc/ControlCacheKey.hxx b/vcl/inc/ControlCacheKey.hxx index 11d4ce07d719..06a1ff97bd8d 100644 --- a/vcl/inc/ControlCacheKey.hxx +++ b/vcl/inc/ControlCacheKey.hxx @@ -22,6 +22,7 @@ #include <tools/gen.hxx> #include <vcl/salnativewidgets.hxx> +#include <boost/functional/hash.hpp> class ControlCacheKey { @@ -76,4 +77,18 @@ public: } }; +struct ControlCacheHashFunction +{ + std::size_t operator()(ControlCacheKey const& aCache) const + { + std::size_t seed = 0; + boost::hash_combine(seed, aCache.mnType); + boost::hash_combine(seed, aCache.mnPart); + boost::hash_combine(seed, aCache.mnState); + boost::hash_combine(seed, aCache.maSize.Width()); + boost::hash_combine(seed, aCache.maSize.Height()); + return seed; + } +}; + #endif // INCLUDED_VCL_INC_CONTROLCACHEKEY_HXX diff --git a/vcl/inc/opengl/win/gdiimpl.hxx b/vcl/inc/opengl/win/gdiimpl.hxx index 2130654a3951..98ddabbc7a53 100644 --- a/vcl/inc/opengl/win/gdiimpl.hxx +++ b/vcl/inc/opengl/win/gdiimpl.hxx @@ -79,30 +79,16 @@ public: }; -struct ControlCacheHashFunction -{ - std::size_t operator()(ControlCacheKey const& aCache) const - { - std::size_t seed = 0; - boost::hash_combine(seed, aCache.mnType); - boost::hash_combine(seed, aCache.mnPart); - boost::hash_combine(seed, aCache.mnState); - boost::hash_combine(seed, aCache.maSize.Width()); - boost::hash_combine(seed, aCache.maSize.Height()); - return seed; - } -}; - -typedef std::pair<ControlCacheKey, std::unique_ptr<TextureCombo>> ControlCachePair; -typedef o3tl::lru_map<ControlCacheKey, std::unique_ptr<TextureCombo>, ControlCacheHashFunction> ControlCacheType; +typedef std::pair<ControlCacheKey, std::unique_ptr<TextureCombo>> OpenGLControlCachePair; +typedef o3tl::lru_map<ControlCacheKey, std::unique_ptr<TextureCombo>, ControlCacheHashFunction> OpenGLControlCacheType; -class TheTextureCache { - ControlCacheType cache; +class OpenGLControlsCache { + OpenGLControlCacheType cache; - TheTextureCache(); + OpenGLControlsCache(); public: - static ControlCacheType & get(); + static OpenGLControlCacheType & get(); }; #endif diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx index 6bd52b073aa5..321f35f24366 100644 --- a/vcl/inc/skia/win/gdiimpl.hxx +++ b/vcl/inc/skia/win/gdiimpl.hxx @@ -16,6 +16,9 @@ #include <skia/gdiimpl.hxx> #include <win/salgdi.h> #include <win/wingdiimpl.hxx> +#include <o3tl/lru_map.hxx> +#include <ControlCacheKey.hxx> +#include <svdata.hxx> class ControlCacheKey; namespace sk_app @@ -34,6 +37,9 @@ public: virtual bool wantsTextColorWhite() const override { return true; } + SkBitmap getAsBitmap(); + SkBitmap getAsMaskBitmap(); + struct Texture; }; @@ -80,6 +86,19 @@ private: std::unique_ptr<sk_app::WindowContext> mWindowContext; }; +typedef std::pair<ControlCacheKey, SkBitmap> SkiaControlCachePair; +typedef o3tl::lru_map<ControlCacheKey, SkBitmap, ControlCacheHashFunction> SkiaControlCacheType; + +class SkiaControlsCache +{ + SkiaControlCacheType cache; + + SkiaControlsCache(); + +public: + static SkiaControlCacheType& get(); +}; + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/saldata.hxx b/vcl/inc/win/saldata.hxx index e9889e6653d1..0e657e15ed95 100644 --- a/vcl/inc/win/saldata.hxx +++ b/vcl/inc/win/saldata.hxx @@ -42,7 +42,8 @@ struct GlobalWinGlyphCache; struct HDCCache; struct TempFontItem; class TextOutRenderer; -class TheTextureCache; +class OpenGLControlsCache; +class SkiaControlsCache; #define MAX_STOCKPEN 4 #define MAX_STOCKBRUSH 4 @@ -123,7 +124,8 @@ public: // tdf#107205 need 2 instances because D2DWrite can't rotate text std::unique_ptr<TextOutRenderer> m_pExTextOutRenderer; std::unique_ptr<GlobalWinGlyphCache> m_pGlobalWinGlyphCache; - std::unique_ptr<TheTextureCache> m_pTextureCache; + std::unique_ptr<OpenGLControlsCache> m_pOpenGLControlsCache; + std::unique_ptr<SkiaControlsCache> m_pSkiaControlsCache; }; inline void SetSalData( SalData* pData ) { ImplGetSVData()->mpSalData = pData; } diff --git a/vcl/opengl/win/gdiimpl.cxx b/vcl/opengl/win/gdiimpl.cxx index bb6e5bf0a16c..c47de25b19f3 100644 --- a/vcl/opengl/win/gdiimpl.cxx +++ b/vcl/opengl/win/gdiimpl.cxx @@ -746,14 +746,14 @@ void WinOpenGLSalGraphicsImpl::Init() OpenGLSalGraphicsImpl::Init(); } -TheTextureCache::TheTextureCache(): cache(200) {} +OpenGLControlsCache::OpenGLControlsCache(): cache(200) {} -ControlCacheType & TheTextureCache::get() { +OpenGLControlCacheType & OpenGLControlsCache::get() { SalData * data = GetSalData(); - if (!data->m_pTextureCache) { - data->m_pTextureCache.reset(new TheTextureCache); + if (!data->m_pOpenGLControlsCache) { + data->m_pOpenGLControlsCache.reset(new OpenGLControlsCache); } - return data->m_pTextureCache->cache; + return data->m_pOpenGLControlsCache->cache; } OpenGLCompatibleDC::OpenGLCompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height) @@ -794,8 +794,8 @@ bool WinOpenGLSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey cons if (!gbCacheEnabled) return false; - auto & gTextureCache = TheTextureCache::get(); - ControlCacheType::const_iterator iterator = gTextureCache.find(rControlCacheKey); + auto & gTextureCache = OpenGLControlsCache::get(); + OpenGLControlCacheType::const_iterator iterator = gTextureCache.find(rControlCacheKey); if (iterator == gTextureCache.end()) return false; @@ -857,8 +857,8 @@ bool WinOpenGLSalGraphicsImpl::RenderAndCacheNativeControl(CompatibleDC& rWhite, if (!aControlCacheKey.canCacheControl()) return true; - ControlCachePair pair(aControlCacheKey, std::move(pCombo)); - TheTextureCache::get().insert(std::move(pair)); + OpenGLControlCachePair pair(aControlCacheKey, std::move(pCombo)); + OpenGLControlsCache::get().insert(std::move(pair)); return bResult; } diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx index 3be821c350ec..ac1ff016d3c4 100644 --- a/vcl/skia/win/gdiimpl.cxx +++ b/vcl/skia/win/gdiimpl.cxx @@ -11,6 +11,7 @@ #include <tools/sk_app/win/WindowContextFactory_win.h> #include <tools/sk_app/WindowContext.h> +#include <win/saldata.hxx> #include <SkColorFilter.h> #include <SkPixelRef.h> @@ -84,22 +85,40 @@ void WinSkiaSalGraphicsImpl::performFlush() bool WinSkiaSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey const& rControlCacheKey, int nX, int nY) { - (void)rControlCacheKey; - (void)nX; - (void)nY; - return false; // TODO + static bool gbCacheEnabled = !getenv("SAL_WITHOUT_WIDGET_CACHE"); + if (!gbCacheEnabled) + return false; + + auto& controlsCache = SkiaControlsCache::get(); + SkiaControlCacheType::const_iterator iterator = controlsCache.find(rControlCacheKey); + if (iterator == controlsCache.end()) + return false; + + preDraw(); + mSurface->getCanvas()->drawBitmap(iterator->second, nX, nY); + postDraw(); + return true; } bool WinSkiaSalGraphicsImpl::RenderAndCacheNativeControl(CompatibleDC& rWhite, CompatibleDC& rBlack, int nX, int nY, ControlCacheKey& aControlCacheKey) { - (void)rWhite; + assert(dynamic_cast<SkiaCompatibleDC*>(&rWhite)); + assert(dynamic_cast<SkiaCompatibleDC*>(&rBlack)); + + SkBitmap bitmap = static_cast<SkiaCompatibleDC&>(rWhite).getAsBitmap(); + preDraw(); + mSurface->getCanvas()->drawBitmap(bitmap, nX, nY); + postDraw(); + // TODO what is the point of the second texture? (void)rBlack; - (void)nX; - (void)nY; - (void)aControlCacheKey; - return false; // TODO + + if (!aControlCacheKey.canCacheControl()) + return true; + SkiaControlCachePair pair(aControlCacheKey, std::move(bitmap)); + SkiaControlsCache::get().insert(std::move(pair)); + return true; } void WinSkiaSalGraphicsImpl::PreDrawText() { preDraw(); } @@ -146,6 +165,12 @@ SkiaCompatibleDC::SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int wid std::unique_ptr<CompatibleDC::Texture> SkiaCompatibleDC::getAsMaskTexture() { auto ret = std::make_unique<SkiaCompatibleDC::Texture>(); + ret->bitmap = getAsMaskBitmap(); + return ret; +} + +SkBitmap SkiaCompatibleDC::getAsMaskBitmap() +{ // mpData is in the BGRA format, with A unused (and set to 0), and RGB are grey, // so convert it to Skia format, then to 8bit and finally use as alpha mask SkBitmap tmpBitmap; @@ -171,8 +196,7 @@ std::unique_ptr<CompatibleDC::Texture> SkiaCompatibleDC::getAsMaskTexture() alpha.setInfo(bitmap8.info().makeColorType(kAlpha_8_SkColorType), bitmap8.rowBytes()); alpha.setPixelRef(sk_ref_sp(bitmap8.pixelRef()), bitmap8.pixelRefOrigin().x(), bitmap8.pixelRefOrigin().y()); - ret->bitmap = alpha; - return ret; + return alpha; } bool SkiaCompatibleDC::copyToTexture(CompatibleDC::Texture& aTexture) @@ -199,4 +223,43 @@ bool SkiaCompatibleDC::copyToTexture(CompatibleDC::Texture& aTexture) return true; } +SkBitmap SkiaCompatibleDC::getAsBitmap() +{ + SkBitmap tmpBitmap; + if (!tmpBitmap.installPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight, + kBGRA_8888_SkColorType, kUnpremul_SkAlphaType), + mpData, maRects.mnSrcWidth * 4)) + abort(); + SkBitmap bitmap; + if (!bitmap.tryAllocPixels(tmpBitmap.info())) + abort(); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + SkCanvas canvas(bitmap); + // The data we got is upside-down. + SkMatrix matrix; + matrix.preTranslate(0, maRects.mnSrcHeight); + matrix.setConcat(matrix, SkMatrix::MakeScale(1, -1)); + canvas.concat(matrix); + canvas.drawBitmapRect(tmpBitmap, + SkRect::MakeXYWH(0, 0, maRects.mnSrcWidth, maRects.mnSrcHeight), + SkRect::MakeXYWH(0, 0, maRects.mnSrcWidth, maRects.mnSrcHeight), &paint); + return bitmap; +} + +SkiaControlsCache::SkiaControlsCache() + : cache(200) +{ +} + +SkiaControlCacheType& SkiaControlsCache::get() +{ + SalData* data = GetSalData(); + if (!data->m_pSkiaControlsCache) + { + data->m_pSkiaControlsCache.reset(new SkiaControlsCache); + } + return data->m_pSkiaControlsCache->cache; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx index c0ec01595f9a..7c7bfc6e76e0 100644 --- a/vcl/win/app/salinst.cxx +++ b/vcl/win/app/salinst.cxx @@ -51,6 +51,7 @@ #include <vcl/skia/SkiaHelper.hxx> #if HAVE_FEATURE_SKIA #include <skia/salbmp.hxx> +#include <skia/win/gdiimpl.hxx> #endif #include <salsys.hxx> diff --git a/vcl/win/gdi/salnativewidgets-luna.cxx b/vcl/win/gdi/salnativewidgets-luna.cxx index d23601238892..ffba4b35ed85 100644 --- a/vcl/win/gdi/salnativewidgets-luna.cxx +++ b/vcl/win/gdi/salnativewidgets-luna.cxx @@ -1300,19 +1300,19 @@ bool WinSalGraphics::drawNativeControl( ControlType nType, } else { - // We can do OpenGL - OpenGLCompatibleDC 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)); + // 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)); - OpenGLCompatibleDC 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)); + 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)); - if (ImplDrawNativeControl(aBlackDC.getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr) && - ImplDrawNativeControl(aWhiteDC.getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr)) + if (ImplDrawNativeControl(aBlackDC->getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr) && + ImplDrawNativeControl(aWhiteDC->getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr)) { - bOk = pImpl->RenderAndCacheNativeControl(aWhiteDC, aBlackDC, cacheRect.Left(), cacheRect.Top(), aControlCacheKey); + bOk = pImpl->RenderAndCacheNativeControl(*aWhiteDC, *aBlackDC, cacheRect.Left(), cacheRect.Top(), aControlCacheKey); } } |