sc/inc/document.hxx                |    9 +++++
 sc/inc/table.hxx                   |   18 ++++++----
 sc/source/core/data/column2.cxx    |    6 +--
 sc/source/core/data/documen4.cxx   |    2 -
 sc/source/core/data/document.cxx   |   31 ++++++++++++++----
 sc/source/core/data/table1.cxx     |   63 +++++++++++++++++++++----------------
 sc/source/core/data/table2.cxx     |    2 -
 sc/source/core/data/table3.cxx     |    4 +-
 sc/source/core/data/table4.cxx     |   14 ++++----
 sc/source/core/data/table7.cxx     |    2 -
 sc/source/filter/dif/difimp.cxx    |    2 -
 sc/source/filter/html/htmlexp2.cxx |    4 --
 sc/source/ui/unoobj/docuno.cxx     |    2 -
 sc/source/ui/view/tabview2.cxx     |   12 +++++--
 14 files changed, 110 insertions(+), 61 deletions(-)

New commits:
commit fe703f245d4419861f7840c945183b4bed41cd81
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Wed Apr 27 18:36:56 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Tue May 3 19:57:24 2022 +0200

    fix horizontal Calc cursor skipping
    
    UITest_calc_tests' columns.CalcColumns.test_column_hide_show fails
    with INITIALCOLCOUNT being 1 because column C was hidden, but
    searching only up to the first allocated column + 1 searched only
    up to column B. Whether an entire column is hidden is not part
    of ScColumn, it's stored in ScTable.
    
    Change-Id: Ib1befe5cd0db8d50a6196bc6621fb1b0967e6209
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133524
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/source/ui/view/tabview2.cxx b/sc/source/ui/view/tabview2.cxx
index 49167895a182..1c2cbd1389e6 100644
--- a/sc/source/ui/view/tabview2.cxx
+++ b/sc/source/ui/view/tabview2.cxx
@@ -739,8 +739,16 @@ void ScTabView::SkipCursorHorizontal(SCCOL& rCurX, SCROW& 
rCurY, SCCOL nOldX, SC
 
     bool bSkipCell = false;
     bool bHFlip = false;
-    // search also the first unallocated column (all unallocated columns share 
a set of attrs)
-    SCCOL nMaxCol = std::min<SCCOL>( rDoc.GetAllocatedColumnsCount(nTab) + 1, 
rDoc.MaxCol());
+    // If a number of last columns are hidden, search up to and including the 
first of them,
+    // because after it nothing changes.
+    SCCOL nMaxCol;
+    if(rDoc.ColHidden(rDoc.MaxCol(), nTab, &nMaxCol))
+        ++nMaxCol;
+    else
+        nMaxCol = rDoc.MaxCol();
+    // Search also at least up to and including the first unallocated column 
(all unallocated columns
+    // share a set of attrs).
+    nMaxCol = std::max( nMaxCol, std::min<SCCOL>( 
rDoc.GetAllocatedColumnsCount(nTab) + 1, rDoc.MaxCol()));
     do
     {
         bSkipCell = rDoc.ColHidden(rCurX, nTab) || rDoc.IsHorOverlapped(rCurX, 
rCurY, nTab);
commit 6f0e08a8cd92caa8a2c01e82559ceddb451b6721
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Fri Apr 22 10:03:47 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Tue May 3 19:57:24 2022 +0200

    fix an off-by-one error in GetEmptyLinesInBlock()
    
    The function has been there since the initial commit and is not
    documented, but I think it counts the shortest amount of empty
    cells in the given area starting from the direction given. And
    AFAICT the off-by-one error was there since the initial commit,
    when it returned one less if the entire area was empty and
    the direction was vertical (horizontal was fine). And
    ScHTMLExport::FillGraphList() even was adjusted for this until
    my recent commit changing that code). But then ad2bc869bfe2d34bde
    added a shortcut for unallocated columns that didn't have
    the error. And the error even got corrected during the rewrite
    in c008dc483f8c6840803983e7e351cec6fdd32070, but then
    01de94471c20a8b9c36d6080638d70e57eac55bf reverted that. Anyway,
    so fix this, I think all the relevant code should(?) now work
    properly.
    
    Change-Id: I194691f7276a1cea75945de05cb0dda2cdca859a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133319
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index e4b57138794a..fc96571c0b5d 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1527,6 +1527,7 @@ public:
                                                  SCCOL& rEndCol, SCROW nEndRow 
) const;
     SC_DLLPUBLIC bool           IsEmptyBlock(SCCOL nStartCol, SCROW nStartRow,
                                              SCCOL nEndCol, SCROW nEndRow, 
SCTAB nTab) const;
+    // I think this returns the number of empty cells starting from the given 
direction.
     SC_DLLPUBLIC SCSIZE         GetEmptyLinesInBlock( SCCOL nStartCol, SCROW 
nStartRow, SCTAB nStartTab,
                                                       SCCOL nEndCol, SCROW 
nEndRow, SCTAB nEndTab,
                                                       ScDirection eDir );
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index aeb28bf2ae00..4cd91d93e771 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1328,13 +1328,13 @@ bool ScColumn::IsNotesEmptyBlock(SCROW nStartRow, SCROW 
nEndRow) const
 
 SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, 
