configure.ac | 11 +- sw/inc/swtable.hxx | 2 sw/source/core/inc/fntcache.hxx | 23 +---- sw/source/core/table/swtable.cxx | 48 +++++----- sw/source/core/txtnode/fntcache.cxx | 164 +++++++++++++++++++++++------------- sw/source/filter/xml/xmltbli.cxx | 2 6 files changed, 150 insertions(+), 100 deletions(-)
New commits: commit e5c88ce0b91d105d3dc6ba1366de101c0e04e09a Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Tue Mar 23 15:52:31 2021 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue Mar 23 15:57:13 2021 +0100 use --enable-ooenv only if --enable-debug/dbgutil I'm not sure what the original purpose of the ooenv script was, but now it contains only debugging settings such as malloc debugging, which has a noticeable overhead (8.2s->10.1s in my random case). At least openSUSE appears to not actually package the script, but it still doesn't make sense to use this script in non-debug builds. Change-Id: I4518bb1680a543ed520399c11c83dd6dc5539f71 diff --git a/configure.ac b/configure.ac index 1182bc1c839c..ea6bee87afe4 100644 --- a/configure.ac +++ b/configure.ac @@ -1184,8 +1184,8 @@ if test "$enable_compiler_plugins" = debug; then fi libo_FUZZ_ARG_ENABLE(ooenv, - AS_HELP_STRING([--disable-ooenv], - [Disable ooenv for the instdir installation.])) + AS_HELP_STRING([--enable-ooenv], + [Enable ooenv for the instdir installation.])) libo_FUZZ_ARG_ENABLE(libnumbertext, AS_HELP_STRING([--disable-libnumbertext], @@ -4652,6 +4652,13 @@ AC_SUBST(ASSERT_ALWAYS_ABORT) # =================================================================== if test $_os != "WINNT" -a $_os != "Darwin"; then AC_MSG_CHECKING([whether to use ooenv for the instdir installation]) + if test -z "$enable_ooenv"; then + if test -n "$ENABLE_DEBUG$ENABLE_DBGUTIL"; then + enable_ooenv=yes + else + enable_ooenv=no + fi + fi if test "$enable_ooenv" = "no"; then AC_MSG_RESULT([no]) else commit b3c890ad303f16e514ea30a96ec86dacb82b6e41 Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Thu Mar 28 13:13:22 2019 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue Mar 23 15:57:13 2021 +0100 tdf#84635 quadratic slowdown on loading large tables skip the re-registration scan in SwTableBox::ChgFrameFormat, which we don't need since we are creating this table for the first time On my machine, loading the 69 page file goes from 40.9s to 30.4s loading the 128 page file goes from 79.1s to 45.1s Change-Id: Id9e48256556e19eca34a892b29beff7eab9f51f1 Reviewed-on: https://gerrit.libreoffice.org/69885 Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> Tested-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/sw/inc/swtable.hxx b/sw/inc/swtable.hxx index 21348a36662b..844ab31497e0 100644 --- a/sw/inc/swtable.hxx +++ b/sw/inc/swtable.hxx @@ -433,7 +433,7 @@ public: // Creates its own FrameFormat if more boxes depend on it. SwFrameFormat* ClaimFrameFormat(); - void ChgFrameFormat( SwTableBoxFormat *pNewFormat ); + void ChgFrameFormat( SwTableBoxFormat *pNewFormat, bool bNeedToReregister = true ); void RemoveFromTable(); const SwStartNode *GetSttNd() const { return m_pStartNode; } diff --git a/sw/source/core/table/swtable.cxx b/sw/source/core/table/swtable.cxx index 93f53065a7ca..82e3259e435e 100644 --- a/sw/source/core/table/swtable.cxx +++ b/sw/source/core/table/swtable.cxx @@ -1734,36 +1734,40 @@ SwFrameFormat* SwTableBox::ClaimFrameFormat() return pRet; } -void SwTableBox::ChgFrameFormat( SwTableBoxFormat* pNewFormat ) +void SwTableBox::ChgFrameFormat( SwTableBoxFormat* pNewFormat, bool bNeedToReregister ) { SwFrameFormat *pOld = GetFrameFormat(); SwIterator<SwCellFrame,SwFormat> aIter( *pOld ); + // tdf#84635 We set bNeedToReregister=false to avoid a quadratic slowdown on loading large tables, + // and since we are creating the table for the first time, no re-registration is necessary. + // First, re-register the Frames. - for( SwCellFrame* pCell = aIter.First(); pCell; pCell = aIter.Next() ) - { - if( pCell->GetTabBox() == this ) - { - pCell->RegisterToFormat( *pNewFormat ); - pCell->InvalidateSize(); - pCell->InvalidatePrt_(); - pCell->SetCompletePaint(); - pCell->SetDerivedVert( false ); - pCell->CheckDirChange(); - - // #i47489# - // make sure that the row will be formatted, in order - // to have the correct Get(Top|Bottom)MarginForLowers values - // set at the row. - const SwTabFrame* pTab = pCell->FindTabFrame(); - if ( pTab && pTab->IsCollapsingBorders() ) + if (bNeedToReregister) + for( SwCellFrame* pCell = aIter.First(); pCell; pCell = aIter.Next() ) + { + if( pCell->GetTabBox() == this ) { - SwFrame* pRow = pCell->GetUpper(); - pRow->InvalidateSize_(); - pRow->InvalidatePrt_(); + pCell->RegisterToFormat( *pNewFormat ); + pCell->InvalidateSize(); + pCell->InvalidatePrt_(); + pCell->SetCompletePaint(); + pCell->SetDerivedVert( false ); + pCell->CheckDirChange(); + + // #i47489# + // make sure that the row will be formatted, in order + // to have the correct Get(Top|Bottom)MarginForLowers values + // set at the row. + const SwTabFrame* pTab = pCell->FindTabFrame(); + if ( pTab && pTab->IsCollapsingBorders() ) + { + SwFrame* pRow = pCell->GetUpper(); + pRow->InvalidateSize_(); + pRow->InvalidatePrt_(); + } } } - } // Now, re-register self. pNewFormat->Add( this ); diff --git a/sw/source/filter/xml/xmltbli.cxx b/sw/source/filter/xml/xmltbli.cxx index ed73304a7e5d..6ee095903afc 100644 --- a/sw/source/filter/xml/xmltbli.cxx +++ b/sw/source/filter/xml/xmltbli.cxx @@ -1921,7 +1921,7 @@ SwTableBoxFormat* SwXMLTableContext::GetSharedBoxFormat( { // set the shared format pBoxFormat2 = aIter->second; - pBox->ChgFrameFormat( pBoxFormat2 ); + pBox->ChgFrameFormat( pBoxFormat2, /*bNeedToReregister*/false ); bNew = false; // copied from an existing format // claim it, if we are not allowed to share commit c72de55d0b7a26bb06c4e550b2e4c402ea8676bc Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Fri Mar 12 14:08:11 2021 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue Mar 23 15:57:13 2021 +0100 do not disable Writer font caching on zoom mismatch This code disables font caching for some cases, e.g. when exporting to PDF if the zoom is set to anything else than 100%, or also when loading a document. It unfortunately comes from the OOo initial import, so it's impossible to find out why it should be needed. SwFntObj instances are created only using SwFntAccess ctor, which checks any SwFntObj it tries to reuse, so if this some additional factor to consider when reusing SwFntObj, then it can be checked there. But when I remove the code, I cannot see any breakage. Tests pass, normal rendering is fine, document thumbnail is fine, printing is fine, PDF export is fine, embedding in a spreadsheet is fine. We had a look at this with Miklos and concluded that it is not needed (until proven otherwise, in which case it'll be also known why it would be needed). Change-Id: I59d375229a265a4353c1da6dd067d892dd4ecfb6 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112589 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx index 206e95340a0f..7cc9cf35714b 100644 --- a/sw/source/core/txtnode/fntcache.cxx +++ b/sw/source/core/txtnode/fntcache.cxx @@ -589,24 +589,6 @@ void SwFntObj::CreateScrFont( const SwViewShell& rSh, const OutputDevice& rOut ) m_pScrFont = m_pPrtFont; } - // check zoom factor, e.g. because of PrtOle2 during export - { - // In case the zoom factor of the output device differs from the - // one in the ViewOptions, this Font must not be cached, - // hence set zoom factor to an invalid value - long nTmp; - if( pOut->GetMapMode().GetScaleX().IsValid() && - pOut->GetMapMode().GetScaleY().IsValid() && - pOut->GetMapMode().GetScaleX() == pOut->GetMapMode().GetScaleY() ) - { - nTmp = long(100 * pOut->GetMapMode().GetScaleX()); - } - else - nTmp = 0; - if( nTmp != m_nZoom ) - m_nZoom = USHRT_MAX - 1; - } - m_nScrAscent = static_cast<sal_uInt16>(pOut->GetFontMetric().GetAscent()); if ( USHRT_MAX == m_nScrHeight ) m_nScrHeight = static_cast<sal_uInt16>(pOut->GetTextHeight()); commit 5ab9cfe16550ab8d439828d766d36a9a8b611c2b Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Thu Mar 11 15:34:41 2021 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue Mar 23 15:57:13 2021 +0100 improve font caching in SwFntObj The code previously cached only SalGlyphItems, but such caching fails if SalLayout::GetGlyphs() does not return valid glyphs, which is the case with MultiSalLayout. Worse, it not only fails, but layout is once computed for caching, that fails, and is computed a second time for actual use. This improved cache caches the result of GetTextWidth(), which itself improves the performance a bit, but it also allows caching the value for GetGlyph() not returning valid glyphs. Moreover this also caches failures to get valid glyphs from GetGlyphs(). There are quite some calls to GetTextArray(), I didn't cache those, but it might be added if needed. Change-Id: Ia2589fb1b778f4f154c88f65d9906584284239da Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112588 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sw/source/core/inc/fntcache.hxx b/sw/source/core/inc/fntcache.hxx index 04cfc4abc219..d8e11701445b 100644 --- a/sw/source/core/inc/fntcache.hxx +++ b/sw/source/core/inc/fntcache.hxx @@ -60,19 +60,9 @@ extern SwFntCache *pFntCache; extern SwFntObj *pLastFont; extern sal_uInt8* mnFontCacheIdCounter; -/** - * Defines a substring on a given output device, to be used as an std::map<> - * key. - */ -struct SwTextGlyphsKey -{ - VclPtr<OutputDevice> m_pOutputDevice; - OUString m_aText; - sal_Int32 m_nIndex; - sal_Int32 m_nLength; - -}; +struct SwTextGlyphsKey; bool operator<(const SwTextGlyphsKey& l, const SwTextGlyphsKey& r); +struct SwTextGlyphsData; class SwFntObj : public SwCacheObj { @@ -95,8 +85,8 @@ class SwFntObj : public SwCacheObj bool m_bSymbol : 1; bool m_bPaintBlank : 1; - /// Cache of already calculated layout glyphs. - std::map<SwTextGlyphsKey, SalLayoutGlyphs> m_aTextGlyphs; + /// Cache of already calculated layout glyphs and text widths. + std::map<SwTextGlyphsKey, SwTextGlyphsData> m_aTextGlyphs; static long nPixWidth; static MapMode *pPixMap; @@ -125,7 +115,10 @@ public: sal_uInt16 GetZoom() const { return m_nZoom; } sal_uInt16 GetPropWidth() const { return m_nPropWidth; } bool IsSymbol() const { return m_bSymbol; } - std::map<SwTextGlyphsKey, SalLayoutGlyphs>& GetTextGlyphs() { return m_aTextGlyphs; } + + long GetCachedTextWidth(const SwTextGlyphsKey& key, const vcl::TextLayoutCache* vclCache); + SalLayoutGlyphs* GetCachedSalLayoutGlyphs(const SwTextGlyphsKey& key); + void ClearCachedTextGlyphs(); void DrawText( SwDrawTextInfo &rInf ); /// determine the TextSize (of the printer) diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx index 500190bf064c..206e95340a0f 100644 --- a/sw/source/core/txtnode/fntcache.cxx +++ b/sw/source/core/txtnode/fntcache.cxx @@ -76,6 +76,28 @@ long SwFntObj::nPixWidth; MapMode* SwFntObj::pPixMap = nullptr; static vcl::DeleteOnDeinit< VclPtr<OutputDevice> > s_pFntObjPixOut( new VclPtr<OutputDevice> ); +/** + * Defines a substring on a given output device, to be used as an std::map<> + * key. + */ +struct SwTextGlyphsKey +{ + VclPtr<OutputDevice> m_pOutputDevice; + OUString m_aText; + sal_Int32 m_nIndex; + sal_Int32 m_nLength; + +}; + +/** + * Glyphs and text width for the given SwTextGlyphsKey. + */ +struct SwTextGlyphsData +{ + SalLayoutGlyphs m_aTextGlyphs; + long m_nTextWidth = -1; // -1 = not computed yet +}; + namespace { @@ -98,36 +120,6 @@ long EvalGridWidthAdd( const SwTextGridItem *const pGrid, const SwDrawTextInfo & return nGridWidthAdd; } -/** - * Pre-calculates glyph items for the rendered subset of rKey's text, assuming - * outdev state does not change between the outdev calls. - */ -SalLayoutGlyphs* lcl_CreateLayout(SwTextGlyphsKey& rKey, SalLayoutGlyphs& rTextGlyphs) -{ - // Use pre-calculated result. - if (rTextGlyphs.IsValid()) - return &rTextGlyphs; - - if (rKey.m_nIndex >= rKey.m_aText.getLength()) - // Same as in OutputDevice::GetTextArray(). - return nullptr; - - // Calculate glyph items. - std::unique_ptr<SalLayout> pLayout - = rKey.m_pOutputDevice->ImplLayout(rKey.m_aText, rKey.m_nIndex, rKey.m_nLength, Point(0, 0), 0, - nullptr, SalLayoutFlags::GlyphItemsOnly); - if (!pLayout) - return nullptr; - - const SalLayoutGlyphs* pGlyphs = pLayout->GetGlyphs(); - if (!pGlyphs) - return nullptr; - - // Remember the calculation result. - rTextGlyphs = *pGlyphs; - - return &rTextGlyphs; -} } bool operator<(const SwTextGlyphsKey& l, const SwTextGlyphsKey& r) @@ -228,6 +220,72 @@ void SwFntObj::CreatePrtFont( const OutputDevice& rPrt ) } +/** + * Pre-calculates glyph items for the rendered subset of rKey's text, assuming + * outdev state does not change between the outdev calls. + */ +static SalLayoutGlyphs* lcl_CreateLayout(const SwTextGlyphsKey& rKey, std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it) +{ + assert (!it->second.m_aTextGlyphs.IsValid()); + + if (rKey.m_nIndex >= rKey.m_aText.getLength()) + // Same as in OutputDevice::GetTextArray(). + return nullptr; + + // Calculate glyph items. + std::unique_ptr<SalLayout> pLayout + = rKey.m_pOutputDevice->ImplLayout(rKey.m_aText, rKey.m_nIndex, rKey.m_nLength, Point(0, 0), 0, + nullptr, SalLayoutFlags::GlyphItemsOnly); + if (!pLayout) + return nullptr; + + const SalLayoutGlyphs* pGlyphs = pLayout->GetGlyphs(); + if (!pGlyphs) + return nullptr; + + // Remember the calculation result. + it->second.m_aTextGlyphs = *pGlyphs; + + return &it->second.m_aTextGlyphs; +} + +SalLayoutGlyphs* SwFntObj::GetCachedSalLayoutGlyphs(const SwTextGlyphsKey& key) +{ + std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it = m_aTextGlyphs.find(key); + if(it != m_aTextGlyphs.end()) + { + if( it->second.m_aTextGlyphs.IsValid()) + return &it->second.m_aTextGlyphs; + // Do not try to create the layout here. If a cache item exists, it's already + // been attempted and the layout was invalid (this happens with MultiSalLayout). + // So in that case this is a cached failure. + return nullptr; + } + it = m_aTextGlyphs.emplace( key, SwTextGlyphsData()).first; + return lcl_CreateLayout(key, it); +} + +long SwFntObj::GetCachedTextWidth(const SwTextGlyphsKey& key, const vcl::TextLayoutCache* vclCache) +{ + std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it = m_aTextGlyphs.find(key); + if(it != m_aTextGlyphs.end() && it->second.m_nTextWidth >= 0) + return it->second.m_nTextWidth; + if(it == m_aTextGlyphs.end()) + { + it = m_aTextGlyphs.emplace( key, SwTextGlyphsData()).first; + lcl_CreateLayout(key, it); + } + it->second.m_nTextWidth = key.m_pOutputDevice->GetTextWidth(key.m_aText, key.m_nIndex, key.m_nLength, vclCache, + it->second.m_aTextGlyphs.IsValid() ? &it->second.m_aTextGlyphs : nullptr ); + assert(it->second.m_nTextWidth >= 0); + return it->second.m_nTextWidth; +} + +void SwFntObj::ClearCachedTextGlyphs() +{ + m_aTextGlyphs.clear(); +} + /* * returns whether we have to adjust the output font to resemble * the formatting font @@ -1458,7 +1516,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) // get screen array std::unique_ptr<long[]> pScrArray(new long[sal_Int32(rInf.GetLen())]); SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) }; - SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]); + SalLayoutGlyphs* pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey); rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray.get(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs); @@ -1473,7 +1531,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) m_pPrinter->SetFont( *m_pPrtFont ); } aGlyphsKey = SwTextGlyphsKey{ m_pPrinter, rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) }; - pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]); + pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey); m_pPrinter->GetTextArray(rInf.GetText(), pKernArray.get(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs); } @@ -1818,7 +1876,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) : sal_Int32(rInf.GetIdx()); aGlyphsKey = SwTextGlyphsKey{ &rInf.GetOut(), *pStr, nTmpIdx, nLen }; if (bCacheLayout) - pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]); + pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey); else pGlyphs = nullptr; rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, pKernArray.get(), @@ -2055,10 +2113,7 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf ) else { SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(nLn) }; - SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]); - aTextSize.setWidth( rInf.GetOut().GetTextWidth( rInf.GetText(), - sal_Int32(rInf.GetIdx()), sal_Int32(nLn), - rInf.GetVclCache(), pGlyphs) ); + aTextSize.setWidth( GetCachedTextWidth(aGlyphsKey, rInf.GetVclCache())); rInf.SetKanaDiff( 0 ); } @@ -2092,7 +2147,7 @@ TextFrameIndex SwFntObj::GetCursorOfst(SwDrawTextInfo &rInf) m_pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() ); m_pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() ); SwTextGlyphsKey aGlyphsKey{ m_pPrinter, rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) }; - SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]); + SalLayoutGlyphs* pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey); m_pPrinter->GetTextArray( rInf.GetText(), pKernArray.get(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs); } @@ -2506,8 +2561,7 @@ TextFrameIndex SwFont::GetTextBreak(SwDrawTextInfo const & rInf, long nTextWidth SwFntAccess aFntAccess(m_aSub[m_nActual].m_nFontCacheId, m_aSub[m_nActual].m_nFontIndex, &m_aSub[m_nActual], rInf.GetShell()); SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), *pTmpText, sal_Int32(nTmpIdx), sal_Int32(nTmpLen) }; - SalLayoutGlyphs* pGlyphs - = lcl_CreateLayout(aGlyphsKey, aFntAccess.Get()->GetTextGlyphs()[aGlyphsKey]); + SalLayoutGlyphs* pGlyphs = aFntAccess.Get()->GetCachedSalLayoutGlyphs(aGlyphsKey); nTextBreak = TextFrameIndex(rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth, sal_Int32(nTmpIdx), sal_Int32(nTmpLen), @@ -2699,7 +2753,7 @@ bool SwDrawTextInfo::ApplyAutoColor( vcl::Font* pFont ) void SwClearFntCacheTextGlyphs() { for (SwFntObj* pFntObj = pFntCache->First(); pFntObj; pFntObj = SwFntCache::Next(pFntObj)) - pFntObj->GetTextGlyphs().clear(); + pFntObj->ClearCachedTextGlyphs(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 7645b367e51832473f1ed4e19b96dd9b15fb3e1b Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Mar 22 13:51:39 2019 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Mar 22 21:00:57 2021 +0100 Related: tdf#124109 sw: save one vcl layout call in SwFntObj::DrawText() Commit 436b829f5b904d76039db0818cff5dedf1ae89f1 (sw: save one vcl layout call in SwFntObj::DrawText(), 2018-08-16) did this unconditionally, which broke kashida justification. Re-introduce the same mechanism, but this time opt out in the kashida case to keep that working. This means that for Latin scripts we are back to 2 layout calls (instead of 3) for each keypress in Writer. Change-Id: I890f0ab04d1f5dce561f1536d7c8a6d67a639813 Reviewed-on: https://gerrit.libreoffice.org/69557 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx index 175821ab90ef..500190bf064c 100644 --- a/sw/source/core/txtnode/fntcache.cxx +++ b/sw/source/core/txtnode/fntcache.cxx @@ -1487,6 +1487,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) long nSpaceAdd = rInf.GetSpace() / SPACING_PRECISION_FACTOR; bool bNoHalfSpace = false; + bool bCacheLayout = true; if ( rInf.GetFont() && rInf.GetLen() ) { @@ -1529,7 +1530,12 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) if ( pSI && pSI->CountKashida() && pSI->KashidaJustify( pKernArray.get(), pScrArray.get(), rInf.GetIdx(), rInf.GetLen(), nSpaceAdd ) != -1 ) + { nSpaceAdd = 0; + // Layout can't be reused in this case, it would lead to missing gaps in + // place of kashida. + bCacheLayout = false; + } else bNoHalfSpace = true; } @@ -1811,8 +1817,12 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) ? (rInf.GetIdx() ? 1 : 0) : sal_Int32(rInf.GetIdx()); aGlyphsKey = SwTextGlyphsKey{ &rInf.GetOut(), *pStr, nTmpIdx, nLen }; + if (bCacheLayout) + pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]); + else + pGlyphs = nullptr; rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, pKernArray.get(), - nTmpIdx , nLen ); + nTmpIdx , nLen, SalLayoutFlags::NONE, pGlyphs ); if (bBullet) { rInf.GetOut().Push(); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits