include/vcl/dropcache.hxx | 30 ++++++++++++++++ include/vcl/glyphitemcache.hxx | 6 ++- sc/source/ui/unoobj/shapeuno.cxx | 53 +++++++++++++++++++++-------- sc/source/ui/view/spellcheckcontext.cxx | 17 ++++++++- sw/source/core/ole/ndole.cxx | 48 ++++++++++++++++++-------- vcl/inc/graphic/Manager.hxx | 7 ++- vcl/inc/svdata.hxx | 5 ++ vcl/source/app/svapp.cxx | 5 -- vcl/source/app/svdata.cxx | 44 ++++++++++++++++++++++++ vcl/source/gdi/impglyphitem.cxx | 8 ++++ vcl/source/graphic/Manager.cxx | 2 - vcl/source/outdev/textline.cxx | 14 +++++++ vcl/source/text/TextLayoutCache.cxx | 51 ++++++++++++++++++++++----- vcl/unx/generic/fontmanager/fontconfig.cxx | 14 +++++++ vcl/unx/generic/gdi/cairotextrender.cxx | 35 +++++++++++++------ 15 files changed, 279 insertions(+), 60 deletions(-)
New commits: commit 3fc2216aa394222e7f3f4f0f4f78c5f198c694f5 Author: Caolán McNamara <caolan.mcnam...@collabora.com> AuthorDate: Sun May 25 20:42:45 2025 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri May 30 10:25:07 2025 +0200 register caches with ImplSVData and put them under a single trim control Change-Id: I72b53102e781f6b16968588b9066588d7fdb3055 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185796 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> diff --git a/include/vcl/dropcache.hxx b/include/vcl/dropcache.hxx new file mode 100644 index 000000000000..3a9854f203f9 --- /dev/null +++ b/include/vcl/dropcache.hxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#pragma once + +#include <vcl/dllapi.h> + +namespace rtl +{ +class OStringBuffer; +} + +class VCL_DLLPUBLIC CacheOwner +{ +protected: + CacheOwner(); + virtual ~CacheOwner(); + +public: + virtual void dropCaches() = 0; + virtual void dumpState(rtl::OStringBuffer& rState) = 0; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/include/vcl/glyphitemcache.hxx b/include/vcl/glyphitemcache.hxx index 4abcfb6e93c7..92e427fe1aed 100644 --- a/include/vcl/glyphitemcache.hxx +++ b/include/vcl/glyphitemcache.hxx @@ -25,6 +25,7 @@ #include <o3tl/lru_map.hxx> #include <vcl/glyphitem.hxx> +#include <vcl/dropcache.hxx> #include <vcl/metric.hxx> #include <vcl/outdev.hxx> #include <vcl/vclptr.hxx> @@ -38,7 +39,7 @@ Allows caching for OutputDevice::DrawText() and similar calls. Pass the text and for the call to OutputDevice::ImplLayout(). Items are cached per output device and its font. If something more changes, call clear(). */ -class VCL_DLLPUBLIC SalLayoutGlyphsCache final +class VCL_DLLPUBLIC SalLayoutGlyphsCache final : public CacheOwner { public: // NOTE: The lifetime of the returned value is guaranteed only until the next call @@ -95,6 +96,9 @@ public: }; private: + virtual void dropCaches() override; + virtual void dumpState(rtl::OStringBuffer& rState) override; + struct CachedGlyphsHash { size_t operator()(const CachedGlyphsKey& key) const { return key.hashValue; } diff --git a/sc/source/ui/unoobj/shapeuno.cxx b/sc/source/ui/unoobj/shapeuno.cxx index 4aabcf03ebe0..88d31031e7ba 100644 --- a/sc/source/ui/unoobj/shapeuno.cxx +++ b/sc/source/ui/unoobj/shapeuno.cxx @@ -25,6 +25,7 @@ #include <svtools/unoimap.hxx> #include <svx/svdobj.hxx> #include <svx/ImageMapInfo.hxx> +#include <vcl/dropcache.hxx> #include <vcl/svapp.hxx> #include <vcl/unohelp.hxx> #include <sfx2/event.hxx> @@ -212,6 +213,43 @@ static uno::Reference<text::XTextRange> lcl_GetTextRange( const uno::Reference<u return xRet; } +namespace { + +struct PropertySetInfoCache : public CacheOwner +{ + uno::Reference<beans::XPropertySetInfo> getPropertySetInfo(const uno::Reference<beans::XPropertySetInfo>& rxPropSetInfo) + { + std::unique_lock l(gCacheMutex); + // prevent memory leaks, possibly we could use an LRU map here. + if (gCacheMap.size() > 100) + gCacheMap.clear(); + auto it = gCacheMap.find(rxPropSetInfo); + if (it != gCacheMap.end()) + return it->second; + uno::Reference<beans::XPropertySetInfo> xCombined = new SfxExtItemPropertySetInfo( lcl_GetShapeMap(), rxPropSetInfo->getProperties() ); + gCacheMap.emplace(rxPropSetInfo, xCombined); + return xCombined; + } + +private: + virtual void dropCaches() override + { + std::unique_lock l(gCacheMutex); + gCacheMap.clear(); + } + + virtual void dumpState(rtl::OStringBuffer& rState) override + { + rState.append(" PropertySetInfoCache: "); + rState.append(static_cast<sal_Int32>(gCacheMap.size())); + } + + std::mutex gCacheMutex; + std::unordered_map<uno::Reference<beans::XPropertySetInfo>, uno::Reference<beans::XPropertySetInfo>> gCacheMap; +}; + +} + /** * If there are lots of shapes, the cost of allocating the XPropertySetInfo structures adds up. * But we have a static set of properties, and most of the underlying types have one static @@ -220,19 +258,8 @@ static uno::Reference<text::XTextRange> lcl_GetTextRange( const uno::Reference<u */ static uno::Reference<beans::XPropertySetInfo> getPropertySetInfoFromCache(const uno::Reference<beans::XPropertySetInfo>& rxPropSetInfo) { - static std::mutex gCacheMutex; - static std::unordered_map<uno::Reference<beans::XPropertySetInfo>, uno::Reference<beans::XPropertySetInfo>> gCacheMap; - - std::unique_lock l(gCacheMutex); - // prevent memory leaks, possibly we could use an LRU map here. - if (gCacheMap.size() > 100) - gCacheMap.clear(); - auto it = gCacheMap.find(rxPropSetInfo); - if (it != gCacheMap.end()) - return it->second; - uno::Reference<beans::XPropertySetInfo> xCombined = new SfxExtItemPropertySetInfo( lcl_GetShapeMap(), rxPropSetInfo->getProperties() ); - gCacheMap.emplace(rxPropSetInfo, xCombined); - return xCombined; + static PropertySetInfoCache aCache; + return aCache.getPropertySetInfo(rxPropSetInfo); } // XPropertySet diff --git a/sc/source/ui/view/spellcheckcontext.cxx b/sc/source/ui/view/spellcheckcontext.cxx index f3145855f8b5..23b0d1dfeb4b 100644 --- a/sc/source/ui/view/spellcheckcontext.cxx +++ b/sc/source/ui/view/spellcheckcontext.cxx @@ -12,6 +12,7 @@ #include <editeng/eeitem.hxx> #include <editeng/langitem.hxx> #include <editeng/unolingu.hxx> +#include <vcl/dropcache.hxx> #include <scitems.hxx> #include <document.hxx> @@ -29,7 +30,7 @@ using namespace css; using sc::SpellCheckContext; -class SpellCheckContext::SpellCheckCache +class SpellCheckContext::SpellCheckCache : public CacheOwner { struct CellPos { @@ -90,6 +91,20 @@ class SpellCheckContext::SpellCheckCache SharedStringMapType maStringMisspells; CellMapType maEditTextMisspells; + virtual void dropCaches() override + { + clear(); + } + + virtual void dumpState(rtl::OStringBuffer& rState) override + { + rState.append(" SpellCheckCache: "); + rState.append(" string misspells: "); + rState.append(static_cast<sal_Int32>(maStringMisspells.size())); + rState.append(" editeng misspells: "); + rState.append(static_cast<sal_Int32>(maEditTextMisspells.size())); + } + public: SpellCheckCache() diff --git a/sw/source/core/ole/ndole.cxx b/sw/source/core/ole/ndole.cxx index 20cef31053a3..5a8b57f5482a 100644 --- a/sw/source/core/ole/ndole.cxx +++ b/sw/source/core/ole/ndole.cxx @@ -33,6 +33,7 @@ #include <sfx2/linkmgr.hxx> #include <unotools/configitem.hxx> #include <utility> +#include <vcl/dropcache.hxx> #include <vcl/outdev.hxx> #include <fmtanchr.hxx> #include <frmfmt.hxx> @@ -70,6 +71,7 @@ namespace { class SwOLELRUCache : private utl::ConfigItem + , public CacheOwner { private: std::deque<SwOLEObj *> m_OleObjects; @@ -78,6 +80,19 @@ private: virtual void ImplCommit() override; + void tryShrinkCacheTo(sal_Int32 nVal); + + virtual void dropCaches() override + { + tryShrinkCacheTo(0); + } + + virtual void dumpState(rtl::OStringBuffer& rState) override + { + rState.append(" SwOLELRUCache: "); + rState.append(static_cast<sal_Int32>(m_OleObjects.size())); + } + public: SwOLELRUCache(); @@ -1305,6 +1320,23 @@ void SwOLELRUCache::ImplCommit() { } +void SwOLELRUCache::tryShrinkCacheTo(sal_Int32 nVal) +{ + // size of cache has been changed + sal_Int32 nCount = m_OleObjects.size(); + sal_Int32 nPos = nCount; + + // try to remove the last entries until new maximum size is reached + while( nCount > nVal ) + { + SwOLEObj *const pObj = m_OleObjects[ --nPos ]; + if ( pObj->UnloadObject() ) + nCount--; + if ( !nPos ) + break; + } +} + void SwOLELRUCache::Load() { Sequence< OUString > aNames( GetPropertyNames() ); @@ -1316,25 +1348,11 @@ void SwOLELRUCache::Load() sal_Int32 nVal = 0; *pValues >>= nVal; - if (nVal < m_nLRU_InitSize) { std::shared_ptr<SwOLELRUCache> xKeepAlive(g_pOLELRU_Cache); // prevent delete this - // size of cache has been changed - sal_Int32 nCount = m_OleObjects.size(); - sal_Int32 nPos = nCount; - - // try to remove the last entries until new maximum size is reached - while( nCount > nVal ) - { - SwOLEObj *const pObj = m_OleObjects[ --nPos ]; - if ( pObj->UnloadObject() ) - nCount--; - if ( !nPos ) - break; - } + tryShrinkCacheTo(nVal); } - m_nLRU_InitSize = nVal; } diff --git a/vcl/inc/graphic/Manager.hxx b/vcl/inc/graphic/Manager.hxx index cac1a24beecf..efef7f5ed683 100644 --- a/vcl/inc/graphic/Manager.hxx +++ b/vcl/inc/graphic/Manager.hxx @@ -11,6 +11,7 @@ #include <sal/types.h> #include <rtl/strbuf.hxx> +#include <vcl/dropcache.hxx> #include <vcl/timer.hxx> #include <memory> @@ -22,7 +23,7 @@ namespace vcl::graphic { class MemoryManaged; -class VCL_DLLPUBLIC MemoryManager final +class VCL_DLLPUBLIC MemoryManager final : public CacheOwner { private: o3tl::sorted_vector<MemoryManaged*> maObjectList; @@ -55,8 +56,8 @@ public: void checkStartReduceTimer(); void reduceMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll = false); void loopAndReduceMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll = false); - void reduceAllAndNow(); - void dumpState(rtl::OStringBuffer& rState); + virtual void dropCaches() override; + virtual void dumpState(rtl::OStringBuffer& rState) override; }; } // end namespace vcl::graphic diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx index c332894e1fc8..5ae6816dcb69 100644 --- a/vcl/inc/svdata.hxx +++ b/vcl/inc/svdata.hxx @@ -23,11 +23,13 @@ #include <o3tl/lru_map.hxx> #include <o3tl/hash_combine.hxx> +#include <o3tl/sorted_vector.hxx> #include <osl/conditn.hxx> #include <tools/fldunit.hxx> #include <unotools/options.hxx> #include <vcl/bitmapex.hxx> #include <vcl/cvtgrf.hxx> +#include <vcl/dropcache.hxx> #include <vcl/image.hxx> #include <vcl/settings.hxx> #include <vcl/svapp.hxx> @@ -422,6 +424,7 @@ struct ImplSVData css::uno::Reference< css::lang::XComponent > mxAccessBridge; std::unique_ptr<vcl::SettingsConfigItem> mpSettingsConfigItem; std::unordered_map< int, OUString > maPaperNames; + o3tl::sorted_vector<CacheOwner*> maCacheOwners; css::uno::Reference<css::i18n::XCharacterClassification> m_xCharClass; @@ -439,6 +442,8 @@ struct ImplSVData LibreOfficeKitWakeCallback mpWakeCallback = nullptr; void *mpPollClosure = nullptr; + void registerCacheOwner(CacheOwner&); + void deregisterCacheOwner(CacheOwner&); void dropCaches(); void dumpState(rtl::OStringBuffer &rState); }; diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx index 22e41ecd9bcf..59cf4c92db9c 100644 --- a/vcl/source/app/svapp.cxx +++ b/vcl/source/app/svapp.cxx @@ -1778,8 +1778,6 @@ void dumpState(rtl::OStringBuffer &rState) pWin = Application::GetNextTopLevelWindow( pWin ); } - vcl::graphic::MemoryManager::get().dumpState(rState); - pSVData->dumpState(rState); #ifndef NDEBUG @@ -1795,9 +1793,6 @@ void trimMemory(int nTarget) if (!pSVData) // shutting down return; pSVData->dropCaches(); - vcl::graphic::MemoryManager::get().reduceAllAndNow(); - // TODO: ideally - free up any deeper dirtied thread stacks. - // comphelper::ThreadPool::getSharedOptimalPool().shutdown(); } // else for now caches re-fill themselves as/when used. } diff --git a/vcl/source/app/svdata.cxx b/vcl/source/app/svdata.cxx index f767c2483925..303e01dbfca4 100644 --- a/vcl/source/app/svdata.cxx +++ b/vcl/source/app/svdata.cxx @@ -425,6 +425,16 @@ ImplSVData::ImplSVData() mpWinData = &private_aImplSVWinData::get(); } +void ImplSVData::registerCacheOwner(CacheOwner& rCacheOwner) +{ + maCacheOwners.insert(&rCacheOwner); +} + +void ImplSVData::deregisterCacheOwner(CacheOwner& rCacheOwner) +{ + maCacheOwners.erase(&rCacheOwner); +} + void ImplSVData::dropCaches() { // we are iterating over a map and doing erase while inside a loop which is doing erase @@ -434,6 +444,28 @@ void ImplSVData::dropCaches() maGDIData.maThemeDrawCommandsCache.clear(); maGDIData.maThemeImageCache.clear(); + mpBlendFrameCache.reset(); + + // copy, some caches self-delete on emptying, e.g. SwOLELRUCache + auto aCacheOwners = maCacheOwners; + for (CacheOwner* pCacheOwner : aCacheOwners) + pCacheOwner->dropCaches(); +} + +CacheOwner::CacheOwner() +{ + if (ImplSVData* pSVData = ImplGetSVData()) + { + pSVData->registerCacheOwner(*this); + return; + } + SAL_WARN("vcl.app", "Cache owner ctor before ImplSVData created. This is useless."); +} + +CacheOwner::~CacheOwner() +{ + if (ImplSVData* pSVData = ImplGetSVData()) + pSVData->deregisterCacheOwner(*this); } void ImplSVData::dumpState(rtl::OStringBuffer &rState) @@ -450,6 +482,18 @@ void ImplSVData::dumpState(rtl::OStringBuffer &rState) rState.append("x"); rState.append(static_cast<sal_Int32>(it->first.maDestSize.Height())); } + + if (mpBlendFrameCache) + { + rState.append(" BlendFrameCache:"); + rState.append(" "); + rState.append(static_cast<sal_Int32>(mpBlendFrameCache->m_aLastSize.Width())); + rState.append("x"); + rState.append(static_cast<sal_Int32>(mpBlendFrameCache->m_aLastSize.Height())); + } + + for (CacheOwner* pCacheOwner : maCacheOwners) + pCacheOwner->dumpState(rState); } ImplSVHelpData* CreateSVHelpData() diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx index 6001ccd0236b..78137c73370e 100644 --- a/vcl/source/gdi/impglyphitem.cxx +++ b/vcl/source/gdi/impglyphitem.cxx @@ -590,4 +590,12 @@ size_t SalLayoutGlyphsCache::GlyphsCost::operator()(const SalLayoutGlyphs& glyph return cost; } +void SalLayoutGlyphsCache::dropCaches() { clear(); } + +void SalLayoutGlyphsCache::dumpState(rtl::OStringBuffer& rState) +{ + rState.append(" SalLayoutGlyphsCache: "); + rState.append(static_cast<sal_Int32>(mCachedGlyphs.size())); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/graphic/Manager.cxx b/vcl/source/graphic/Manager.cxx index 3c765f039584..17f25cedec7c 100644 --- a/vcl/source/graphic/Manager.cxx +++ b/vcl/source/graphic/Manager.cxx @@ -119,7 +119,7 @@ void MemoryManager::swappedOut(MemoryManaged* pMemoryManaged, sal_Int64 nNewSize changeExisting(pMemoryManaged, nNewSize); } -void MemoryManager::reduceAllAndNow() +void MemoryManager::dropCaches() { std::unique_lock aGuard(maMutex); reduceMemory(aGuard, true); diff --git a/vcl/source/outdev/textline.cxx b/vcl/source/outdev/textline.cxx index 42ffa0613aa2..87a2591ab77c 100644 --- a/vcl/source/outdev/textline.cxx +++ b/vcl/source/outdev/textline.cxx @@ -25,6 +25,7 @@ #include <o3tl/lru_map.hxx> #include <comphelper/configuration.hxx> #include <tools/lazydelete.hxx> +#include <vcl/dropcache.hxx> #include <vcl/metaact.hxx> #include <vcl/settings.hxx> #include <vcl/virdev.hxx> @@ -40,7 +41,7 @@ #define STRIKEOUT_LAST STRIKEOUT_X namespace { - struct WavyLineCache final + struct WavyLineCache final : public CacheOwner { WavyLineCache () : m_aItems( 10 ) {} @@ -66,6 +67,17 @@ namespace { rOutput = aBitmap; } + virtual void dropCaches() override + { + m_aItems.clear(); + } + + virtual void dumpState(rtl::OStringBuffer& rState) override + { + rState.append(" WavyLineCache: "); + rState.append(static_cast<sal_Int32>(m_aItems.size())); + } + private: struct WavyLineCacheItem { diff --git a/vcl/source/text/TextLayoutCache.cxx b/vcl/source/text/TextLayoutCache.cxx index 3e3571dfc861..1a7c6ab521cf 100644 --- a/vcl/source/text/TextLayoutCache.cxx +++ b/vcl/source/text/TextLayoutCache.cxx @@ -23,9 +23,11 @@ #include <o3tl/hash_combine.hxx> #include <o3tl/lru_map.hxx> +#include <rtl/strbuf.hxx> #include <unotools/configmgr.hxx> #include <tools/lazydelete.hxx> #include <officecfg/Office/Common.hxx> +#include <vcl/dropcache.hxx> namespace vcl::text { @@ -48,25 +50,56 @@ struct TextLayoutCacheCost return item->runs.size() * sizeof(item->runs.front()); } }; -} // namespace -std::shared_ptr<const TextLayoutCache> TextLayoutCache::Create(OUString const& rString) +struct TextLayoutCacheMap : public CacheOwner { typedef o3tl::lru_map<OUString, std::shared_ptr<const TextLayoutCache>, FirstCharsStringHash, FastStringCompareEqual, TextLayoutCacheCost> Cache; - static tools::DeleteOnDeinit<Cache> cache( - !comphelper::IsFuzzing() ? officecfg::Office::Common::Cache::Font::TextRunsCacheSize::get() - : 100); - if (Cache* map = cache.get()) + + Cache cache; + + TextLayoutCacheMap(int capacity) + : cache(capacity) { - auto it = map->find(rString); - if (it != map->end()) + } + + std::shared_ptr<const TextLayoutCache> Create(OUString const& rString) + { + auto it = cache.find(rString); + if (it != cache.end()) return it->second; auto ret = std::make_shared<const TextLayoutCache>(rString.getStr(), rString.getLength()); - map->insert({ rString, ret }); + cache.insert({ rString, ret }); return ret; } + + virtual void dropCaches() override { cache.clear(); } + + virtual void dumpState(rtl::OStringBuffer& rState) override + { + rState.append(" TextLayoutCache: "); + rState.append(static_cast<sal_Int32>(cache.size())); + + TextLayoutCacheCost cost; + size_t nTotalCost = 0; + for (auto it = cache.begin(); it != cache.end(); ++it) + nTotalCost += cost(it->second); + + rState.append(" cost: "); + rState.append(static_cast<sal_Int64>(nTotalCost)); + } +}; + +} // namespace + +std::shared_ptr<const TextLayoutCache> TextLayoutCache::Create(OUString const& rString) +{ + static tools::DeleteOnDeinit<TextLayoutCacheMap> cache( + !comphelper::IsFuzzing() ? officecfg::Office::Common::Cache::Font::TextRunsCacheSize::get() + : 100); + if (TextLayoutCacheMap* map = cache.get()) + return map->Create(rString); return std::make_shared<const TextLayoutCache>(rString.getStr(), rString.getLength()); } } diff --git a/vcl/unx/generic/fontmanager/fontconfig.cxx b/vcl/unx/generic/fontmanager/fontconfig.cxx index 061e5256fc1c..80054e28bc7f 100644 --- a/vcl/unx/generic/fontmanager/fontconfig.cxx +++ b/vcl/unx/generic/fontmanager/fontconfig.cxx @@ -27,6 +27,7 @@ #include <unx/fontmanager.hxx> #include <unx/helper.hxx> #include <comphelper/sequence.hxx> +#include <vcl/dropcache.hxx> #include <vcl/svapp.hxx> #include <vcl/vclenum.hxx> #include <font/FontSelectPattern.hxx> @@ -113,7 +114,7 @@ struct FcPatternDeleter typedef std::unique_ptr<FcPattern, FcPatternDeleter> FcPatternUniquePtr; -class CachedFontConfigFontOptions +class CachedFontConfigFontOptions : public CacheOwner { private: o3tl::lru_map<FontOptionsKey, FcPatternUniquePtr> lru_options_cache; @@ -137,6 +138,17 @@ public: lru_options_cache.insert(std::make_pair(rKey, FcPatternUniquePtr(FcPatternDuplicate(pPattern)))); } +private: + virtual void dropCaches() override + { + lru_options_cache.clear(); + } + + virtual void dumpState(rtl::OStringBuffer& rState) override + { + rState.append(" CachedFontConfigFontOptions: "); + rState.append(static_cast<sal_Int32>(lru_options_cache.size())); + } }; typedef std::pair<FcChar8*, FcChar8*> lang_and_element; diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx index 9c201a2cc1ec..80110829d99a 100644 --- a/vcl/unx/generic/gdi/cairotextrender.cxx +++ b/vcl/unx/generic/gdi/cairotextrender.cxx @@ -43,7 +43,7 @@ namespace { typedef struct FT_FaceRec_* FT_Face; -class CairoFontsCache +class CairoFontsCache : public CacheOwner { public: struct CacheId @@ -62,16 +62,30 @@ public: }; private: - typedef std::deque< std::pair<cairo_font_face_t*, CacheId> > LRUFonts; - static LRUFonts maLRUFonts; -public: - CairoFontsCache() = delete; + typedef std::deque< std::pair<cairo_font_face_t*, CacheId> > LRUFonts; + LRUFonts maLRUFonts; + + virtual void dropCaches() override + { + maLRUFonts.clear(); + } + + virtual void dumpState(rtl::OStringBuffer& rState) override + { + rState.append(" CairoFontsCache: "); + rState.append(static_cast<sal_Int32>(maLRUFonts.size())); + } - static void CacheFont(cairo_font_face_t* pFont, const CacheId &rId); - static cairo_font_face_t* FindCachedFont(const CacheId &rId); +public: + void CacheFont(cairo_font_face_t* pFont, const CacheId &rId); + cairo_font_face_t* FindCachedFont(const CacheId &rId); }; -CairoFontsCache::LRUFonts CairoFontsCache::maLRUFonts; +CairoFontsCache& getCairoFontsCache() +{ + static CairoFontsCache aCache; + return aCache; +} void CairoFontsCache::CacheFont(cairo_font_face_t* pFont, const CairoFontsCache::CacheId &rId) { @@ -188,13 +202,14 @@ CairoTextRender::~CairoTextRender() static void ApplyFont(cairo_t* cr, const CairoFontsCache::CacheId& rId, double nWidth, double nHeight, int nGlyphRotation, const GenericSalLayout& rLayout) { - cairo_font_face_t* font_face = CairoFontsCache::FindCachedFont(rId); + CairoFontsCache& rCache = getCairoFontsCache(); + cairo_font_face_t* font_face = rCache.FindCachedFont(rId); if (!font_face) { const FontConfigFontOptions *pOptions = rId.mpOptions; FcPattern *pPattern = pOptions->GetPattern(); font_face = cairo_ft_font_face_create_for_pattern(pPattern); - CairoFontsCache::CacheFont(font_face, rId); + rCache.CacheFont(font_face, rId); } cairo_set_font_face(cr, font_face);