include/vcl/glyphitemcache.hxx | 2 ++ vcl/source/gdi/impglyphitem.cxx | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+)
New commits: commit 0a6d946694e4fcb39228c5e1fec58fcfd8a45989 Author: Luboš Luňák <[email protected]> AuthorDate: Wed Apr 27 09:52:04 2022 +0200 Commit: Luboš Luňák <[email protected]> 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 <[email protected]> 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) {
