sc/inc/column.hxx                |    1 
 sc/inc/document.hxx              |    2 +
 sc/inc/table.hxx                 |    1 
 sc/source/core/data/column3.cxx  |   66 +++++++++++++++++++++++++++++++++++++--
 sc/source/core/data/document.cxx |   17 ++++++++++
 sc/source/core/data/table1.cxx   |    7 ++++
 sc/source/ui/view/output2.cxx    |    5 ++
 7 files changed, 96 insertions(+), 3 deletions(-)

New commits:
commit b9cf92fbee77ddc34903b3ccbc2a1de7f17903a7
Author:     Luboš Luňák <[email protected]>
AuthorDate: Mon Apr 4 17:52:04 2022 +0200
Commit:     Andras Timar <[email protected]>
CommitDate: Wed May 18 10:48:56 2022 +0200

    try to limit cell interpreting to only visible cells when drawing
    
    If there's a document with a huge formula group, InterpretDirtyCells()
    on load will only interpret the range needed for drawing. But then
    scrolling just a bit could result in e.g. IsValue() call on a cell,
    and that could result in unrestricted Interpret() on the whole
    huge formula group, which could be slow. So explicitly interpret
    just the drawn cells in the hope that it'll avoid any further
    Interpret() calls.
    
    Change-Id: I01c9f95cf8a1cf240b798feef27d21010957030c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133306
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <[email protected]>
    (cherry picked from commit 64cb1d10fffccebbc825c858083f13eb717b0553)

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index fd1b42a0f81b..5658915007a1 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -714,6 +714,7 @@ public:
     bool IsDrawObjectsEmptyBlock(SCROW nStartRow, SCROW nEndRow) const;
 
     void InterpretDirtyCells( SCROW nRow1, SCROW nRow2 );
+    void InterpretCellsIfNeeded( SCROW nRow1, SCROW nRow2 );
 
     static void JoinNewFormulaCell( const sc::CellStoreType::position_type& 
aPos, ScFormulaCell& rCell );
 
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index fc96571c0b5d..76798748e04f 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1359,6 +1359,8 @@ public:
     void              SetDirty( const ScRange&, bool bIncludeEmptyCells );
     void              SetTableOpDirty( const ScRange& );  // for Interpreter 
TableOp
     void              InterpretDirtyCells( const ScRangeList& rRanges );
+    // Interprets cells that have NeedsInterpret(), i.e. the same like calling 
MaybeInterpret() on them.
+    void              InterpretCellsIfNeeded( const ScRangeList& rRanges );
     SC_DLLPUBLIC void CalcAll();
     SC_DLLPUBLIC void CalcAfterLoad( bool bStartListening = true );
     void              CompileAll();
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 57a332d8708f..4e4e9d8d00c3 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -1051,6 +1051,7 @@ public:
     void FillMatrix( ScMatrix& rMat, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, 
SCROW nRow2, svl::SharedStringPool* pPool ) const;
 
     void InterpretDirtyCells( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW 
nRow2 );
+    void InterpretCellsIfNeeded( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW 
nRow2 );
 
     void SetFormulaResults( SCCOL nCol, SCROW nRow, const double* pResults, 
size_t nLen );
 
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index ba494e62bb98..851abbad39ba 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -104,13 +104,11 @@ void ScColumn::BroadcastRows( SCROW nStartRow, SCROW 
nEndRow, SfxHintId nHint )
 
 namespace {
 
-class DirtyCellInterpreter
+class CellInterpreterBase
 {
-public:
-    void operator() (size_t, ScFormulaCell* p)
+protected:
+    void Interpret(ScFormulaCell* p)
     {
-        if(!p->GetDirty())
-            return;
         // Interpret() takes a range in a formula group, so group those 
together.
         if( firstCell != nullptr && p->GetCellGroup() == p->GetCellGroup()
             && p->aPos.Row() == lastPos.Row() + 1 )
@@ -129,7 +127,7 @@ public:
         lastPos = p->aPos;
 
     }
-    ~DirtyCellInterpreter()
+    ~CellInterpreterBase()
     {
         flushPending();
     }
@@ -146,6 +144,26 @@ private:
     ScAddress lastPos;
 };
 
+class DirtyCellInterpreter : public CellInterpreterBase
+{
+public:
+    void operator() (size_t, ScFormulaCell* p)
+    {
+        if(p->GetDirty())
+            Interpret(p);
+    }
+};
+
+class NeedsInterpretCellInterpreter : public CellInterpreterBase
+{
+public:
+    void operator() (size_t, ScFormulaCell* p)
+    {
+        if(p->NeedsInterpret())
+            Interpret(p);
+    }
+};
+
 }
 
 void ScColumn::InterpretDirtyCells( SCROW nRow1, SCROW nRow2 )
@@ -157,6 +175,15 @@ void ScColumn::InterpretDirtyCells( SCROW nRow1, SCROW 
nRow2 )
     sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
 }
 
