sc/inc/table.hxx | 12 +++++++++- sc/source/core/data/table2.cxx | 49 ++++++++++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 11 deletions(-)
New commits: commit 185df5e6b3c81eec52f54f643697e8cfee9c1454 Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Tue Feb 25 14:41:30 2025 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Wed Feb 26 10:01:28 2025 +0100 speed up display of XLSX with lots of conditional formatting The biggest win here is the call to ShrinkToUsedDataArea, because otherwise, we end up iterating over 16384 columns, most of which are empty Change-Id: I92f90b82b66b3a3997890cb22432482e10f7f960 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182178 Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> Tested-by: Jenkins diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 74d4f978a523..944b1a9e211e 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -1330,9 +1330,19 @@ private: void SetLoadingMedium(bool bLoading); + struct FillMaxRotCacheMapHash + { + size_t operator()(const std::pair<const ScPatternAttr*, const SfxItemSet*>& rPair) const noexcept + { + return std::hash<const ScPatternAttr*>{}(rPair.first) ^ (std::hash<const SfxItemSet*>{}(rPair.second) << 1); + } + }; + typedef std::unordered_map<std::pair<const ScPatternAttr*, const SfxItemSet*>, ScRotateDir, FillMaxRotCacheMapHash> FillMaxRotCacheMap; + SCSIZE FillMaxRot( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCOL nX2, SCCOL nCol, SCROW nAttrRow1, SCROW nAttrRow2, SCSIZE nArrY, - const ScPatternAttr* pPattern, const SfxItemSet* pCondSet ); + const ScPatternAttr* pPattern, const SfxItemSet* pCondSet, + FillMaxRotCacheMap* pCache); // idle calculation of OutputDevice text width for cell // also invalidates script type, broadcasts for "calc as shown" diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 6b320dd64a95..20125f3de716 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -2448,13 +2448,30 @@ bool ScTable::IsBlockEmpty( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) return bEmpty; } +// Return value = new nArrY SCSIZE ScTable::FillMaxRot( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCOL nX2, SCCOL nCol, SCROW nAttrRow1, SCROW nAttrRow2, SCSIZE nArrY, - const ScPatternAttr* pPattern, const SfxItemSet* pCondSet ) -{ - // Return value = new nArrY + const ScPatternAttr* pPattern, const SfxItemSet* pCondSet, + FillMaxRotCacheMap* pCache ) +{ + // Use a cache to lookup nRotDir, because it gets expensive when painting large spreadsheets + // with lots of conditional formatting. + ScRotateDir nRotDir; + if (pCache) + { + auto aKey = std::make_pair(pPattern, pCondSet); + auto it = pCache->find(aKey); + if (it != pCache->end()) + nRotDir = it->second; + else + { + nRotDir = pPattern->GetRotateDir( pCondSet ); + pCache->insert({aKey, nRotDir}); + } + } + else + nRotDir = pPattern->GetRotateDir( pCondSet ); - ScRotateDir nRotDir = pPattern->GetRotateDir( pCondSet ); if ( nRotDir != ScRotateDir::NONE ) { bool bHit = true; @@ -2529,8 +2546,13 @@ void ScTable::FindMaxRotCol( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCC SCROW nY1 = pRowInfo[0].nRowNo; SCROW nY2 = pRowInfo[nArrCount-1].nRowNo; - - for (SCCOL nCol : GetColumnsRange(0, rDocument.MaxCol())) + FillMaxRotCacheMap aCacheMap; + std::unordered_map<OUString, SfxStyleSheetBase*> aStyleSheetCache; + SCCOL nStartCol = 0; + SCCOL nEndCol = rDocument.MaxCol(); + bool bShrunk = false; + ShrinkToUsedDataArea(bShrunk, nStartCol, nY1, nEndCol, nY2, /*bColumnsOnly*/false, false, false, nullptr); + for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol) { if (!ColHidden(nCol)) { @@ -2566,13 +2588,20 @@ void ScTable::FindMaxRotCol( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCC OUString aStyleName = static_cast<const ScCondFormatEntry*>(pEntry)->GetStyle(); if (!aStyleName.isEmpty()) { - SfxStyleSheetBase* pStyleSheet = - pStylePool->Find( aStyleName, SfxStyleFamily::Para ); + SfxStyleSheetBase* pStyleSheet; + auto it = aStyleSheetCache.find(aStyleName); + if (it != aStyleSheetCache.end()) + pStyleSheet = it->second; + else + { + pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Para ); + aStyleSheetCache.insert({aStyleName, pStyleSheet}); + } if ( pStyleSheet ) { FillMaxRot( pRowInfo, nArrCount, nX1, nX2, nCol, nAttrRow1, nAttrRow2, - nArrY, pPattern, &pStyleSheet->GetItemSet() ); + nArrY, pPattern, &pStyleSheet->GetItemSet(), &aCacheMap); // not changing nArrY } } @@ -2584,7 +2613,7 @@ void ScTable::FindMaxRotCol( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCC nArrY = FillMaxRot( pRowInfo, nArrCount, nX1, nX2, nCol, nAttrRow1, nAttrRow2, - nArrY, pPattern, nullptr ); + nArrY, pPattern, nullptr, &aCacheMap ); pPattern = aIter.GetNext( nAttrCol, nAttrRow1, nAttrRow2 ); }