include/vcl/glyphitemcache.hxx     |   17 ++++++++++-------
 vcl/inc/TextLayoutCache.hxx        |   32 ++++++++++++++++++++++++++++++++
 vcl/source/gdi/CommonSalLayout.cxx |   30 +-----------------------------
 vcl/source/gdi/impglyphitem.cxx    |   20 +++++++++++++++-----
 4 files changed, 58 insertions(+), 41 deletions(-)

New commits:
commit 94c2fb28d76c9c37849412a66b31d6861bce3155
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Wed Apr 6 19:28:07 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Fri Apr 8 21:28:15 2022 +0200

    faster hashing of very long strings in SalLayoutGlyphsCache
    
    tdf#147284 being a (pathological) testcase.
    
    Change-Id: I08d8dffb40193b461555bed818c040761e8d575b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132669
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/vcl/inc/TextLayoutCache.hxx b/vcl/inc/TextLayoutCache.hxx
index 0ce0c19d8278..ecb85ea7043d 100644
--- a/vcl/inc/TextLayoutCache.hxx
+++ b/vcl/inc/TextLayoutCache.hxx
@@ -20,6 +20,8 @@
 #pragma once
 
 #include <sal/types.h>
+#include <rtl/ustring.hxx>
+#include <o3tl/hash_combine.hxx>
 
 #include <vcl/dllapi.h>
 
@@ -48,6 +50,36 @@ public:
     std::vector<vcl::text::Run> runs;
     TextLayoutCache(sal_Unicode const* pStr, sal_Int32 const nEnd);
 };
+
+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;
+    }
+};
+
+struct FastStringCompareEqual
+{
+    bool operator()(const OUString& str1, const OUString& str2) const
+    {
+        // Strings passed to GenericSalLayout::CreateTextLayoutCache() may be 
very long,
+        // and OUString operator == compares backwards and using hard-written 
code, while
+        // memcmp() compares much faster.
+        if (str1.getLength() != str2.getLength())
+            return false;
+        if (str1.getStr() == str2.getStr())
+            return true;
+        return memcmp(str1.getStr(), str2.getStr(), str1.getLength() * 
sizeof(str1.getStr()[0]))
+               == 0;
+    }
+};
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index 8dee28727997..2c8a4db8398f 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -154,40 +154,12 @@ 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;
-    }
-};
-
-struct ForwardStringCompareEqual
-{
-    bool operator()( const OUString& str1, const OUString& str2 ) const
-    {
-        // Strings passed to GenericSalLayout::CreateTextLayoutCache() may be 
very long,
-        // and OUString operator == compares backwards, which is inefficient 
for very long
-        // strings (bad memory prefetch).
-        if( str1.getLength() != str2.getLength())
-            return false;
-        if( str1.getStr() == str2.getStr())
-            return true;
-        return memcmp( str1.getStr(), str2.getStr(), str1.getLength() * 
sizeof( str1.getStr()[ 0 ] )) == 0;
-    }
-};
-
 } // namespace
 
 std::shared_ptr<const vcl::text::TextLayoutCache> 
