include/vcl/outdev.hxx             |    2 +-
 sw/source/core/text/inftxt.hxx     |    8 ++++----
 sw/source/core/text/porfld.cxx     |    2 +-
 sw/source/core/text/pormulti.cxx   |    2 +-
 vcl/inc/sallayout.hxx              |    2 +-
 vcl/source/gdi/CommonSalLayout.cxx |   31 +++++++++++++++++++++++++++++--
 vcl/source/outdev/text.cxx         |    2 +-
 7 files changed, 38 insertions(+), 11 deletions(-)

New commits:
commit b2f0da51e36ae65d304881967605700ecee59575
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Mon Mar 14 15:55:00 2022 +0100
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Tue Mar 15 14:35:54 2022 +0100

    make CreateTextLayoutCache() cached (tdf#116400)
    
    The result depends only on the string, so it's possible to cache it
    easily, and caching this for text drawing calls can have a good
    hit rate.
    
    Change-Id: I56c6e254cc176ab07afe0df24ed37b19579fe64d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131556
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index fe1d9583e2ba..e1f85ad16fc7 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -1075,7 +1075,7 @@ public:
                                               sal_Int32 nIndex, sal_Int32 nLen,
                                               tools::Long nCharExtra,
                                               vcl::text::TextLayoutCache 
const* = nullptr) const;
-    static std::shared_ptr<vcl::text::TextLayoutCache> 
CreateTextLayoutCache(OUString const&);
+    static std::shared_ptr<const vcl::text::TextLayoutCache> 
CreateTextLayoutCache(OUString const&);
 
 protected:
     SAL_DLLPRIVATE void         ImplInitTextLineSize();
diff --git a/sw/source/core/text/inftxt.hxx b/sw/source/core/text/inftxt.hxx
index 9ee658364355..7c7bf57afa56 100644
--- a/sw/source/core/text/inftxt.hxx
+++ b/sw/source/core/text/inftxt.hxx
@@ -145,7 +145,7 @@ protected:
     // performance hack - this is only used by SwTextFormatInfo but
     // because it's not even possible to dynamic_cast these things
     // currently it has to be stored here
-    std::shared_ptr<vcl::text::TextLayoutCache> m_pCachedVclData;
+    std::shared_ptr<const vcl::text::TextLayoutCache> m_pCachedVclData;
 
     SwFont *m_pFnt;
     SwUnderlineFont *m_pUnderFnt; // Font for underlining
@@ -325,11 +325,11 @@ public:
         { return ( m_pKanaComp && m_nKanaIdx < m_pKanaComp->size() )
                    ? (*m_pKanaComp)[m_nKanaIdx] : 0; }
 
-    const std::shared_ptr<vcl::text::TextLayoutCache>& GetCachedVclData() const
+    const std::shared_ptr<const vcl::text::TextLayoutCache>& 
GetCachedVclData() const
     {
         return m_pCachedVclData;
     }
-    void SetCachedVclData(std::shared_ptr<vcl::text::TextLayoutCache> const& 
pCachedVclData)
+    void SetCachedVclData(std::shared_ptr<const vcl::text::TextLayoutCache> 
const& pCachedVclData)
     {
         m_pCachedVclData = pCachedVclData;
     }
