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 );
             }

Reply via email to