+void ScColumn::InterpretCellsIfNeeded( SCROW nRow1, SCROW nRow2 )
+{
+    if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > 
nRow2)
+        return;
+
+    NeedsInterpretCellInterpreter aFunc;
+    sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
+}
+
 void ScColumn::DeleteContent( SCROW nRow, bool bBroadcast )
 {
     sc::CellStoreType::position_type aPos = maCells.position(nRow);
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 7cf852ecc9e4..9847e1f60bea 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -3935,6 +3935,23 @@ void ScDocument::InterpretDirtyCells( const ScRangeList& 
rRanges )
     mpFormulaGroupCxt.reset();
 }
 
+void ScDocument::InterpretCellsIfNeeded( const ScRangeList& rRanges )
+{
+    for (size_t nPos=0, nRangeCount = rRanges.size(); nPos < nRangeCount; 
nPos++)
+    {
+        const ScRange& rRange = rRanges[nPos];
+        for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); 
++nTab)
+        {
+            ScTable* pTab = FetchTable(nTab);
+            if (!pTab)
+                return;
+
+            pTab->InterpretCellsIfNeeded(
+                rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), 
rRange.aEnd.Row());
+        }
+    }
+}
+
 void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
 {
     if (m_TableOpList.empty())
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 377dfa3d2114..71985c0475e7 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2603,6 +2603,13 @@ void ScTable::InterpretDirtyCells( SCCOL nCol1, SCROW 
nRow1, SCCOL nCol2, SCROW
         aCol[nCol].InterpretDirtyCells(nRow1, nRow2);
 }
 
+void ScTable::InterpretCellsIfNeeded( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, 
SCROW nRow2 )
+{
+    nCol2 = ClampToAllocatedColumns(nCol2);
+    for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+        aCol[nCol].InterpretCellsIfNeeded(nRow1, nRow2);
+}
+
 void ScTable::SetFormulaResults( SCCOL nCol, SCROW nRow, const double* 
pResults, size_t nLen )
 {
     if (!ValidCol(nCol))
diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx
index e10349ed6a06..ce247163c853 100644
--- a/sc/source/ui/view/output2.cxx
+++ b/sc/source/ui/view/output2.cxx
@@ -1552,6 +1552,11 @@ tools::Rectangle ScOutputData::LayoutStrings(bool 
bPixelToLogic, bool bPaint, co
     const SfxItemSet* pOldCondSet = nullptr;
     SvtScriptType nOldScript = SvtScriptType::NONE;
 
+    // Try to limit interpreting to only visible cells. Calling e.g. IsValue()
+    // on a formula cell that needs interpreting would call Interpret()
+    // for the entire formula group, which could be large.
+    mpDoc->InterpretCellsIfNeeded( ScRange( nX1, nY1, nTab, nX2, nY2, nTab ));
+
     // alternative pattern instances in case we need to modify the pattern
     // before processing the cell value.
     std::vector<std::unique_ptr<ScPatternAttr> > aAltPatterns;
commit 90dd39331cbaf68c3fb8ae0f76575082ce843cda
Author:     Luboš Luňák <[email protected]>
AuthorDate: Mon Apr 4 16:30:58 2022 +0200
Commit:     Andras Timar <[email protected]>
CommitDate: Wed May 18 10:48:42 2022 +0200

    limit Interpret() for dirty cells only to the given row range (bsc#1197497)
    
    ScColumn::InterpretDirtyCells() already takes a row range, and Interpret()
    can take a range inside a formula group, so don't lose the information
    in DirtyCellInterpreter, otherwise a whole large formula could be
    interpreted when just a subset would be enough.
    
    Change-Id: I93e5a7a212976be6fd588de6f68204cd1a271348
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133305
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <[email protected]>
    (cherry picked from commit c315a2f7b99fc1dfbc3fc834590d22fbe41ea70f)

diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 84b68b76db39..ba494e62bb98 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -104,13 +104,46 @@ void ScColumn::BroadcastRows( SCROW nStartRow, SCROW 
nEndRow, SfxHintId nHint )
 
 namespace {
 
-struct DirtyCellInterpreter
+class DirtyCellInterpreter
 {
+public:
     void operator() (size_t, ScFormulaCell* p)
     {
-        if (p->GetDirty())
+        if(!p->GetDirty())
+            return;
+        // Interpret() takes a range in a formula group, so group those 
together.
+        if( firstCell != nullptr && p->GetCellGroup() == p->GetCellGroup()
+            && p->aPos.Row() == lastPos.Row() + 1 )
+        {
+            assert( p->aPos.Tab() == lastPos.Tab() && p->aPos.Col() == 
lastPos.Col());
+            lastPos = p->aPos; // Extend range.
+            return;
+        }
+        flushPending();
+        if( !p->GetCellGroup())
+        {
             p->Interpret();
+            return;
+        }
+        firstCell = p;
+        lastPos = p->aPos;
+
+    }
+    ~DirtyCellInterpreter()
+    {
+        flushPending();
+    }
+private:
+    void flushPending()
+    {
+        if(firstCell == nullptr)
+            return;
+        SCROW firstRow = firstCell->GetCellGroup()->mpTopCell->aPos.Row();
+        firstCell->Interpret(firstCell->aPos.Row() - firstRow, lastPos.Row() - 
firstRow);
+        firstCell = nullptr;
     }
+    ScFormulaCell* firstCell = nullptr;
+    ScAddress lastPos;
 };
 
 }

Reply via email to