@@ -673,7 +673,7 @@ public:
 class SwTextSlot final
 {
     OUString aText;
-    std::shared_ptr<vcl::text::TextLayoutCache> m_pOldCachedVclData;
+    std::shared_ptr<const vcl::text::TextLayoutCache> m_pOldCachedVclData;
     const OUString *pOldText;
     sw::WrongListIterator * m_pOldSmartTagList;
     sw::WrongListIterator * m_pOldGrammarCheckList;
diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx
index 47a55150ab3f..8c586530eff8 100644
--- a/sw/source/core/text/porfld.cxx
+++ b/sw/source/core/text/porfld.cxx
@@ -137,7 +137,7 @@ namespace {
  */
 class SwFieldSlot
 {
-    std::shared_ptr<vcl::text::TextLayoutCache> m_pOldCachedVclData;
+    std::shared_ptr<const vcl::text::TextLayoutCache> m_pOldCachedVclData;
     const OUString *pOldText;
     OUString aText;
     TextFrameIndex nIdx;
diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx
index 2e4831065537..d47b281ac9a9 100644
--- a/sw/source/core/text/pormulti.cxx
+++ b/sw/source/core/text/pormulti.cxx
@@ -2000,7 +2000,7 @@ bool SwTextFormatter::BuildMultiPortion( SwTextFormatInfo 
&rInf,
     // save some values
     const OUString* pOldText = &(rInf.GetText());
     const SwTwips nOldPaintOfst = rInf.GetPaintOfst();
-    std::shared_ptr<vcl::text::TextLayoutCache> const 
pOldCachedVclData(rInf.GetCachedVclData());
+    std::shared_ptr<const vcl::text::TextLayoutCache> const 
pOldCachedVclData(rInf.GetCachedVclData());
     rInf.SetCachedVclData(nullptr);
 
     OUString const aMultiStr( rInf.GetText().copy(0, sal_Int32(nMultiLen + 
rInf.GetIdx())) );
diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx
index 847c22ace091..75110158dc53 100644
--- a/vcl/inc/sallayout.hxx
+++ b/vcl/inc/sallayout.hxx
@@ -113,7 +113,7 @@ public:
     void            AdjustLayout(vcl::text::ImplLayoutArgs&) final override;
     bool            LayoutText(vcl::text::ImplLayoutArgs&, const 
SalLayoutGlyphsImpl*) final override;
     void            DrawText(SalGraphics&) const final override;
-    static std::shared_ptr<vcl::text::TextLayoutCache> 
CreateTextLayoutCache(OUString const&);
+    static std::shared_ptr<const vcl::text::TextLayoutCache> 
CreateTextLayoutCache(OUString const&);
     SalLayoutGlyphs GetGlyphs() const final override;
 
     bool            IsKashidaPosValid(int nCharPos) const final override;
diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index 811849309d67..e26dc68692bf 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -21,8 +21,11 @@
 
 #include <sal/log.hxx>
 #include <unotools/configmgr.hxx>
+#include <o3tl/hash_combine.hxx>
+#include <o3tl/lru_map.hxx>
 #include <o3tl/temporary.hxx>
 
+#include <vcl/lazydelete.hxx>
 #include <vcl/unohelp.hxx>
 #include <vcl/font/Feature.hxx>
 #include <vcl/font/FeatureParser.hxx>
@@ -151,11 +154,35 @@ namespace {
         return VerticalOrientation(nRet);
     }
 
+struct FirstCharsStringHash
+{
+    size_t operator()( const OUString& str ) const
+    {
+        // Strings passed to GenericSalLayout::CreateTextLayoutCache() may be 
very long,
+        // and computing an entire hash could almost negate the gain of 
hashing. Hash just first
+        // characters, that should be good enough.
+        size_t hash = rtl_ustr_hashCode_WithLength( str.getStr(), 
std::min<size_t>( 100, str.getLength()));
+        o3tl::hash_combine(hash, str.getLength());
+        return hash;
+    }
+};
+
 } // namespace
 
-std::shared_ptr<vcl::text::TextLayoutCache> 
GenericSalLayout::CreateTextLayoutCache(OUString const& rString)
+std::shared_ptr<const vcl::text::TextLayoutCache> 
GenericSalLayout::CreateTextLayoutCache(OUString const& rString)
 {
-    return std::make_shared<vcl::text::TextLayoutCache>(rString.getStr(), 
rString.getLength());
+    typedef o3tl::lru_map<OUString, std::shared_ptr<const 
vcl::text::TextLayoutCache>, FirstCharsStringHash> Cache;
+    static vcl::DeleteOnDeinit< Cache > cache( 1000 );
+    if( Cache* map = cache.get())
+    {
+        auto it = map->find(rString);
+        if( it != map->end())
+            return it->second;
+        auto ret = std::make_shared<const 
vcl::text::TextLayoutCache>(rString.getStr(), rString.getLength());
+        map->insert( { rString, ret } );
+        return ret;
+    }
+    return std::make_shared<const 
vcl::text::TextLayoutCache>(rString.getStr(), rString.getLength());
 }
 
 SalLayoutGlyphs GenericSalLayout::GetGlyphs() const
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index e9c9ff59d414..8ac3cc379073 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -1456,7 +1456,7 @@ std::unique_ptr<SalLayout> OutputDevice::ImplLayout(const 
OUString& rOrigStr,
     return pSalLayout;
 }
 
-std::shared_ptr<vcl::text::TextLayoutCache> 
OutputDevice::CreateTextLayoutCache(
+std::shared_ptr<const vcl::text::TextLayoutCache> 
OutputDevice::CreateTextLayoutCache(
         OUString const& rString)
 {
     return GenericSalLayout::CreateTextLayoutCache(rString);

Reply via email to