diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2022-04-04 17:52:04 +0200 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2022-04-22 14:19:37 +0200 |
commit | 64cb1d10fffccebbc825c858083f13eb717b0553 (patch) | |
tree | bde2e6f19e2e10f691e1118911388c12b52a616c | |
parent | c315a2f7b99fc1dfbc3fc834590d22fbe41ea70f (diff) |
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 <l.lunak@collabora.com>
-rw-r--r-- | sc/inc/column.hxx | 1 | ||||
-rw-r--r-- | sc/inc/document.hxx | 2 | ||||
-rw-r--r-- | sc/inc/table.hxx | 1 | ||||
-rw-r--r-- | sc/source/core/data/column3.cxx | 39 | ||||
-rw-r--r-- | sc/source/core/data/document.cxx | 17 | ||||
-rw-r--r-- | sc/source/core/data/table1.cxx | 7 | ||||
-rw-r--r-- | sc/source/ui/view/output2.cxx | 5 |
7 files changed, 66 insertions, 6 deletions
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 676e3fc0e634..812a2e6b5abc 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -716,6 +716,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 e28992d21cfe..3a19ffa02ffb 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -1362,6 +1362,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 ec78bfa598c5..2e2d78360e73 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -1054,6 +1054,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 3c75230b5c69..795eb8aa2a31 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -103,13 +103,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 ) @@ -128,7 +126,7 @@ public: lastPos = p->aPos; } - ~DirtyCellInterpreter() + ~CellInterpreterBase() { flushPending(); } @@ -145,6 +143,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 ) @@ -156,6 +174,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 c8e951e7b909..7020095fddf2 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -3944,6 +3944,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 16b90b3b7c62..9119aa076e1a 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -2605,6 +2605,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 a507e1da8452..3fbd8eab65e9 100644 --- a/sc/source/ui/view/output2.cxx +++ b/sc/source/ui/view/output2.cxx @@ -1506,6 +1506,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; |