include/vcl/glyphitemcache.hxx  |    2 ++
 vcl/source/gdi/impglyphitem.cxx |   30 ++++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

New commits:
commit 0a6d946694e4fcb39228c5e1fec58fcfd8a45989
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Wed Apr 27 09:52:04 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Tue May 3 09:08:44 2022 +0200

    optimize repeated calls for the same string in SalLayoutGlyphsCache
    
    It often happens that the entire text will be laid out in parts,
    so if the first call is a prefix and another one follows that,
    lay out the entire string and then use the glyph subset optimization.
    Doing this only for the second segment instead immediately for
    the prefix is more efficient, as sometimes there is only the prefix
    call and there's no call for the rest of the string. This also
    avoids failures in CppunitTest_sw_layoutwriter, as a number of tests
    such as testAbi11870 lay out only a prefix and doing a layout
    for the entire string leads to font fallback, on which
    CppunitTest_sw_layoutwriter aborts in PrintFontManager::Substitute().
    
    Change-Id: I76554868ec7e8a79dd09709a247ad1d839291c06
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133495
    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 998dcf97f915..a17f53c61e56 100644
--- a/include/vcl/glyphitemcache.hxx
+++ b/include/vcl/glyphitemcache.hxx
@@ -96,6 +96,8 @@ private:
     // Last temporary glyphs returned (pointer is returned, so the object 
needs to be kept somewhere).
     std::optional<CachedGlyphsKey> mLastTemporaryKey;
     SalLayoutGlyphs mLastTemporaryGlyphs;
+    // If set, info about the last call which wanted a prefix of the full text.
+    std::optional<CachedGlyphsKey> mLastPrefixKey;
 
     SalLayoutGlyphsCache(const SalLayoutGlyphsCache&) = delete;
     SalLayoutGlyphsCache& operator=(const SalLayoutGlyphsCache&) = delete;
diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx
index 769c1afb9743..81553622a132 100644
--- a/vcl/source/gdi/impglyphitem.cxx
+++ b/vcl/source/gdi/impglyphitem.cxx
@@ -301,6 +301,7 @@ SalLayoutGlyphsCache::GetLayoutGlyphs(VclPtr<const 
OutputDevice> outputDevice, c
     const SalLayoutFlags glyphItemsOnlyLayout
         = SalLayoutFlags::GlyphItemsOnly | SalLayoutFlags::BiDiStrong;
 #endif
+    bool resetLastPrefixKey = true;
     if (nIndex != 0 || nLen != text.getLength())
     {
         // The glyphs functions are often called first for an entire string
@@ -311,8 +312,34 @@ SalLayoutGlyphsCache::GetLayoutGlyphs(VclPtr<const 
OutputDevice> outputDevice, c
             return &mLastTemporaryGlyphs;
         const CachedGlyphsKey keyWhole(outputDevice, text, 0, 
text.getLength(), nLogicWidth);
         GlyphsCache::const_iterator itWhole = mCachedGlyphs.find(keyWhole);
+        if (itWhole == mCachedGlyphs.end())
+        {
+            // This function may often be called repeatedly for segments of 
the same string,
+            // in which case it is more efficient to cache glyphs for the 
entire string
+            // and then return subsets of them. So if the first call is for a 
prefix of the string,
+            // remember that, and if the next call follows the previous part 
of the string,
+            // cache the entire string.
+            if (nIndex == 0)
+            {
+                mLastPrefixKey = key;
+                resetLastPrefixKey = false;
+            }
+            else if (mLastPrefixKey.has_value() && mLastPrefixKey->len == 
nIndex
+                     && mLastPrefixKey
+                            == CachedGlyphsKey(outputDevice, text, 
mLastPrefixKey->index,
+                                               mLastPrefixKey->len, 
nLogicWidth))
+            {
+                assert(mLastPrefixKey->index == 0);
+                std::unique_ptr<SalLayout> layout
+                    = outputDevice->ImplLayout(text, nIndex, nLen, Point(0, 
0), nLogicWidth, {},
+                                               glyphItemsOnlyLayout, 
layoutCache);
+                GetLayoutGlyphs(outputDevice, text, 0, text.getLength(), 
nLogicWidth, layoutCache);
+                itWhole = mCachedGlyphs.find(keyWhole);
+            }
+        }
         if (itWhole != mCachedGlyphs.end() && itWhole->second.IsValid())
         {
+            mLastPrefixKey.reset();
             mLastTemporaryGlyphs
                 = makeGlyphsSubset(itWhole->second, outputDevice, text, 
nIndex, nLen);
             if (mLastTemporaryGlyphs.IsValid())
@@ -337,6 +364,9 @@ SalLayoutGlyphsCache::GetLayoutGlyphs(VclPtr<const 
OutputDevice> outputDevice, c
             }
         }
     }
+    if (resetLastPrefixKey)
+        mLastPrefixKey.reset();
+
     std::shared_ptr<const vcl::text::TextLayoutCache> tmpLayoutCache;
     if (layoutCache == nullptr)
     {

Reply via email to