Related: tdf#98844 CreateMatrixFromDoubleRef() for bCalcAsShown ScCellIterator
... to cover ForceArray cases like SUMPRODUCT().
Change-Id: I149ef4a9633f3237d48fc4f2b6011b03bccebc49
Reviewed-on: https://gerrit.libreoffice.org/78721
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx
index e928b97..a2b8dc5 100644
--- a/sc/source/core/tool/interpr5.cxx
+++ b/sc/source/core/tool/interpr5.cxx
@@ -350,7 +350,108 @@ ScMatrixRef ScInterpreter::CreateMatrixFromDoubleRef( const FormulaToken* pToken
if (!pMat || nGlobalError != FormulaError::NONE)
return nullptr;
pDok->FillMatrix(*pMat, nTab1, nCol1, nRow1, nCol2, nRow2);
if (!bCalcAsShown)
{
// Use fast array fill.
pDok->FillMatrix(*pMat, nTab1, nCol1, nRow1, nCol2, nRow2);
}
else
{
// Use slower ScCellIterator to round values.
// TODO: this probably could use CellBucket for faster storage, see
// sc/source/core/data/column2.cxx and FillMatrixHandler, and then be
// moved to a function on its own, and/or squeeze the rounding into a
// similar FillMatrixHandler that would need to keep track of the cell
// position then.
// Set position where the next entry is expected.
SCROW nNextRow = nRow1;
SCCOL nNextCol = nCol1;
// Set last position as if there was a previous entry.
SCROW nThisRow = nRow2;
SCCOL nThisCol = nCol1 - 1;
ScCellIterator aCellIter( pDok, ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
for (bool bHas = aCellIter.first(); bHas; bHas = aCellIter.next())
{
nThisCol = aCellIter.GetPos().Col();
nThisRow = aCellIter.GetPos().Row();
if (nThisCol != nNextCol || nThisRow != nNextRow)
{
// Fill empty between iterator's positions.
for ( ; nNextCol <= nThisCol; ++nNextCol)
{
const SCSIZE nC = nNextCol - nCol1;
const SCSIZE nMatStopRow = ((nNextCol < nThisCol) ? nMatRows : nThisRow - nRow1);
for (SCSIZE nR = nNextRow - nRow1; nR < nMatStopRow; ++nR)
{
pMat->PutEmpty( nC, nR);
}
nNextRow = nRow1;
}
}
if (nThisRow == nRow2)
{
nNextCol = nThisCol + 1;
nNextRow = nRow1;
}
else
{
nNextCol = nThisCol;
nNextRow = nThisRow + 1;
}
const SCSIZE nMatCol = static_cast<SCSIZE>(nThisCol - nCol1);
const SCSIZE nMatRow = static_cast<SCSIZE>(nThisRow - nRow1);
ScRefCellValue aCell( aCellIter.getRefCellValue());
if (aCellIter.isEmpty() || aCell.hasEmptyValue())
{
pMat->PutEmpty( nMatCol, nMatRow);
}
else if (aCell.hasError())
{
pMat->PutError( aCell.mpFormula->GetErrCode(), nMatCol, nMatRow);
}
else if (aCell.hasNumeric())
{
double fVal = aCell.getValue();
// CELLTYPE_FORMULA already stores the rounded value.
if (aCell.meType == CELLTYPE_VALUE)
{
// TODO: this could be moved to ScCellIterator to take
// advantage of the faster ScAttrArray_IterGetNumberFormat.
const ScAddress aAdr( nThisCol, nThisRow, nTab1);
const sal_uInt32 nNumFormat = pDok->GetNumberFormat( mrContext, aAdr);
fVal = pDok->RoundValueAsShown( fVal, nNumFormat, &mrContext);
}
pMat->PutDouble( fVal, nMatCol, nMatRow);
}
else if (aCell.hasString())
{
pMat->PutString( mrStrPool.intern( aCell.getString( pDok)), nMatCol, nMatRow);
}
else
{
assert(!"aCell.what?");
pMat->PutEmpty( nMatCol, nMatRow);
}
}
// Fill empty if iterator's last position wasn't the end.
if (nThisCol != nCol2 || nThisRow != nRow2)
{
for ( ; nNextCol <= nCol2; ++nNextCol)
{
SCSIZE nC = nNextCol - nCol1;
for (SCSIZE nR = nNextRow - nRow1; nR < nMatRows; ++nR)
{
pMat->PutEmpty( nC, nR);
}
nNextRow = nRow1;
}
}
}
if (pToken && pTokenMatrixMap)
pTokenMatrixMap->emplace(pToken, new ScMatrixToken( pMat));