include/o3tl/lru_map.hxx | 141 ++++++++++++++++++ include/vcl/salnativewidgets.hxx | 42 +++++ o3tl/CppunitTest_o3tl_tests.mk | 1 o3tl/qa/test-lru_map.cxx | 239 +++++++++++++++++++++++++++++++ scp2/source/ooo/directory_ooo.scp | 5 scp2/source/ooo/file_extra_ooo.scp | 7 scp2/source/ooo/module_ooo.scp | 1 vcl/inc/opengl/x11/gdiimpl.hxx | 11 + vcl/inc/unx/salgdi.h | 6 vcl/inc/unx/x11/x11gdiimpl.h | 6 vcl/opengl/x11/gdiimpl.cxx | 95 ++++++++++-- vcl/unx/generic/gdi/gdiimpl.cxx | 11 + vcl/unx/generic/gdi/gdiimpl.hxx | 5 vcl/unx/generic/gdi/salgdi2.cxx | 15 + vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx | 23 +- 15 files changed, 587 insertions(+), 21 deletions(-)
New commits: commit 6c853a986444294dd937cd570a4dc0a31943e432 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> Date: Fri Jul 24 16:54:44 2015 +0900 Add "styles" template folder + content to installation Change-Id: Ibb674e17eedfc325d3e335aa074391ad7b2b2aa2 diff --git a/scp2/source/ooo/directory_ooo.scp b/scp2/source/ooo/directory_ooo.scp index 1337098..0f76c94 100644 --- a/scp2/source/ooo/directory_ooo.scp +++ b/scp2/source/ooo/directory_ooo.scp @@ -588,6 +588,11 @@ Directory gid_Dir_Template_Common_Presnt DosName = "presnt"; End +Directory gid_Dir_Template_Common_Styles + ParentID = gid_Dir_Template_Common; + DosName = "styles"; +End + Directory gid_Brand_Dir_Program_Services #if defined MACOSX ParentID = gid_Brand_Dir_Share; diff --git a/scp2/source/ooo/file_extra_ooo.scp b/scp2/source/ooo/file_extra_ooo.scp index c2cc985..f56c028 100644 --- a/scp2/source/ooo/file_extra_ooo.scp +++ b/scp2/source/ooo/file_extra_ooo.scp @@ -192,6 +192,13 @@ File gid_File_Extra_Tplpresnt Name = "extras_tplpresnt.filelist"; End +File gid_File_Extra_Tpl_styles + Dir = FILELIST_DIR; + TXT_FILE_BODY; + Styles = (FILELIST); + Name = "extras_tpl_styles.filelist"; +End + File gid_File_Extra_Tplpersonal Dir = FILELIST_DIR; TXT_FILE_BODY; diff --git a/scp2/source/ooo/module_ooo.scp b/scp2/source/ooo/module_ooo.scp index 50066d3..9acfbe8 100644 --- a/scp2/source/ooo/module_ooo.scp +++ b/scp2/source/ooo/module_ooo.scp @@ -80,6 +80,7 @@ Module gid_Module_Root gid_File_Extra_Tplofficorr, gid_File_Extra_Tploffimisc, gid_File_Extra_Tplpresnt, + gid_File_Extra_Tpl_styles, gid_File_Extra_Tplpersonal, gid_File_Extra_Tplwizbitmap, gid_File_Extra_Tplwizletter, commit 1c28c59f927361ef85c8aea8b575d274c532a34d Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> Date: Fri Jul 24 16:08:01 2015 +0900 opengl: don't cache checkboxes for now Change-Id: I67d0dcb48d1843587abbc1dc0f7da1f8057b281e diff --git a/vcl/opengl/x11/gdiimpl.cxx b/vcl/opengl/x11/gdiimpl.cxx index 2114419..bf5e6f6 100644 --- a/vcl/opengl/x11/gdiimpl.cxx +++ b/vcl/opengl/x11/gdiimpl.cxx @@ -238,8 +238,15 @@ bool X11OpenGLSalGraphicsImpl::RenderAndCacheNativeControl(X11Pixmap* pPixmap, X { std::unique_ptr<TextureCombo> pCombo(new TextureCombo); bool bResult = RenderPixmap(pPixmap, pMask, nX, nY, *pCombo); + if (!bResult) + return false; + + if (aControlCacheKey.mnType == CTRL_CHECKBOX) + return true; + ControlCachePair pair(aControlCacheKey, std::move(pCombo)); gTextureCache.insert(std::move(pair)); + return bResult; } commit 3bc00eca4acf9dfc3b2834077cee552f32c8f107 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> Date: Fri Jul 24 14:19:35 2015 +0900 Use LRU map for caching of native widgets Change-Id: Ia0423dac5309aabc5e81357cf4f67b5ee14bab31 diff --git a/vcl/opengl/x11/gdiimpl.cxx b/vcl/opengl/x11/gdiimpl.cxx index 3890b64..2114419 100644 --- a/vcl/opengl/x11/gdiimpl.cxx +++ b/vcl/opengl/x11/gdiimpl.cxx @@ -25,6 +25,8 @@ #include <vcl/opengl/OpenGLContext.hxx> #include <vcl/opengl/OpenGLHelper.hxx> +#include <o3tl/lru_map.hxx> + X11OpenGLSalGraphicsImpl::X11OpenGLSalGraphicsImpl( X11SalGraphics& rParent ): OpenGLSalGraphicsImpl(rParent,rParent.GetGeometryProvider()), mrParent(rParent) @@ -117,9 +119,10 @@ struct TextureCombo std::unique_ptr<OpenGLTexture> mpMask; }; -typedef std::unordered_map<ControlCacheKey, std::unique_ptr<TextureCombo>, ControlCacheHashFunction> ControlCacheType; +typedef typename std::pair<ControlCacheKey, std::unique_ptr<TextureCombo>> ControlCachePair; +typedef o3tl::lru_map<ControlCacheKey, std::unique_ptr<TextureCombo>, ControlCacheHashFunction> ControlCacheType; -ControlCacheType gTextureCache; +ControlCacheType gTextureCache(200); bool X11OpenGLSalGraphicsImpl::RenderPixmap(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, TextureCombo& rCombo) { @@ -235,7 +238,8 @@ bool X11OpenGLSalGraphicsImpl::RenderAndCacheNativeControl(X11Pixmap* pPixmap, X { std::unique_ptr<TextureCombo> pCombo(new TextureCombo); bool bResult = RenderPixmap(pPixmap, pMask, nX, nY, *pCombo); - gTextureCache[aControlCacheKey] = std::move(pCombo); + ControlCachePair pair(aControlCacheKey, std::move(pCombo)); + gTextureCache.insert(std::move(pair)); return bResult; } commit 80a92134806a876287818530eb61c6bb536a05f9 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> Date: Fri Jul 24 13:39:22 2015 +0900 LRU map (cache) implementation to o3tl + tests Change-Id: I6b1a39918e6c8c67712be2c8e9907266dcfefedb diff --git a/include/o3tl/lru_map.hxx b/include/o3tl/lru_map.hxx new file mode 100644 index 0000000..6d3b725 --- /dev/null +++ b/include/o3tl/lru_map.hxx @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_O3TL_LRU_MAP_HXX +#define INCLUDED_O3TL_LRU_MAP_HXX + +#include <list> +#include <unordered_map> + +namespace o3tl +{ + +/** LRU map + * + * Similar to unordered_map (it actually uses it) with additionaly functionality + * which removes the entries that have been "least recently used" when the size + * hits the specified capacity. + * + * It only implements the minimal methods needed and the implementation is NOT + * thread safe. + * + * The implementation is as simple as possible but it still uses O(1) complexity + * for most of the operations with a combination unordered map and linked list. + * + **/ +template<typename Key, typename Value, class KeyHash = std::hash<Key>> +class lru_map SAL_FINAL +{ +private: + typedef typename std::pair<Key, Value> key_value_pair_t; + typedef std::list<key_value_pair_t> list_t; + typedef typename list_t::iterator list_iterator_t; + typedef typename list_t::const_iterator list_const_iterator_t; + + typedef std::unordered_map<Key, list_iterator_t, KeyHash> map_t; + typedef typename map_t::iterator map_iterator_t; + typedef typename map_t::const_iterator map_const_iterator_t; + + list_t mLruList; + map_t mLruMap; + const size_t mMaxSize; + + inline void checkLRU() + { + if (mLruMap.size() > mMaxSize) + { + // remove from map + mLruMap.erase(mLruList.back().first); + // remove from list + mLruList.pop_back(); + } + } +public: + typedef list_iterator_t iterator; + typedef list_const_iterator_t const_iterator; + + lru_map(size_t nMaxSize) + : mMaxSize(nMaxSize) + {} + + void insert(key_value_pair_t& rPair) + { + map_iterator_t iterator = mLruMap.find(rPair.first); + + if (iterator == mLruMap.end()) // doesn't exist -> add to queue and map + { + // add to front of the list + mLruList.push_front(rPair); + // add the list position (iterator) to the map + mLruMap[rPair.first] = mLruList.begin(); + checkLRU(); + } + else // already exists -> replace value + { + // replace value + iterator->second->second = rPair.second; + // bring to front of the lru list + mLruList.splice(mLruList.begin(), mLruList, iterator->second); + } + } + + void insert(key_value_pair_t&& rPair) + { + map_iterator_t iterator = mLruMap.find(rPair.first); + + if (iterator == mLruMap.end()) // doesn't exist -> add to list and map + { + // add to front of the list + mLruList.push_front(std::move(rPair)); + // add the list position (iterator) to the map + mLruMap[rPair.first] = mLruList.begin(); + checkLRU(); + } + else // already exists -> replace value + { + // replace value + iterator->second->second = std::move(rPair.second); + // push to back of the lru list + mLruList.splice(mLruList.begin(), mLruList, iterator->second); + } + } + + const list_const_iterator_t find(const Key& key) + { + const map_iterator_t iterator = mLruMap.find(key); + if (iterator == mLruMap.cend()) // can't find entry for the key + { + // return empty iterator + return mLruList.cend(); + } + else + { + // push to back of the lru list + mLruList.splice(mLruList.begin(), mLruList, iterator->second); + return iterator->second; + } + } + + const list_const_iterator_t end() const + { + return mLruList.end(); + } + + size_t size() const + { + return mLruList.size(); + } +}; + +} + +#endif /* INCLUDED_O3TL_LRU_MAP_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/o3tl/CppunitTest_o3tl_tests.mk b/o3tl/CppunitTest_o3tl_tests.mk index 66f2951..c8f8f6b 100644 --- a/o3tl/CppunitTest_o3tl_tests.mk +++ b/o3tl/CppunitTest_o3tl_tests.mk @@ -33,6 +33,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,o3tl_tests,\ o3tl/qa/test-vector_pool \ o3tl/qa/test-sorted_vector \ o3tl/qa/test-typed_flags \ + o3tl/qa/test-lru_map \ )) # vim: set noet sw=4: diff --git a/o3tl/qa/test-lru_map.cxx b/o3tl/qa/test-lru_map.cxx new file mode 100644 index 0000000..d9428e3 --- /dev/null +++ b/o3tl/qa/test-lru_map.cxx @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include <sal/types.h> +#include "cppunit/TestAssert.h" +#include "cppunit/TestFixture.h" +#include "cppunit/extensions/HelperMacros.h" + +#include <o3tl/lru_map.hxx> + +#include <boost/functional/hash.hpp> + +using namespace ::o3tl; + +class lru_map_test : public CppUnit::TestFixture +{ +public: + void testBaseUsage(); + void testReplaceKey(); + void testReplaceValue(); + void testLruRemoval(); + void testCustomHash(); + + CPPUNIT_TEST_SUITE(lru_map_test); + CPPUNIT_TEST(testBaseUsage); + CPPUNIT_TEST(testReplaceKey); + CPPUNIT_TEST(testReplaceValue); + CPPUNIT_TEST(testLruRemoval); + CPPUNIT_TEST(testCustomHash); + CPPUNIT_TEST_SUITE_END(); +}; + +void lru_map_test::testBaseUsage() +{ + o3tl::lru_map<int, int> lru(10); + lru.insert(std::make_pair<int, int>(1, 1)); + + std::pair<int, int> pair; + for (int i = 2; i < 7; i++) + { + pair.first = pair.second = i; + lru.insert(pair); + } + + CPPUNIT_ASSERT_EQUAL(size_t(6), lru.size()); + + o3tl::lru_map<int, int>::const_iterator it; + + it = lru.find(2); + CPPUNIT_ASSERT(it != lru.end()); + CPPUNIT_ASSERT_EQUAL(2, it->second); + + it = lru.find(5); + CPPUNIT_ASSERT(it != lru.end()); + CPPUNIT_ASSERT_EQUAL(5, it->second); + + it = lru.find(0); + CPPUNIT_ASSERT(it == lru.end()); +} + +void lru_map_test::testReplaceValue() +{ + o3tl::lru_map<int, int> lru(2); + // check if map is empty + CPPUNIT_ASSERT_EQUAL(size_t(0), lru.size()); + + // check if inserting entry with with same key replaces the value + + // inserting new entry + lru.insert(std::make_pair<int, int>(1, 2)); + CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size()); + CPPUNIT_ASSERT_EQUAL(2, lru.find(1)->second); + + // inserting new entry with key that alreay exists + lru.insert(std::make_pair<int, int>(1, 4)); + CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size()); + CPPUNIT_ASSERT_EQUAL(4, lru.find(1)->second); + + // inserting new entry + lru.insert(std::make_pair<int, int>(2, 200)); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + CPPUNIT_ASSERT_EQUAL(4, lru.find(1)->second); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + + // check if insert with same key, moves the entry back of the lru queu + + // inserting new entry with key that alreay exists + lru.insert(std::make_pair<int, int>(1, 6)); + // inserting new entry, lru removed + lru.insert(std::make_pair<int, int>(3, 300)); + + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + CPPUNIT_ASSERT_EQUAL(6, lru.find(1)->second); + CPPUNIT_ASSERT_EQUAL(300, lru.find(3)->second); + +} + +void lru_map_test::testReplaceKey() +{ + o3tl::lru_map<int, int> lru(2); + + // inserting new entry + lru.insert(std::make_pair<int, int>(1, 100)); + CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size()); + CPPUNIT_ASSERT_EQUAL(100, lru.find(1)->second); + CPPUNIT_ASSERT(lru.find(2) == lru.end()); + CPPUNIT_ASSERT(lru.find(3) == lru.end()); + + // inserting new entry + lru.insert(std::make_pair<int, int>(2, 200)); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + CPPUNIT_ASSERT_EQUAL(100, lru.find(1)->second); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + CPPUNIT_ASSERT(lru.find(3) == lru.end()); + + // inserting new entry, lru entry is removed + lru.insert(std::make_pair<int, int>(3, 300)); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + CPPUNIT_ASSERT(lru.find(1) == lru.end()); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + CPPUNIT_ASSERT_EQUAL(300, lru.find(3)->second); + + // inserting new entry, lru entry is removed + std::pair<int, int> pair(4, 400); + lru.insert(pair); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + CPPUNIT_ASSERT(lru.find(1) == lru.end()); + CPPUNIT_ASSERT(lru.find(2) == lru.end()); + CPPUNIT_ASSERT_EQUAL(300, lru.find(3)->second); + CPPUNIT_ASSERT_EQUAL(400, lru.find(4)->second); +} + +void lru_map_test::testLruRemoval() +{ + o3tl::lru_map<int, int> lru(5); + CPPUNIT_ASSERT_EQUAL(size_t(0), lru.size()); + + // fill up.. + lru.insert(std::make_pair<int, int>(1, 100)); + lru.insert(std::make_pair<int, int>(2, 200)); + lru.insert(std::make_pair<int, int>(3, 300)); + lru.insert(std::make_pair<int, int>(4, 400)); + lru.insert(std::make_pair<int, int>(5, 500)); + CPPUNIT_ASSERT_EQUAL(size_t(5), lru.size()); + CPPUNIT_ASSERT_EQUAL(100, lru.find(1)->second); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + CPPUNIT_ASSERT_EQUAL(300, lru.find(3)->second); + CPPUNIT_ASSERT_EQUAL(400, lru.find(4)->second); + CPPUNIT_ASSERT_EQUAL(500, lru.find(5)->second); + + // add one more entry - lru entry should be removed + lru.insert(std::make_pair<int, int>(6, 600)); + + CPPUNIT_ASSERT_EQUAL(size_t(5), lru.size()); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + CPPUNIT_ASSERT_EQUAL(300, lru.find(3)->second); + CPPUNIT_ASSERT_EQUAL(400, lru.find(4)->second); + CPPUNIT_ASSERT_EQUAL(500, lru.find(5)->second); + CPPUNIT_ASSERT_EQUAL(600, lru.find(6)->second); + + // access the lru entry to put it at the back of the lru queue + lru.find(2); + // add new entry - lru entry should be removed + lru.insert(std::make_pair<int, int>(7, 700)); + + CPPUNIT_ASSERT_EQUAL(size_t(5), lru.size()); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + CPPUNIT_ASSERT_EQUAL(400, lru.find(4)->second); + CPPUNIT_ASSERT_EQUAL(500, lru.find(5)->second); + CPPUNIT_ASSERT_EQUAL(600, lru.find(6)->second); + CPPUNIT_ASSERT_EQUAL(700, lru.find(7)->second); +} + +struct TestClassKey +{ + int mA; + int mB; + + TestClassKey(int a, int b) + : mA(a) + , mB(b) + {} + + bool operator==(TestClassKey const& aOther) const + { + return mA == aOther.mA + && mB == aOther.mB; + } +}; + +struct TestClassKeyHashFunction +{ + std::size_t operator()(TestClassKey const& aKey) const + { + std::size_t seed = 0; + boost::hash_combine(seed, aKey.mA); + boost::hash_combine(seed, aKey.mB); + return seed; + } +}; + +void lru_map_test::testCustomHash() +{ + // check lru_map with custom hash function + o3tl::lru_map<TestClassKey, int, TestClassKeyHashFunction> lru(2); + CPPUNIT_ASSERT_EQUAL(size_t(0), lru.size()); + + lru.insert(std::make_pair<TestClassKey, int>(TestClassKey(1,1), 2)); + CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size()); + + lru.insert(std::make_pair<TestClassKey, int>(TestClassKey(1,1), 7)); + CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size()); + + lru.insert(std::make_pair<TestClassKey, int>(TestClassKey(1,2), 9)); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + + CPPUNIT_ASSERT(lru.end() == lru.find(TestClassKey(0,0))); // non existent + CPPUNIT_ASSERT_EQUAL(7, lru.find(TestClassKey(1,1))->second); + CPPUNIT_ASSERT_EQUAL(9, lru.find(TestClassKey(1,2))->second); + + lru.insert(std::make_pair<TestClassKey, int>(TestClassKey(2,1), 13)); + + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + + CPPUNIT_ASSERT(lru.end() == lru.find(TestClassKey(1,1))); + CPPUNIT_ASSERT_EQUAL(9, lru.find(TestClassKey(1,2))->second); + CPPUNIT_ASSERT_EQUAL(13, lru.find(TestClassKey(2,1))->second); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(lru_map_test); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 450727fdffa4a0dc3b2d4e635a5c1bc0411b3c36 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> Date: Thu Jul 23 19:15:20 2015 +0900 tdf#92018 cache native controls for X11 OpenGL backend (for now) Change-Id: I85c7cc01113bc4ac810c450a6460059463cc8e03 diff --git a/include/vcl/salnativewidgets.hxx b/include/vcl/salnativewidgets.hxx index 5177efe..8118b29 100644 --- a/include/vcl/salnativewidgets.hxx +++ b/include/vcl/salnativewidgets.hxx @@ -25,6 +25,8 @@ #include <tools/gen.hxx> #include <o3tl/typed_flags_set.hxx> +#include <boost/functional/hash.hpp> + /* Control Types: * * Specify the overall, whole control @@ -254,6 +256,46 @@ namespace o3tl template<> struct typed_flags<ControlState> : is_typed_flags<ControlState, 0xc007f> {}; } +class ControlCacheKey +{ +public: + ControlType mnType; + ControlPart mnPart; + ControlState mnState; + Size maSize; + + ControlCacheKey(ControlType nType, ControlPart nPart, ControlState nState, const Size& rSize) + : mnType(nType) + , mnPart(nPart) + , mnState(nState) + , maSize(rSize) + {} + + bool operator==(ControlCacheKey const& aOther) const + { + return mnType == aOther.mnType + && mnPart == aOther.mnPart + && mnState == aOther.mnState + && maSize.Width() == aOther.maSize.Width() + && maSize.Height() == aOther.maSize.Height(); + } +}; + +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; + } +}; + + /* ButtonValue: * * Identifies the tri-state value options diff --git a/vcl/inc/opengl/x11/gdiimpl.hxx b/vcl/inc/opengl/x11/gdiimpl.hxx index feb3961..9e2ece3 100644 --- a/vcl/inc/opengl/x11/gdiimpl.hxx +++ b/vcl/inc/opengl/x11/gdiimpl.hxx @@ -16,6 +16,8 @@ #include "unx/x11/x11gdiimpl.h" #include "openglgdiimpl.hxx" +class TextureCombo; + class VCL_PLUGIN_PUBLIC X11OpenGLSalGraphicsImpl : public OpenGLSalGraphicsImpl, public X11GraphicsImpl { private: @@ -29,6 +31,8 @@ protected: virtual OpenGLContext* CreateWinContext() SAL_OVERRIDE; virtual bool UseContext( OpenGLContext* pContext ) SAL_OVERRIDE; + bool RenderPixmap(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, TextureCombo& rCombo); + public: // implementation of X11GraphicsImpl @@ -37,7 +41,12 @@ public: virtual void Init() SAL_OVERRIDE; bool FillPixmapFromScreen( X11Pixmap* pPixmap, int nX, int nY ) SAL_OVERRIDE; - bool RenderPixmapToScreen( X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY ) SAL_OVERRIDE; + bool RenderPixmapToScreen(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY) SAL_OVERRIDE; + + bool RenderAndCacheNativeControl(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, + ControlCacheKey& aControlCacheKey) SAL_OVERRIDE; + bool TryRenderCachedNativeControl(ControlCacheKey& rControlCacheKey, + int nX, int nY) SAL_OVERRIDE; }; #endif // INCLUDED_VCL_INC_OPENGL_X11_GDIIMPL_HXX diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h index 99fe40d..3e80153 100644 --- a/vcl/inc/unx/salgdi.h +++ b/vcl/inc/unx/salgdi.h @@ -267,6 +267,12 @@ public: virtual void BeginPaint() SAL_OVERRIDE; virtual void EndPaint() SAL_OVERRIDE; + bool TryRenderCachedNativeControl(ControlCacheKey& aControlCacheKey, + int nX, int nY); + + bool RenderAndCacheNativeControl(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, + ControlCacheKey& aControlCacheKey); + // fill a pixmap from a screen region bool FillPixmapFromScreen( X11Pixmap* pPixmap, int nX, int nY ); diff --git a/vcl/inc/unx/x11/x11gdiimpl.h b/vcl/inc/unx/x11/x11gdiimpl.h index 22859c3..c504364 100644 --- a/vcl/inc/unx/x11/x11gdiimpl.h +++ b/vcl/inc/unx/x11/x11gdiimpl.h @@ -12,6 +12,8 @@ #include "unx/pixmap.hxx" +class ControlCacheKey; + class X11GraphicsImpl { public: @@ -19,6 +21,10 @@ public: virtual bool FillPixmapFromScreen( X11Pixmap* pPixmap, int nX, int nY ) = 0; virtual bool RenderPixmapToScreen( X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY ) = 0; + + virtual bool TryRenderCachedNativeControl(ControlCacheKey& rControlCacheKey, int nX, int nY) = 0; + virtual bool RenderAndCacheNativeControl(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, + ControlCacheKey& aControlCacheKey) = 0; }; #endif // INCLUDED_VCL_INC_UNX_X11_X11GDIIMPL_HXX diff --git a/vcl/opengl/x11/gdiimpl.cxx b/vcl/opengl/x11/gdiimpl.cxx index 1d453da..3890b64 100644 --- a/vcl/opengl/x11/gdiimpl.cxx +++ b/vcl/opengl/x11/gdiimpl.cxx @@ -111,18 +111,28 @@ bool X11OpenGLSalGraphicsImpl::FillPixmapFromScreen( X11Pixmap* pPixmap, int nX, return true; } -bool X11OpenGLSalGraphicsImpl::RenderPixmapToScreen( X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY ) +struct TextureCombo +{ + std::unique_ptr<OpenGLTexture> mpTexture; + std::unique_ptr<OpenGLTexture> mpMask; +}; + +typedef std::unordered_map<ControlCacheKey, std::unique_ptr<TextureCombo>, ControlCacheHashFunction> ControlCacheType; + +ControlCacheType gTextureCache; + +bool X11OpenGLSalGraphicsImpl::RenderPixmap(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, TextureCombo& rCombo) { - const int aAttribs[] = { + const int aAttribs[] = + { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, None }; + Display* pDisplay = mrParent.GetXDisplay(); bool bInverted; - SAL_INFO( "vcl.opengl", "RenderPixmapToScreen (" << nX << " " << nY << ")" ); - const long nWidth = pPixmap->GetWidth(); const long nHeight = pPixmap->GetHeight(); SalTwoRect aPosAry(0, 0, nWidth, nHeight, nX, nY, nWidth, nHeight); @@ -145,27 +155,28 @@ bool X11OpenGLSalGraphicsImpl::RenderPixmapToScreen( X11Pixmap* pPixmap, X11Pixm //TODO: lfrb: glXGetProc to get the functions - OpenGLTexture aTexture( pPixmap->GetWidth(), pPixmap->GetHeight(), false ); + rCombo.mpTexture.reset(new OpenGLTexture(pPixmap->GetWidth(), pPixmap->GetHeight(), false)); + glActiveTexture( GL_TEXTURE0 ); - aTexture.Bind(); + rCombo.mpTexture->Bind(); glXBindTexImageEXT( pDisplay, pGlxPixmap, GLX_FRONT_LEFT_EXT, NULL ); - aTexture.Unbind(); + rCombo.mpTexture->Unbind(); if( pMask != NULL && pGlxMask ) { - OpenGLTexture aMaskTexture( pMask->GetWidth(), pMask->GetHeight(), false ); - aMaskTexture.Bind(); + rCombo.mpMask.reset(new OpenGLTexture(pPixmap->GetWidth(), pPixmap->GetHeight(), false)); + rCombo.mpMask->Bind(); glXBindTexImageEXT( pDisplay, pGlxMask, GLX_FRONT_LEFT_EXT, NULL ); - aMaskTexture.Unbind(); + rCombo.mpMask->Unbind(); - DrawTextureDiff( aTexture, aMaskTexture, aPosAry, bInverted ); + DrawTextureDiff(*rCombo.mpTexture, *rCombo.mpMask, aPosAry, bInverted); glXReleaseTexImageEXT( pDisplay, pGlxMask, GLX_FRONT_LEFT_EXT ); glXDestroyPixmap( pDisplay, pGlxMask ); } else { - DrawTexture( aTexture, aPosAry, bInverted ); + DrawTexture(*rCombo.mpTexture, aPosAry, bInverted); } CHECK_GL_ERROR(); @@ -176,7 +187,56 @@ bool X11OpenGLSalGraphicsImpl::RenderPixmapToScreen( X11Pixmap* pPixmap, X11Pixm PostDraw(); CHECK_GL_ERROR(); + return true; } +bool X11OpenGLSalGraphicsImpl::RenderPixmapToScreen( X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY ) +{ + SAL_INFO( "vcl.opengl", "RenderPixmapToScreen (" << nX << " " << nY << ")" ); + + TextureCombo aCombo; + return RenderPixmap(pPixmap, pMask, nX, nY, aCombo); +} + +bool X11OpenGLSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey& rControlCacheKey, int nX, int nY) +{ + static bool gbCacheEnabled = !getenv("SAL_WITHOUT_WIDGET_CACHE"); + + if (!gbCacheEnabled) + return false; + + ControlCacheType::const_iterator iterator = gTextureCache.find(rControlCacheKey); + + if (iterator == gTextureCache.end()) + return false; + + const std::unique_ptr<TextureCombo>& pCombo = iterator->second; + + PreDraw(); + + OpenGLTexture& rTexture = *pCombo->mpTexture; + + SalTwoRect aPosAry(0, 0, rTexture.GetWidth(), rTexture.GetHeight(), + nX, nY, rTexture.GetWidth(), rTexture.GetHeight()); + + if (pCombo->mpMask) + DrawTextureDiff(rTexture, *pCombo->mpMask, aPosAry, true); + else + DrawTexture(rTexture, aPosAry, true); + + PostDraw(); + + return true; +} + +bool X11OpenGLSalGraphicsImpl::RenderAndCacheNativeControl(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, + ControlCacheKey& aControlCacheKey) +{ + std::unique_ptr<TextureCombo> pCombo(new TextureCombo); + bool bResult = RenderPixmap(pPixmap, pMask, nX, nY, *pCombo); + gTextureCache[aControlCacheKey] = std::move(pCombo); + return bResult; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/gdiimpl.cxx b/vcl/unx/generic/gdi/gdiimpl.cxx index 7a2beb1..d350d01 100644 --- a/vcl/unx/generic/gdi/gdiimpl.cxx +++ b/vcl/unx/generic/gdi/gdiimpl.cxx @@ -212,6 +212,17 @@ bool X11SalGraphicsImpl::RenderPixmapToScreen( X11Pixmap* pPixmap, X11Pixmap* /* return true; } +bool X11SalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey& /*rControlCacheKey*/, int /*nX*/, int /*nY*/) +{ + return false; +} + +bool X11SalGraphicsImpl::RenderAndCacheNativeControl(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, + ControlCacheKey& /*rControlCacheKey*/) +{ + return RenderPixmapToScreen(pPixmap, pMask, nX, nY); +} + XID X11SalGraphicsImpl::GetXRenderPicture() { XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); diff --git a/vcl/unx/generic/gdi/gdiimpl.hxx b/vcl/unx/generic/gdi/gdiimpl.hxx index f5df99c..3059dc4 100644 --- a/vcl/unx/generic/gdi/gdiimpl.hxx +++ b/vcl/unx/generic/gdi/gdiimpl.hxx @@ -279,6 +279,11 @@ public: void Init() SAL_OVERRIDE; bool FillPixmapFromScreen( X11Pixmap* pPixmap, int nX, int nY ) SAL_OVERRIDE; bool RenderPixmapToScreen( X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY ) SAL_OVERRIDE; + + virtual bool TryRenderCachedNativeControl(ControlCacheKey& rControlCacheKey, + int nX, int nY) SAL_OVERRIDE; + virtual bool RenderAndCacheNativeControl(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, + ControlCacheKey& aControlCacheKey) SAL_OVERRIDE; }; #endif diff --git a/vcl/unx/generic/gdi/salgdi2.cxx b/vcl/unx/generic/gdi/salgdi2.cxx index b98d9b6..629cf88 100644 --- a/vcl/unx/generic/gdi/salgdi2.cxx +++ b/vcl/unx/generic/gdi/salgdi2.cxx @@ -89,6 +89,21 @@ bool X11SalGraphics::RenderPixmapToScreen( X11Pixmap* pPixmap, X11Pixmap* pMask, return rImpl.RenderPixmapToScreen( pPixmap, pMask, nX, nY ); } +bool X11SalGraphics::TryRenderCachedNativeControl(ControlCacheKey& rControlCacheKey, int nX, int nY) +{ + SAL_INFO( "vcl", "TryRenderCachedNativeControl" ); + X11GraphicsImpl& rImpl = dynamic_cast<X11GraphicsImpl&>(*mxImpl.get()); + return rImpl.TryRenderCachedNativeControl(rControlCacheKey, nX, nY); +} + +bool X11SalGraphics::RenderAndCacheNativeControl(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, + ControlCacheKey& rControlCacheKey) +{ + SAL_INFO( "vcl", "RenderAndCachePixmap" ); + X11GraphicsImpl& rImpl = dynamic_cast<X11GraphicsImpl&>(*mxImpl.get()); + return rImpl.RenderAndCacheNativeControl(pPixmap, pMask, nX, nY, rControlCacheKey); +} + extern "C" { static Bool GraphicsExposePredicate( Display*, XEvent* pEvent, XPointer pFrameWindow ) diff --git a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx index 9da1bfa..6a07683 100644 --- a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx +++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx @@ -896,12 +896,23 @@ bool GtkSalGraphics::drawNativeControl(ControlType nType, ControlPart nPart, if( aClipRegion.IsNull() ) aClipRegion = aCtrlRect; + Rectangle aPixmapRect; + + // make pixmap a little larger since some themes draw decoration + // outside the rectangle, see e.g. checkbox + aPixmapRect = Rectangle(Point( aCtrlRect.Left()-1, aCtrlRect.Top()-1 ), + Size( aCtrlRect.GetWidth()+2, aCtrlRect.GetHeight()+2) ); + + ControlCacheKey aControlCacheKey(nType, nPart, nState, aPixmapRect.GetSize()); + if (TryRenderCachedNativeControl(aControlCacheKey, aPixmapRect.Left(), aPixmapRect.Top())) + return true; + clipList aClip; int nPasses = 0; GdkDrawable* gdkDrawable[2]; std::unique_ptr<GdkX11Pixmap> xPixmap; std::unique_ptr<GdkX11Pixmap> xMask; - Rectangle aPixmapRect; + if ((bNeedPixmapPaint || (nState & ControlState::DOUBLEBUFFERING)) && nType != CTRL_SCROLLBAR && nType != CTRL_SPINBOX @@ -911,11 +922,6 @@ bool GtkSalGraphics::drawNativeControl(ControlType nType, ControlPart nPart, && ! (nType == CTRL_TOOLBAR && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) ) ) { - // make pixmap a little larger since some themes draw decoration - // outside the rectangle, see e.g. checkbox - aPixmapRect = Rectangle( Point( aCtrlRect.Left()-1, aCtrlRect.Top()-1 ), - Size( aCtrlRect.GetWidth()+2, aCtrlRect.GetHeight()+2) ); - if( bNeedTwoPasses ) { xPixmap.reset( NWGetPixmapFromScreen( aPixmapRect, BG_WHITE ) ); @@ -969,7 +975,9 @@ bool GtkSalGraphics::drawNativeControl(ControlType nType, ControlPart nPart, } if( xPixmap ) - returnVal = NWRenderPixmapToScreen( xPixmap.get(), xMask.get(), aPixmapRect) && returnVal; + returnVal = returnVal && RenderAndCacheNativeControl(xPixmap.get(), xMask.get(), + aPixmapRect.Left(), aPixmapRect.Top(), + aControlCacheKey); return returnVal; } @@ -4250,7 +4258,6 @@ GdkX11Pixmap* GtkSalGraphics::NWGetPixmapFromScreen( Rectangle srcRect, int nBgC { GdkX11Pixmap* pPixmap; int nDepth = vcl_sal::getSalDisplay(GetGenericData())->GetVisual( m_nXScreen ).GetDepth(); -; pPixmap = new GdkX11Pixmap( srcRect.GetWidth(), srcRect.GetHeight(), nDepth );
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits