summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2019-10-31 11:47:18 +0100
committerLuboš Luňák <l.lunak@collabora.com>2019-11-27 09:55:13 +0100
commit31b2c10484fc265ff0f05ce405c2ed5b982f8714 (patch)
treec2417156e30bff34610ca49943a73794d21adea4
parent840f55c0f6e21d00b51e4a52824c7eb7f938122f (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.hxx15
-rw-r--r--vcl/inc/opengl/win/gdiimpl.hxx26
-rw-r--r--vcl/inc/skia/win/gdiimpl.hxx19
-rw-r--r--vcl/inc/win/saldata.hxx6
-rw-r--r--vcl/opengl/win/gdiimpl.cxx18
-rw-r--r--vcl/skia/win/gdiimpl.cxx85
-rw-r--r--vcl/win/app/salinst.cxx1
-rw-r--r--vcl/win/gdi/salnativewidgets-luna.cxx20
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);
}
}