sc/inc/table.hxx | 12 +++++++++- sc/source/core/data/table2.cxx | 49 ++++++++++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 11 deletions(-)
New commits: commit f9d457aa4a7c2e6d0913ffdd5c04b96f014dfcf8 Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Tue Feb 25 14:41:30 2025 +0200 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Tue Feb 25 17:48:25 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/+/182165 Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> Reviewed-by: Michael Meeks <michael.me...@collabora.com> Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com> 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 fe3faf8893d3..fe2c87f86aab 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -2454,13 +2454,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; @@ -2535,8 +2552,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)) { @@ -2572,13 +2594,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 } } @@ -2590,7 +2619,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 ); }