diff options
author | Noel Grandin <noel@peralex.com> | 2021-08-28 18:53:07 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2021-08-31 14:26:46 +0200 |
commit | bb5425ed3d8cc04e4242059a17912752d6b48c53 (patch) | |
tree | 4d6b2e92939a26a0a94499cc83a7764104fd5ce3 /sw | |
parent | eae0636311d3a1b3a1af58a3e4df686b55afa3fa (diff) |
tdf#135683 speed up writer layout cache access
can be hot, so use a std::unordered_map
Change-Id: I70e34e80cad67536414c71facbe0222dd88c65a7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121208
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/source/core/inc/fntcache.hxx | 35 | ||||
-rw-r--r-- | sw/source/core/txtnode/fntcache.cxx | 77 |
2 files changed, 55 insertions, 57 deletions
diff --git a/sw/source/core/inc/fntcache.hxx b/sw/source/core/inc/fntcache.hxx index ab5c6a9e473b..0bdc4757d9b3 100644 --- a/sw/source/core/inc/fntcache.hxx +++ b/sw/source/core/inc/fntcache.hxx @@ -23,7 +23,7 @@ #include <sal/config.h> #include <cstdint> -#include <map> +#include <unordered_map> #include <vcl/font.hxx> #include <vcl/vclptr.hxx> @@ -60,9 +60,34 @@ void SwClearFntCacheTextGlyphs(); extern SwFntCache *pFntCache; extern SwFntObj *pLastFont; -struct SwTextGlyphsKey; -bool operator<(const SwTextGlyphsKey& l, const SwTextGlyphsKey& r); -struct SwTextGlyphsData; +/** + * Defines a substring on a given output device, to be used as an std::unordered_map<> + * key. + */ +struct SwTextGlyphsKey +{ + VclPtr<OutputDevice> m_pOutputDevice; + OUString m_aText; + sal_Int32 m_nIndex; + sal_Int32 m_nLength; + size_t mnHashCode; + + SwTextGlyphsKey(VclPtr<OutputDevice> const& pOutputDevice, const OUString & sText, sal_Int32 nIndex, sal_Int32 nLength); + bool operator==(SwTextGlyphsKey const & rhs) const; +}; +struct SwTextGlyphsKeyHash +{ + size_t operator()(SwTextGlyphsKey const & rKey) const { return rKey.mnHashCode; } +}; +/** + * Glyphs and text width for the given SwTextGlyphsKey. + */ +struct SwTextGlyphsData +{ + SalLayoutGlyphs m_aTextGlyphs; + tools::Long m_nTextWidth = -1; // -1 = not computed yet +}; +typedef std::unordered_map<SwTextGlyphsKey, SwTextGlyphsData, SwTextGlyphsKeyHash> SwTextGlyphsMap; class SwFntObj final : public SwCacheObj { @@ -86,7 +111,7 @@ class SwFntObj final : public SwCacheObj bool m_bPaintBlank : 1; /// Cache of already calculated layout glyphs and text widths. - std::map<SwTextGlyphsKey, SwTextGlyphsData> m_aTextGlyphs; + SwTextGlyphsMap m_aTextGlyphs; static tools::Long s_nPixWidth; static MapMode *s_pPixMap; diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx index 9490fe51add0..17be5c9f0eef 100644 --- a/sw/source/core/txtnode/fntcache.cxx +++ b/sw/source/core/txtnode/fntcache.cxx @@ -57,6 +57,7 @@ #include <strings.hrc> #include <fntcap.hxx> #include <vcl/outdev/ScopedStates.hxx> +#include <o3tl/hash_combine.hxx> using namespace ::com::sun::star; @@ -73,26 +74,31 @@ MapMode* SwFntObj::s_pPixMap = nullptr; static vcl::DeleteOnDeinit< VclPtr<OutputDevice> > s_pFntObjPixOut {}; /** - * Defines a substring on a given output device, to be used as an std::map<> + * Defines a substring on a given output device, to be used as an std::unordered_map<> * key. */ -struct SwTextGlyphsKey +SwTextGlyphsKey::SwTextGlyphsKey(VclPtr<OutputDevice> const& pOutputDevice, const OUString & sText, sal_Int32 nIndex, sal_Int32 nLength) + : m_pOutputDevice(pOutputDevice), m_aText(sText), m_nIndex(nIndex), m_nLength(nLength) { - VclPtr<OutputDevice> m_pOutputDevice; - OUString m_aText; - sal_Int32 m_nIndex; - sal_Int32 m_nLength; - -}; - -/** - * Glyphs and text width for the given SwTextGlyphsKey. - */ -struct SwTextGlyphsData + mnHashCode = 0; + o3tl::hash_combine(mnHashCode, pOutputDevice.get()); + o3tl::hash_combine(mnHashCode, m_nIndex); + o3tl::hash_combine(mnHashCode, m_nLength); + if(m_nLength >= 0 && m_nIndex >= 0 && m_nIndex + m_nLength <= m_aText.getLength()) + o3tl::hash_combine(mnHashCode, m_aText.getStr() + m_nIndex, m_nLength); +} +bool SwTextGlyphsKey::operator==(SwTextGlyphsKey const & rhs) const { - SalLayoutGlyphs m_aTextGlyphs; - tools::Long m_nTextWidth = -1; // -1 = not computed yet -}; + bool b = m_pOutputDevice.get() == rhs.m_pOutputDevice.get() + && m_nIndex == rhs.m_nIndex + && m_nLength == rhs.m_nLength; + if (!b) + return false; + if(m_nLength >= 0 && m_nIndex >= 0 && m_nIndex + m_nLength <= m_aText.getLength()) + return m_aText.subView(m_nIndex,m_nLength) == rhs.m_aText.subView(m_nIndex, m_nLength); + return m_aText == rhs.m_aText; +} + namespace { @@ -118,39 +124,6 @@ tools::Long EvalGridWidthAdd( const SwTextGridItem *const pGrid, const SwDrawTex } -bool operator<(const SwTextGlyphsKey& l, const SwTextGlyphsKey& r) -{ - if (l.m_pOutputDevice.get() < r.m_pOutputDevice.get()) - return true; - if (l.m_pOutputDevice.get() > r.m_pOutputDevice.get()) - return false; - if (l.m_nIndex < r.m_nIndex) - return true; - if (l.m_nIndex > r.m_nIndex) - return false; - if (l.m_nLength < r.m_nLength) - return true; - if (l.m_nLength > r.m_nLength) - return false; - - // Comparing strings is expensive, so compare them: - // - only at the end of this function - // - only once - // - only the relevant substring (if the index/length is not out of bounds) - sal_Int32 nRet = 0; - if (l.m_nLength < 0 || l.m_nIndex < 0 || l.m_nIndex + l.m_nLength > l.m_aText.getLength()) - nRet = l.m_aText.compareTo(r.m_aText); - else - nRet = memcmp(l.m_aText.getStr() + l.m_nIndex, r.m_aText.getStr() + r.m_nIndex, - l.m_nLength * sizeof(sal_Unicode)); - if (nRet < 0) - return true; - if (nRet > 0) - return false; - - return false; -}; - void SwFntCache::Flush( ) { if ( pLastFont ) @@ -220,7 +193,7 @@ void SwFntObj::CreatePrtFont( const OutputDevice& rPrt ) * Pre-calculates glyph items for the rendered subset of rKey's text, assuming * outdev state does not change between the outdev calls. */ -static SalLayoutGlyphs* lcl_CreateLayout(const SwTextGlyphsKey& rKey, std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it) +static SalLayoutGlyphs* lcl_CreateLayout(const SwTextGlyphsKey& rKey, SwTextGlyphsMap::iterator it) { assert (!it->second.m_aTextGlyphs.IsValid()); @@ -243,7 +216,7 @@ static SalLayoutGlyphs* lcl_CreateLayout(const SwTextGlyphsKey& rKey, std::map<S SalLayoutGlyphs* SwFntObj::GetCachedSalLayoutGlyphs(const SwTextGlyphsKey& key) { - std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it = m_aTextGlyphs.find(key); + SwTextGlyphsMap::iterator it = m_aTextGlyphs.find(key); if(it != m_aTextGlyphs.end()) { if( it->second.m_aTextGlyphs.IsValid()) @@ -259,7 +232,7 @@ SalLayoutGlyphs* SwFntObj::GetCachedSalLayoutGlyphs(const SwTextGlyphsKey& key) tools::Long SwFntObj::GetCachedTextWidth(const SwTextGlyphsKey& key, const vcl::text::TextLayoutCache* vclCache) { - std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it = m_aTextGlyphs.find(key); + SwTextGlyphsMap::iterator it = m_aTextGlyphs.find(key); if(it != m_aTextGlyphs.end() && it->second.m_nTextWidth >= 0) return it->second.m_nTextWidth; if(it == m_aTextGlyphs.end()) |