speedup ScTable::SetDrawPageSize

which calls GetColOffset() with a very large column value, which
causes it to loop, repeatedly searching the hidden-columns
data-structure. With large spreadsheets, this becomes expensive.

Change-Id: If1a1a7f85e2f36273e2de8da41be2756f52be8a5
Signed-off-by: Noel Grandin <noel.grandin@collabora.co.uk>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/5764
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit 86a8a9ec70c039a493986cf78abaa17882f49bd7)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207624
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Noel Grandin
2026-07-06 10:47:56 +02:00
committed by Xisco Fauli
parent f86af27062
commit f478a4f600
4 changed files with 90 additions and 9 deletions
+2
View File
@@ -84,6 +84,8 @@ public:
SCROW countVisibleRows(SCROW nStartRow, SCROW nEndRow) const;
SCCOL countVisibleCols(SCCOL nStartCol, SCCOL nEndCol) const;
SCCOLROW lastHiddenColRow(SCCOLROW nPos, bool bCol) const;
const ScFlatBoolColSegments& getHiddenCols() const { return *mpHiddenCols; }
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+11 -1
View File
@@ -94,13 +94,23 @@ public:
SCCOL mnCol2;
bool mbValue;
};
class RangeIterator
{
public:
explicit RangeIterator(ScFlatBoolColSegments const& rSegs);
bool getFirst(RangeData& rRange);
bool getNext(RangeData& rRange);
private:
ScFlatBoolColSegments const& mrSegs;
};
ScFlatBoolColSegments(SCCOL nMaxCol);
ScFlatBoolColSegments(const ScFlatBoolColSegments& r);
~ScFlatBoolColSegments();
bool setTrue(SCCOL nCol1, SCCOL nCol2);
bool setFalse(SCCOL nCol1, SCCOL nCol2);
bool getRangeData(SCCOL nCol, RangeData& rData);
bool getRangeData(SCCOL nCol, RangeData& rData) const;
void removeSegment(SCCOL nCol1, SCCOL nCol2);
void insertSegment(SCCOL nCol, SCCOL nSize);
+30 -1
View File
@@ -506,6 +506,35 @@ OString ScFlatBoolRowSegments::dumpAsString()
return aOutput.makeStringAndClear();
}
ScFlatBoolColSegments::RangeIterator::RangeIterator(ScFlatBoolColSegments const & rSegs) :
mrSegs(rSegs)
{
}
bool ScFlatBoolColSegments::RangeIterator::getFirst(RangeData& rRange)
{
ScFlatBoolSegmentsImpl::RangeData aData;
if (!mrSegs.mpImpl->getFirst(aData))
return false;
rRange.mnCol1 = static_cast<SCCOL>(aData.mnPos1);
rRange.mnCol2 = static_cast<SCCOL>(aData.mnPos2);
rRange.mbValue = static_cast<bool>(aData.mnValue);
return true;
}
bool ScFlatBoolColSegments::RangeIterator::getNext(RangeData& rRange)
{
ScFlatBoolSegmentsImpl::RangeData aData;
if (!mrSegs.mpImpl->getNext(aData))
return false;
rRange.mnCol1 = static_cast<SCCOL>(aData.mnPos1);
rRange.mnCol2 = static_cast<SCCOL>(aData.mnPos2);
rRange.mbValue = static_cast<bool>(aData.mnValue);
return true;
}
ScFlatBoolColSegments::ScFlatBoolColSegments(SCCOL nMaxCol) :
mpImpl(new ScFlatBoolSegmentsImpl(nMaxCol))
{
@@ -530,7 +559,7 @@ bool ScFlatBoolColSegments::setFalse(SCCOL nCol1, SCCOL nCol2)
return mpImpl->setFalse(static_cast<SCCOLROW>(nCol1), static_cast<SCCOLROW>(nCol2));
}
bool ScFlatBoolColSegments::getRangeData(SCCOL nCol, RangeData& rData)
bool ScFlatBoolColSegments::getRangeData(SCCOL nCol, RangeData& rData) const
{
ScFlatBoolSegmentsImpl::RangeData aData;
if (!mpImpl->getRangeData(static_cast<SCCOLROW>(nCol), aData))
+47 -7
View File
@@ -4494,17 +4494,57 @@ SCROW ScTable::GetRowForHeightPixels(SCROW nStartRow, tools::Long& rStartRowHeig
tools::Long ScTable::GetColOffset( SCCOL nCol, bool bHiddenAsZero ) const
{
tools::Long n = 0;
if ( mpColWidth )
if ( !mpColWidth )
{
auto colWidthIt = mpColWidth->begin();
for (SCCOL i = 0; i < nCol; (++i < nCol) ? ++colWidthIt : (void)false)
if (!( bHiddenAsZero && ColHidden(i) ))
n += *colWidthIt;
OSL_FAIL("GetColumnOffset: Data missing");
return 0;
}
tools::Long n = 0;
if (bHiddenAsZero)
{
// Walk the two data structures in parallel, for performance.
size_t nColWidthIndex;
SCCOL nColWidthRangeEnd;
sal_uInt16 nColWidth = mpColWidth->GetValue(0, nColWidthIndex, nColWidthRangeEnd);
ScFlatBoolColSegments::RangeData aHiddenColsRange;
ScFlatBoolColSegments::RangeIterator aHiddenColsRangeItr(maFilterData.getHiddenCols());
bool bHasHiddenColsRange = aHiddenColsRangeItr.getFirst(aHiddenColsRange);
for (SCCOL i = 0; i < nCol; ++i)
{
// Fetch the next width range if necessary.
if (i > nColWidthRangeEnd)
nColWidth = mpColWidth->GetNextValue(nColWidthIndex, nColWidthRangeEnd);
// Fetch the next hidden cols range if necessary.
if (bHasHiddenColsRange && i > aHiddenColsRange.mnCol2)
bHasHiddenColsRange = aHiddenColsRangeItr.getNext(aHiddenColsRange);
if (!bHasHiddenColsRange)
{
// Zero width, because absence of data implies hidden, see FilterData::colHidden.
}
else if (i >= aHiddenColsRange.mnCol1 && i <= aHiddenColsRange.mnCol2)
{
// Inside a range for which we have "is-hidden" data
if (!aHiddenColsRange.mbValue)
n += nColWidth;
}
else
{
n += nColWidth;
}
}
}
else
{
OSL_FAIL("GetColumnOffset: Data missing");
size_t nColWidthIndex;
SCCOL nColWidthRangeEnd;
sal_uInt16 nColWidth = mpColWidth->GetValue(0, nColWidthIndex, nColWidthRangeEnd);
for (SCCOL i = 0; i < nCol; ++i)
{
if (i > nColWidthRangeEnd)
nColWidth = mpColWidth->GetNextValue(nColWidthIndex, nColWidthRangeEnd);
n += nColWidth;
}
}
return n;
}