sw/source/core/text/itrform2.cxx | 11 ++++++++--- sw/source/core/text/portxt.cxx | 6 ++++++ vcl/source/gdi/CommonSalLayout.cxx | 9 ++++++--- vcl/source/gdi/impglyphitem.cxx | 9 ++++++++- 4 files changed, 28 insertions(+), 7 deletions(-)
New commits: commit b0908a76d02e7babf23c4287f57f3d6e368e26e8 Author: Jonathan Clark <jonat...@libreoffice.org> AuthorDate: Tue Sep 3 05:49:28 2024 -0600 Commit: Adolfo Jayme Barrientos <fit...@ubuntu.com> CommitDate: Wed Sep 4 18:16:49 2024 +0200 tdf#92064 sw: Improve large paragraph layout performance This change includes the following scalability improvements for documents containing extremely large paragraphs: - Reduces the size of layout contexts to account for LF control chars. - Due to typical access patterns while laying out paragraphs, VCL was making O(n^2) calls to vcl::ScriptRun::next(). VCL now uses an existing global LRU cache for script runs, avoiding much of this overhead. Change-Id: Iee03938683c95776a817d4819fe9a43c65a7c3fc Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172801 Tested-by: Jenkins Reviewed-by: Jonathan Clark <jonat...@libreoffice.org> Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172815 Reviewed-by: Ilmari Lauhakangas <ilmari.lauhakan...@libreoffice.org> Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com> diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 3673b46ba247..788d64fc538f 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -1460,6 +1460,7 @@ SwTextPortion *SwTextFormatter::NewTextPortion( SwTextFormatInfo &rInf ) case CH_TXTATR_BREAKWORD: case CH_TXTATR_INWORD: case CH_TXTATR_TAB: + case CH_TXTATR_NEWLINE: case CH_TXT_ATR_INPUTFIELDSTART: case CH_TXT_ATR_INPUTFIELDEND: case CH_TXT_ATR_FORMELEMENT: diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 0e4e3fe9dc48..115870dc9cf6 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -384,7 +384,7 @@ bool GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay const int nLength = rArgs.mrStr.getLength(); const sal_Unicode *pStr = rArgs.mrStr.getStr(); - std::optional<vcl::text::TextLayoutCache> oNewScriptRun; + std::shared_ptr<const vcl::text::TextLayoutCache> pNewScriptRun; vcl::text::TextLayoutCache const* pTextLayout; if (rArgs.m_pTextLayoutCache) { @@ -392,8 +392,11 @@ bool GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay } else { - oNewScriptRun.emplace(pStr, rArgs.mnEndCharPos); - pTextLayout = &*oNewScriptRun; + // tdf#92064, tdf#162663: + // Also use the global LRU cache for full string script runs. + // This obviates O(n^2) calls to vcl::ScriptRun::next() when laying out large paragraphs. + pNewScriptRun = vcl::text::TextLayoutCache::Create(rArgs.mrStr); + pTextLayout = pNewScriptRun.get(); } // nBaseOffset is used to align vertical text to the center of rotated commit ef40759390de4eba93d0a1e9369fc8ba5c1ea534 Author: Jonathan Clark <jonat...@libreoffice.org> AuthorDate: Fri Jul 12 13:40:34 2024 -0600 Commit: Adolfo Jayme Barrientos <fit...@ubuntu.com> CommitDate: Wed Sep 4 18:16:38 2024 +0200 tdf#92064 sw: Improve Tibetan layout performance This change includes the following scalability improvements for documents containing extremely long paragraphs: - Reduces the size of layout contexts to account for line breaks. - Disables a misbehaving glyph cache performance optimization for long strings. Change-Id: Ie9a3365076c0d112a7a655988d672a9f4609b42b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170420 Tested-by: Jenkins Reviewed-by: Jonathan Clark <jonat...@libreoffice.org> Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172858 Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com> Reviewed-by: Ilmari Lauhakangas <ilmari.lauhakan...@libreoffice.org> diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 71b78bc0914d..3673b46ba247 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -1418,8 +1418,11 @@ SwTextPortion *SwTextFormatter::NewTextPortion( SwTextFormatInfo &rInf ) if (!nCharWidthGuess) nCharWidthGuess = 1; auto nExpect = rInf.GetIdx() + TextFrameIndex(rInf.GetLineWidth() / nCharWidthGuess); - if (nExpect > rInf.GetIdx() && nNextChg > nExpect) - nNextChg = nExpect; + if (nExpect > rInf.GetIdx()) + { + nNextChg = std::min(nNextChg, nExpect); + nNextContext = std::min(nNextContext, nExpect); + } // we keep an invariant during method calls: // there are no portion ending characters like hard spaces @@ -1444,7 +1447,8 @@ SwTextPortion *SwTextFormatter::NewTextPortion( SwTextFormatInfo &rInf ) // for the first text portion in a paragraph, or for any successive // portions that are outside of the bounds of the previous context. if (!rInf.GetLayoutContext().has_value() - || rInf.GetLayoutContext()->m_nEnd <= rInf.GetIdx().get()) + || rInf.GetLayoutContext()->m_nBegin < rInf.GetLineStart().get() + || rInf.GetLayoutContext()->m_nEnd < nNextChg.get()) { // The layout context must terminate at special characters sal_Int32 nEnd = rInf.GetIdx().get(); diff --git a/sw/source/core/text/portxt.cxx b/sw/source/core/text/portxt.cxx index ee39f156c24a..ec0303c0665c 100644 --- a/sw/source/core/text/portxt.cxx +++ b/sw/source/core/text/portxt.cxx @@ -445,6 +445,12 @@ bool SwTextPortion::Format_( SwTextFormatInfo &rInf ) SetLen( pGuess->BreakPos() - rInf.GetIdx() ); + // Clamp layout context to the end of the line + if(auto stClampedContext = GetLayoutContext(); stClampedContext.has_value()) { + stClampedContext->m_nEnd = pGuess->BreakPos().get(); + SetLayoutContext(stClampedContext); + } + OSL_ENSURE( pGuess->BreakStart() >= pGuess->FieldDiff(), "Trouble with expanded field portions during line break" ); TextFrameIndex const nRealStart = pGuess->BreakStart() - pGuess->FieldDiff(); diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx index 1b40291736b7..946230a51762 100644 --- a/vcl/source/gdi/impglyphitem.cxx +++ b/vcl/source/gdi/impglyphitem.cxx @@ -364,6 +364,13 @@ const SalLayoutGlyphs* SalLayoutGlyphsCache::GetLayoutGlyphs( // part being underlined. Doing this for any two segments allows this optimization // even when the prefix of the string would use a different font. // TODO: Can those font differences be ignored? + + // Shaping performance seems to scale poorly with respect to string length. Certain + // writing systems involve extremely long strings (for example, Tibetan: tdf#92064). + // In such cases, this optimization would be a net loss, and must be disabled. + constexpr sal_Int32 nOptLengthThreshold = 20000; + bool bEnableOptimization = (text.getLength() < nOptLengthThreshold); + // Writer layouts tests enable SAL_NON_APPLICATION_FONT_USE=abort in order // to make PrintFontManager::Substitute() abort if font fallback happens. When // laying out the entire string the chance this happens increases (e.g. testAbi11870 @@ -374,7 +381,7 @@ const SalLayoutGlyphs* SalLayoutGlyphsCache::GetLayoutGlyphs( const char* pEnv = getenv("SAL_NON_APPLICATION_FONT_USE"); return pEnv && strcmp(pEnv, "abort") == 0; }(); - if (mLastSubstringKey.has_value() && !bAbortOnFontSubstitute) + if (bEnableOptimization && mLastSubstringKey.has_value() && !bAbortOnFontSubstitute) { sal_Int32 pos = nIndex; if (mLastSubstringKey->len < pos && text[pos - 1] == nbSpace)