GenericSalLayout::CreateTextLayoutCache(OUString const& rString)
 {
     typedef o3tl::lru_map<OUString, std::shared_ptr<const 
vcl::text::TextLayoutCache>,
-        FirstCharsStringHash, ForwardStringCompareEqual> Cache;
+        vcl::text::FirstCharsStringHash, vcl::text::FastStringCompareEqual> 
Cache;
     static vcl::DeleteOnDeinit< Cache > cache( 1000 );
     if( Cache* map = cache.get())
     {
diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx
index eaf8cf5c8453..d320d27dad88 100644
--- a/vcl/source/gdi/impglyphitem.cxx
+++ b/vcl/source/gdi/impglyphitem.cxx
@@ -21,6 +21,7 @@
 #include <vcl/glyphitemcache.hxx>
 #include <vcl/vcllayout.hxx>
 #include <tools/stream.hxx>
+#include <TextLayoutCache.hxx>
 
 SalLayoutGlyphs::SalLayoutGlyphs() {}
 
@@ -146,7 +147,7 @@ 
SalLayoutGlyphsCache::CachedGlyphsKey::CachedGlyphsKey(const VclPtr<const Output
     SvMemoryStream stream;
     WriteFont(stream, outputDevice->GetFont());
     o3tl::hash_combine(hashValue, static_cast<const char*>(stream.GetData()), 
stream.GetSize());
-    o3tl::hash_combine(hashValue, text);
+    o3tl::hash_combine(hashValue, vcl::text::FirstCharsStringHash()(text));
     o3tl::hash_combine(hashValue, index);
     o3tl::hash_combine(hashValue, len);
     o3tl::hash_combine(hashValue, logicPos.X());
@@ -158,7 +159,8 @@ inline bool 
SalLayoutGlyphsCache::CachedGlyphsKey::operator==(const CachedGlyphs
 {
     return hashValue == other.hashValue && outputDevice == other.outputDevice
            && index == other.index && len == other.len && logicPos == 
other.logicPos
-           && logicWidth == other.logicWidth && text == other.text;
+           && logicWidth == other.logicWidth
+           && vcl::text::FastStringCompareEqual()(text, other.text);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 1b593dbc62dc2ceebc3f8be30d7221c916098f6d
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Wed Apr 6 18:52:21 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Fri Apr 8 21:27:59 2022 +0200

    use vcl::text::TextLayoutCache in SalLayoutGlyphsCache
    
    Change-Id: I0ec22fe53e05319dec15456a916b10e97ea91a75
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132668
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/include/vcl/glyphitemcache.hxx b/include/vcl/glyphitemcache.hxx
index 8c7cd01bbadc..83c77309a632 100644
--- a/include/vcl/glyphitemcache.hxx
+++ b/include/vcl/glyphitemcache.hxx
@@ -44,15 +44,18 @@ public:
         : mCachedGlyphs(size)
     {
     }
-    const SalLayoutGlyphs* GetLayoutGlyphs(VclPtr<const OutputDevice> 
outputDevice,
-                                           const OUString& text) const
+    const SalLayoutGlyphs*
+    GetLayoutGlyphs(VclPtr<const OutputDevice> outputDevice, const OUString& 
text,
+                    const vcl::text::TextLayoutCache* layoutCache = nullptr) 
const
     {
-        return GetLayoutGlyphs(outputDevice, text, 0, text.getLength());
+        return GetLayoutGlyphs(outputDevice, text, 0, text.getLength(), 
Point(0, 0), 0,
+                               layoutCache);
     }
-    const SalLayoutGlyphs* GetLayoutGlyphs(VclPtr<const OutputDevice> 
outputDevice,
-                                           const OUString& text, sal_Int32 
nIndex, sal_Int32 nLen,
-                                           const Point& rLogicPos = Point(0, 
0),
-                                           tools::Long nLogicWidth = 0) const;
+    const SalLayoutGlyphs*
+    GetLayoutGlyphs(VclPtr<const OutputDevice> outputDevice, const OUString& 
text, sal_Int32 nIndex,
+                    sal_Int32 nLen, const Point& rLogicPos = Point(0, 0),
+                    tools::Long nLogicWidth = 0,
+                    const vcl::text::TextLayoutCache* layoutCache = nullptr) 
const;
     void clear() { mCachedGlyphs.clear(); }
 
 private:
diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx
index 3853691d7d00..eaf8cf5c8453 100644
--- a/vcl/source/gdi/impglyphitem.cxx
+++ b/vcl/source/gdi/impglyphitem.cxx
@@ -97,7 +97,8 @@ bool SalLayoutGlyphsImpl::IsValid() const
 const SalLayoutGlyphs*
 SalLayoutGlyphsCache::GetLayoutGlyphs(VclPtr<const OutputDevice> outputDevice, 
const OUString& text,
                                       sal_Int32 nIndex, sal_Int32 nLen, const 
Point& rLogicPos,
-                                      tools::Long nLogicWidth) const
+                                      tools::Long nLogicWidth,
+                                      const vcl::text::TextLayoutCache* 
layoutCache) const
 {
     if (nLen == 0)
         return nullptr;
@@ -112,8 +113,15 @@ SalLayoutGlyphsCache::GetLayoutGlyphs(VclPtr<const 
OutputDevice> outputDevice, c
         // So in that case this is a cached failure.
         return nullptr;
     }
-    std::unique_ptr<SalLayout> layout = outputDevice->ImplLayout(
-        text, nIndex, nLen, rLogicPos, nLogicWidth, {}, 
SalLayoutFlags::GlyphItemsOnly);
+    std::shared_ptr<const vcl::text::TextLayoutCache> tmpLayoutCache;
+    if (layoutCache == nullptr)
+    {
+        tmpLayoutCache = OutputDevice::CreateTextLayoutCache(text);
+        layoutCache = tmpLayoutCache.get();
+    }
+    std::unique_ptr<SalLayout> layout
+        = outputDevice->ImplLayout(text, nIndex, nLen, rLogicPos, nLogicWidth, 
{},
+                                   SalLayoutFlags::GlyphItemsOnly, 
layoutCache);
     if (layout)
     {
         mCachedGlyphs.insert(std::make_pair(key, layout->GetGlyphs()));

Reply via email to