sc/inc/table.hxx               |   12 +++++++++-
 sc/source/core/data/table2.cxx |   49 ++++++++++++++++++++++++++++++++---------
 2 files changed, 50 insertions(+), 11 deletions(-)

New commits:
commit 3f5684c527134ca49a91e6efc35bd98b31032935
Author:     Noel Grandin <[email protected]>
AuthorDate: Tue Feb 25 14:41:30 2025 +0200
Commit:     Michael Meeks <[email protected]>
CommitDate: Tue Feb 25 16:12:24 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/+/182170
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Michael Meeks <[email protected]>

diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index d25d67a8e735..35d8c387129d 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -1331,9 +1331,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 643eb6b04384..3bb2eaba278b 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -2417,13 +2417,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;
@@ -2498,8 +2515,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))
         {
@@ -2535,13 +2557,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
                                         }
                                     }
@@ -2553,7 +2582,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 );
             }

Reply via email to