ScDirection eDir ) const
 {
-    // Given a range of rows, find a top or bottom empty segment.  Skip the 
start row.
+    // Given a range of rows, find a top or bottom empty segment.
     switch (eDir)
     {
         case DIR_TOP:
         {
             // Determine the length of empty head segment.
-            size_t nLength = nEndRow - nStartRow;
+            size_t nLength = nEndRow - nStartRow + 1;
             std::pair<sc::CellStoreType::const_iterator,size_t> aPos = 
maCells.position(nStartRow);
             sc::CellStoreType::const_iterator it = aPos.first;
             if (it->type != sc::element_type_empty)
@@ -1349,7 +1349,7 @@ SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, 
SCROW nEndRow, ScDirecti
         case DIR_BOTTOM:
         {
             // Determine the length of empty tail segment.
-            size_t nLength = nEndRow - nStartRow;
+            size_t nLength = nEndRow - nStartRow + 1;
             std::pair<sc::CellStoreType::const_iterator,size_t> aPos = 
maCells.position(nEndRow);
             sc::CellStoreType::const_iterator it = aPos.first;
             if (it->type != sc::element_type_empty)
commit fa487acd51833021802871213f8fd2f93bb2d882
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Apr 21 21:56:32 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Tue May 3 19:57:24 2022 +0200

    fix checking whether a block of cells is empty
    
    The GetEmptyLinesInBlock() call has unclear semantics and it appears
    that it has an off-by-one error. Use a simple clear function
    for the check.
    
    Change-Id: I45d9b73428aedababc1ad93c202daa1de945b5bf
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133303
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 566c742e38a1..e4b57138794a 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1525,6 +1525,8 @@ public:
     void                        ExtendPrintArea( OutputDevice* pDev, SCTAB 
nTab,
                                                  SCCOL nStartCol, SCROW 
nStartRow,
                                                  SCCOL& rEndCol, SCROW nEndRow 
) const;
+    SC_DLLPUBLIC bool           IsEmptyBlock(SCCOL nStartCol, SCROW nStartRow,
+                                             SCCOL nEndCol, SCROW nEndRow, 
SCTAB nTab) const;
     SC_DLLPUBLIC SCSIZE         GetEmptyLinesInBlock( SCCOL nStartCol, SCROW 
nStartRow, SCTAB nStartTab,
                                                       SCCOL nEndCol, SCROW 
nEndRow, SCTAB nEndTab,
                                                       ScDirection eDir );
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 2340680ddbea..57a332d8708f 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -619,6 +619,7 @@ public:
     SCROW       GetLastDataRow( SCCOL nCol1, SCCOL nCol2, SCROW nLastRow,
                                 ScDataAreaExtras* pDataAreaExtras = nullptr ) 
const;
 
+    bool        IsEmptyBlock(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, 
SCROW nEndRow) const;
     SCSIZE      GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
                                         SCCOL nEndCol, SCROW nEndRow, 
ScDirection eDir ) const;
 
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 1bfc84ee9824..7cf852ecc9e4 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -6133,6 +6133,13 @@ ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
     return mxPoolHelper->GetStylePool();
 }
 
+bool ScDocument::IsEmptyBlock(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, 
SCROW nEndRow, SCTAB nTab) const
+{
+    if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && 
maTabs[nTab])
+        return maTabs[nTab]->IsEmptyBlock(nStartCol, nStartRow, nEndCol, 
nEndRow);
+    return true;
+}
+
 SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, 
SCTAB nStartTab,
                             SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, 
ScDirection eDir )
 {
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 489b8939bfdf..377dfa3d2114 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -1175,6 +1175,15 @@ SCROW ScTable::GetLastDataRow( SCCOL nCol1, SCCOL nCol2, 
SCROW nLastRow, ScDataA
     return nNewLastRow;
 }
 
+bool ScTable::IsEmptyBlock( SCCOL nStartCol, SCROW nStartRow,
+                            SCCOL nEndCol, SCROW nEndRow ) const
+{
+    for( SCCOL col : GetAllocatedColumnsRange( nStartCol, nEndCol ))
+        if( !aCol[col].IsEmptyBlock( nStartRow, nEndRow ))
+            return false;
+    return true;
+}
+
 SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
                                         SCCOL nEndCol, SCROW nEndRow, 
ScDirection eDir ) const
 {
diff --git a/sc/source/filter/html/htmlexp2.cxx 
b/sc/source/filter/html/htmlexp2.cxx
index 50ff33b6ffc8..acb2f1394167 100644
--- a/sc/source/filter/html/htmlexp2.cxx
+++ b/sc/source/filter/html/htmlexp2.cxx
@@ -89,9 +89,7 @@ void ScHTMLExport::FillGraphList( const SdrPage* pPage, SCTAB 
nTab,
             SCCOL nCol2 = aR.aEnd.Col();
             SCROW nRow2 = aR.aEnd.Row();
             // All cells empty under object?
-            bool bInCell = (pDoc->GetEmptyLinesInBlock(
-                nCol1, nRow1, nTab, nCol2, nRow2, nTab, DIR_TOP )
-                == static_cast< SCSIZE >( nRow2 - nRow1 ));    // rows-1 !
+            bool bInCell = pDoc->IsEmptyBlock( nCol1, nRow1, nCol2, nRow2, 
nTab );
             if ( bInCell )
             {   // Spacing in spanning cell
                 tools::Rectangle aCellRect = pDoc->GetMMRect(
commit 5b89dc537bff62926b1a6174097b873ebd6f351d
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Apr 21 22:33:26 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Tue May 3 19:57:23 2022 +0200

    use range-checked GetCellValue()
    
    Change-Id: Ie02b6be79d1be7481ebcfbc6862295a34e38f7db
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133304
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 93d38c9e3ec4..a0cf373fc95b 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -1867,7 +1867,7 @@ void ScTable::FillAutoSimple(
             {
                 if (bVertical)      // rInner&:=nRow, rOuter&:=nCol
                 {
-                    aSrcCell = aCol[rCol].GetCellValue(nSource);
+                    aSrcCell = GetCellValue(rCol, nSource);
                     if (nISrcStart == nISrcEnd && aSrcCell.meType == 
CELLTYPE_FORMULA)
                     {
                         FillFormulaVertical(*aSrcCell.mpFormula, rInner, rCol, 
nIStart, nIEnd, pProgress, rProgress);
@@ -1881,7 +1881,7 @@ void ScTable::FillAutoSimple(
                 }
                 else                // rInner&:=nCol, rOuter&:=nRow
                 {
-                    aSrcCell = aCol[nSource].GetCellValue(rRow);
+                    aSrcCell = GetCellValue(nSource, rRow);
                     const SvNumFormatType nFormatType = 
rDocument.GetFormatTable()->GetType(
                                 aCol[nSource].GetNumberFormat( 
rDocument.GetNonThreadedContext(), rRow));
                     bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL);
@@ -2207,9 +2207,9 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL 
nCol2, SCROW nRow2,
         // it is still a good upper estimation.
         ScCellValue aSrcCell;
         if (bVertical)
-            aSrcCell = 
aCol[static_cast<SCCOL>(nOStart)].GetCellValue(static_cast<SCROW>(nISource));
+            aSrcCell = GetCellValue(static_cast<SCCOL>(nOStart), 
static_cast<SCROW>(nISource));
         else
-            aSrcCell = 
aCol[static_cast<SCCOL>(nISource)].GetCellValue(static_cast<SCROW>(nOStart));
+            aSrcCell = GetCellValue(static_cast<SCCOL>(nISource), 
static_cast<SCROW>(nOStart));
         // Same logic as for the actual series.
         if (!aSrcCell.isEmpty() && (aSrcCell.meType == CELLTYPE_VALUE || 
aSrcCell.meType == CELLTYPE_FORMULA))
         {
@@ -2263,7 +2263,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL 
nCol2, SCROW nRow2,
         CreateColumnIfNotExists(nCol);
 
         // Source cell value. We need to clone the value since it may be 
inserted repeatedly.
-        ScCellValue aSrcCell = 
aCol[nCol].GetCellValue(static_cast<SCROW>(nRow));
+        ScCellValue aSrcCell = GetCellValue(nCol, static_cast<SCROW>(nRow));
 
         // Maybe another source cell need to be searched, if the fill is going 
through merged cells,
         // where overlapped parts does not contain any information, so they 
can be skipped.
@@ -2288,9 +2288,9 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL 
nCol2, SCROW nRow2,
 
             //Set the real source cell
             if (bVertical)
-                aSrcCell = 
aCol[nOStart].GetCellValue(static_cast<SCROW>(nFirstValueIdx));
+                aSrcCell = GetCellValue(nOStart, 
static_cast<SCROW>(nFirstValueIdx));
             else
-                aSrcCell = 
aCol[nFirstValueIdx].GetCellValue(static_cast<SCROW>(nOStart));
+                aSrcCell = GetCellValue(nFirstValueIdx, 
static_cast<SCROW>(nOStart));
         }
 
         const ScPatternAttr* pSrcPattern = 
aCol[nCol].GetPattern(static_cast<SCROW>(nRow));
commit 427c4aa9ec13ca07d61178ab2a449470392ac0a7
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Apr 21 21:03:59 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Tue May 3 19:57:23 2022 +0200

    simply return from a loop
    
    Change-Id: I4e10945f32dfb535663ea7392f19532e45ca9ee3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133301
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 37fce167410e..489b8939bfdf 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -1234,11 +1234,10 @@ bool ScTable::IsEmptyLine( SCROW nRow, SCCOL nStartCol, 
SCCOL nEndCol ) const
 
     nEndCol   = std::min<SCCOL>( nEndCol,   aCol.size()-1 );
 
-    bool bFound = false;
-    for (SCCOL i=nStartCol; i<=nEndCol && !bFound; i++)
+    for (SCCOL i=nStartCol; i<=nEndCol; i++)
         if (aCol[i].HasDataAt(nRow))
-            bFound = true;
-    return !bFound;
+            return false;
+    return true;
 }
 
 void ScTable::LimitChartArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& 
rEndCol, SCROW& rEndRow ) const
commit fd54ffec2defdd78ed7f203026b51c5a7034c291
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Apr 21 19:54:53 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Tue May 3 19:57:23 2022 +0200

    fix off-by-one error
    
    Change-Id: Ic58a896a7a2edf5ba602ab9cfc5a4578fd5d0a56
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133296
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 892555995e43..37fce167410e 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -318,7 +318,7 @@ ScTable::~ScTable() COVERITY_NOEXCEPT_FALSE
 {
     if (!rDocument.IsInDtorClear())
     {
-        for (SCCOL nCol = 0; nCol < (aCol.size() - 1); ++nCol)
+        for (SCCOL nCol = 0; nCol < aCol.size(); ++nCol)
         {
             aCol[nCol].FreeNotes();
         }
commit df629d0a5c854589e5e1f133713a5efa8156ae8c
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Apr 21 19:11:38 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Tue May 3 19:57:23 2022 +0200

    rework GetColumnsRange() and ScColumnsRange
    
    The problem with GetColumnsRange() was that it was clamping the range
    to the number of allocated columns, but that's not always wanted,
    e.g. ScDocument::InsertMatrixFormula() needs to iterate over the whole
    range and allocate columns if necessary instead of ignoring them.
    From an API point of view it's also not very obvious that something
    called GetColumnsRange() actually does something more than just
    returning the given range.
    
    Handle this by making GetColumnsRange() return the actual given range,
    and add GetWriteableColumnsRange() and GetAllocatedColumnsRange()
    for the specific cases. This also required changing ScColumnsRange
    to work simply on SCCOL value instead of using std::vector iterator
    (since the vector may not have all the elements in the range).
    
    Change-Id: I9b645459461efe6b282e8ac5d7a29549830f46c1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133295
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index c2c597983cea..566c742e38a1 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -2600,6 +2600,12 @@ public:
     void                finalizeOutlineImport();
     bool                TableExists( SCTAB nTab ) const;
 
+    // Returns the given column range, first allocating all the columns if 
necessary.
+    SC_DLLPUBLIC ScColumnsRange GetWritableColumnsRange(SCTAB nTab, SCCOL 
nColBegin, SCCOL nColEnd);
+    // Returns a column range, clamped to the allocated columns.
+    SC_DLLPUBLIC ScColumnsRange GetAllocatedColumnsRange(SCTAB nTab, SCCOL 
nColBegin, SCCOL nColEnd) const;
+    // Returns the given range, without any adjustments. One of the variants 
above may return
+    // a smaller range (better performance) if the use case is known.
     SC_DLLPUBLIC ScColumnsRange GetColumnsRange(SCTAB nTab, SCCOL nColBegin, 
SCCOL nColEnd) const;
 
     bool IsInDocShellRecalc() const   { return mbDocShellRecalc; }
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 8ec17616dc1f..2340680ddbea 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -123,7 +123,7 @@ class ScColumnsRange final
  public:
     class Iterator final
     {
-        std::vector<std::unique_ptr<ScColumn, 
o3tl::default_delete<ScColumn>>>::const_iterator maColIter;
+        SCCOL mCol;
     public:
         typedef std::input_iterator_tag iterator_category;
         typedef SCCOL value_type;
@@ -131,17 +131,18 @@ class ScColumnsRange final
         typedef const SCCOL* pointer;
         typedef SCCOL reference;
 
-        explicit Iterator(const std::vector<std::unique_ptr<ScColumn, 
o3tl::default_delete<ScColumn>>>::const_iterator& colIter) : maColIter(colIter) 
{}
+        explicit Iterator(SCCOL nCol) : mCol(nCol) {}
 
-        Iterator& operator++() { ++maColIter; return *this;}
-        Iterator& operator--() { --maColIter; return *this;}
+        Iterator& operator++() { ++mCol; return *this;}
+        Iterator& operator--() { --mCol; return *this;}
 
-        bool operator==(const Iterator & rOther) const {return maColIter == 
rOther.maColIter;}
+        // Comparing iterators from different containers is undefined, so 
comparing mCol is enough.
+        bool operator==(const Iterator & rOther) const {return mCol == 
rOther.mCol;}
         bool operator!=(const Iterator & rOther) const {return !(*this == 
rOther);}
-        SCCOL operator*() const {return (*maColIter)->GetCol();}
+        SCCOL operator*() const {return mCol;}
     };
 
-    ScColumnsRange(const Iterator & rBegin, const Iterator & rEnd) : 
maBegin(rBegin), maEnd(rEnd) {}
+    ScColumnsRange(SCCOL nBegin, SCCOL nEnd) : maBegin(nBegin), maEnd(nEnd) {}
     const Iterator & begin() { return maBegin; }
     const Iterator & end() { return maEnd; }
     std::reverse_iterator<Iterator> rbegin() { return 
std::reverse_iterator<Iterator>(maEnd); }
@@ -1111,6 +1112,8 @@ public:
     */
     static void UpdateSearchItemAddressForReplace( const SvxSearchItem& 
rSearchItem, SCCOL& rCol, SCROW& rRow );
 
+    ScColumnsRange GetWritableColumnsRange(SCCOL begin, SCCOL end);
+    ScColumnsRange GetAllocatedColumnsRange(SCCOL begin, SCCOL end) const;
     ScColumnsRange GetColumnsRange(SCCOL begin, SCCOL end) const;
     SCCOL ClampToAllocatedColumns(SCCOL nCol) const { return std::min(nCol, 
static_cast<SCCOL>(aCol.size() - 1)); }
     SCCOL GetAllocatedColumnsCount() const { return aCol.size(); }
diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx
index de75f206b34e..cf9a2fbd0a83 100644
--- a/sc/source/core/data/documen4.cxx
+++ b/sc/source/core/data/documen4.cxx
@@ -332,7 +332,7 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW 
nRow1,
             *t->GetSingleRef() = aRefData;
         }
 
-        for (SCCOL nCol : GetColumnsRange(nTab1, nCol1, nCol2))
+        for (SCCOL nCol : GetWritableColumnsRange(nTab1, nCol1, nCol2))
         {
             for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
             {
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 0ee24ea0ab8c..1bfc84ee9824 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2541,15 +2541,27 @@ const ScTable* ScDocument::FetchTable( SCTAB nTab ) 
const
     return maTabs[nTab].get();
 }
 
-ScColumnsRange ScDocument::GetColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL 
nColEnd) const
+ScColumnsRange ScDocument::GetWritableColumnsRange( SCTAB nTab, SCCOL 
nColBegin, SCCOL nColEnd)
 {
     if (!TableExists(nTab))
     {
-        std::vector<std::unique_ptr<ScColumn, o3tl::default_delete<ScColumn>>> 
aEmptyVector;
-        return ScColumnsRange(ScColumnsRange::Iterator(aEmptyVector.begin()),
-                              ScColumnsRange::Iterator(aEmptyVector.end()));
+        SAL_WARN("sc",  "GetWritableColumnsRange() called for non-existent 
table");
+        return ScColumnsRange(-1, -1);
     }
+    return maTabs[nTab]->GetWritableColumnsRange(nColBegin, nColEnd);
+}
 
+ScColumnsRange ScDocument::GetAllocatedColumnsRange( SCTAB nTab, SCCOL 
nColBegin, SCCOL nColEnd) const
+{
+    if (!TableExists(nTab))
+        return ScColumnsRange(-1, -1);
+    return maTabs[nTab]->GetAllocatedColumnsRange(nColBegin, nColEnd);
+}
+
+ScColumnsRange ScDocument::GetColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL 
nColEnd) const
+{
+    if (!TableExists(nTab))
+        return ScColumnsRange(-1, -1);
     return maTabs[nTab]->GetColumnsRange(nColBegin, nColEnd);
 }
 
@@ -6860,7 +6872,7 @@ ScAddress ScDocument::GetNotePosition( size_t nIndex ) 
const
 {
     for (size_t nTab = 0; nTab < maTabs.size(); ++nTab)
     {
-        for (SCCOL nCol : GetColumnsRange(nTab, 0, MaxCol()))
+        for (SCCOL nCol : GetAllocatedColumnsRange(nTab, 0, MaxCol()))
         {
             size_t nColNoteCount = GetNoteCount(nTab, nCol);
             if (!nColNoteCount)
@@ -6887,7 +6899,7 @@ ScAddress ScDocument::GetNotePosition( size_t nIndex ) 
const
 
 ScAddress ScDocument::GetNotePosition( size_t nIndex, SCTAB nTab ) const
 {
-    for (SCCOL nCol : GetColumnsRange(nTab, 0, MaxCol()))
+    for (SCCOL nCol : GetAllocatedColumnsRange(nTab, 0, MaxCol()))
     {
         size_t nColNoteCount = GetNoteCount(nTab, nCol);
         if (!nColNoteCount)
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 311a3756d817..892555995e43 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2670,31 +2670,34 @@ const ScConditionalFormatList* 
ScTable::GetCondFormList() const
     return mpCondFormatList.get();
 }
 
-ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const
+ScColumnsRange ScTable::GetWritableColumnsRange(SCCOL nColBegin, SCCOL nColEnd)
+{
+    // because the range is inclusive, some code will pass nColEnd<nColBegin 
to indicate an empty range
+    if (nColEnd < nColBegin)
+        return ScColumnsRange(-1, -1);
+    assert( nColEnd >= 0 && nColEnd <= GetDoc().MaxCol());
+    CreateColumnIfNotExists(nColEnd);
+    return GetColumnsRange(nColBegin, nColEnd);
+}
+
+ScColumnsRange ScTable::GetAllocatedColumnsRange(SCCOL nColBegin, SCCOL 
nColEnd) const
 {
-    ScColContainer::ScColumnVector::const_iterator beginIter;
-    ScColContainer::ScColumnVector::const_iterator endIter;
+    if (nColBegin >= aCol.size())
+        return ScColumnsRange(-1, -1);
+    // clamp end of range to available columns
+    if (nColEnd >= aCol.size())
+        nColEnd = aCol.size() - 1;
+    return GetColumnsRange(nColBegin, nColEnd);
+}
 
+ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const
+{
     // because the range is inclusive, some code will pass nColEnd<nColBegin 
to indicate an empty range
     if (nColEnd < nColBegin)
-    {
-        beginIter = aCol.end();
-        endIter = aCol.end();
-    }
-    else if (nColBegin >= aCol.size())
-    {
-        beginIter = aCol.end();
-        endIter = aCol.end();
-    }
-    else
-    {
-        // clamp end of range to available columns
-        if (nColEnd >= aCol.size())
-            nColEnd = aCol.size() - 1;
-        beginIter = aCol.begin() + nColBegin;
-        endIter = aCol.begin() + nColEnd + 1;
-    }
-    return ScColumnsRange(ScColumnsRange::Iterator(beginIter), 
ScColumnsRange::Iterator(endIter));
+        return ScColumnsRange(-1, -1);
+    assert( nColBegin >= 0 && nColBegin <= GetDoc().MaxCol());
+    assert( nColEnd >= 0 && nColEnd <= GetDoc().MaxCol());
+    return ScColumnsRange(nColBegin, nColEnd + 1); // change inclusive end to 
past-end
 }
 
 // out-of-line the cold part of the CreateColumnIfNotExists function
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 415507f313e1..19707dff4403 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -260,7 +260,7 @@ bool ScTable::TestInsertCol( SCROW nStartRow, SCROW 
nEndRow, SCSIZE nSize ) cons
         && ! pOutlineTable->TestInsertCol(nSize) )
             return false;
 
-    auto range = GetColumnsRange( rDocument.MaxCol() - 
static_cast<SCCOL>(nSize) + 1, rDocument.MaxCol() );
+    auto range = GetAllocatedColumnsRange( rDocument.MaxCol() - 
static_cast<SCCOL>(nSize) + 1, rDocument.MaxCol() );
     for (auto it = range.rbegin(); it != range.rend(); ++it )
         if (! aCol[*it].TestInsertCol(nStartRow, nEndRow))
             return false;
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 3508c183e85f..c99bc9f8c7ce 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -1927,12 +1927,12 @@ public:
         SCCOL nStartCol = mrParam.nCol1;
         SCCOL nEndCol = mrParam.nCol2;
 
-        for (SCCOL nCol : mrTab.GetColumnsRange(0, nStartCol - 1))
+        for (SCCOL nCol : mrTab.GetAllocatedColumnsRange(0, nStartCol - 1))
         {
             if (mrTab.HasData(nCol, nRow))
                 return true;
         }
-        for (SCCOL nCol : mrTab.GetColumnsRange(nEndCol + 1, 
mrTab.GetDoc().MaxCol()))
+        for (SCCOL nCol : mrTab.GetAllocatedColumnsRange(nEndCol + 1, 
mrTab.GetDoc().MaxCol()))
         {
             if (mrTab.HasData(nCol, nRow))
                 return true;
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
index dc3a8c045dd9..30788b0daca7 100644
--- a/sc/source/core/data/table7.cxx
+++ b/sc/source/core/data/table7.cxx
@@ -321,7 +321,7 @@ void ScTable::EndListeningIntersectedGroups(
     if (nCol2 < nCol1 || !IsColValid(nCol1) || !ValidCol(nCol2))
         return;
 
-    for (SCCOL nCol : GetColumnsRange(nCol1, nCol2))
+    for (SCCOL nCol : GetAllocatedColumnsRange(nCol1, nCol2))
         aCol[nCol].EndListeningIntersectedGroups(rCxt, nRow1, nRow2, 
pGroupPos);
 }
 
diff --git a/sc/source/filter/dif/difimp.cxx b/sc/source/filter/dif/difimp.cxx
index 5f7178b9fe8a..cf5953c81c99 100644
--- a/sc/source/filter/dif/difimp.cxx
+++ b/sc/source/filter/dif/difimp.cxx
@@ -683,7 +683,7 @@ void DifAttrCache::SetNumFormat( const ScDocument* pDoc, 
const SCCOL nCol, const
 
 void DifAttrCache::Apply( ScDocument& rDoc, SCTAB nTab )
 {
-    for( SCCOL nCol : rDoc.GetColumnsRange(nTab, 0, rDoc.MaxCol()) )
+    for( SCCOL nCol : rDoc.GetWritableColumnsRange(nTab, 0, rDoc.MaxCol()) )
     {
         if( maColMap.count(nCol) )
             maColMap[ nCol ]->Apply( rDoc, nCol, nTab );
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index 85dec63985b1..694ee5dc09e1 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -4627,7 +4627,7 @@ sal_Int32 SAL_CALL ScAnnotationsObj::getCount()
     if (pDocShell)
     {
         const ScDocument& rDoc = pDocShell->GetDocument();
-        for (SCCOL nCol : rDoc.GetColumnsRange(nTab, 0, rDoc.MaxCol()))
+        for (SCCOL nCol : rDoc.GetAllocatedColumnsRange(nTab, 0, 
rDoc.MaxCol()))
             nCount += rDoc.GetNoteCount(nTab, nCol);
     }
     return nCount;

Reply via email to