sc/inc/attarray.hxx                    |    1 
 sc/inc/column.hxx                      |   16 ++++++--
 sc/inc/document.hxx                    |    9 +++++
 sc/inc/table.hxx                       |    9 +++--
 sc/qa/unit/subsequent_export_test2.cxx |   33 ++++++++++++++++++
 sc/qa/unit/ucalc.cxx                   |   54 ++++++++++++++++++++++++++++++
 sc/source/core/data/attarray.cxx       |   20 +++++++++++
 sc/source/core/data/column3.cxx        |    2 -
 sc/source/core/data/dociter.cxx        |   59 +++++++++++++++++----------------
 sc/source/core/data/table1.cxx         |   15 ++++++++
 10 files changed, 181 insertions(+), 37 deletions(-)

New commits:
commit 7a9e60c4b7d6c28f5b3e084e3db9ab2445c94bfd
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Wed Mar 9 15:12:43 2022 +0100
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Thu Mar 10 08:34:58 2022 +0100

    fix attr iterators to walk even unallocated columns if needed
    
    Things like applying bold to an entire row no longer allocates
    all rows after my recent changes, but the attribute change is
    done in ScTable to the default attribute of unallocated columns.
    That means that clamping column positions to the end of allocated
    columns is no longer valid when handling attributes. Add functions
    that clamp depending on whether unallocated columns have
    a non-default attribute set.
    
    Change-Id: I879d0a034c0b336064361d0f8cb12e5a8da22b9c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131265
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/inc/attarray.hxx b/sc/inc/attarray.hxx
index 34d1403bcc91..c08da494c142 100644
--- a/sc/inc/attarray.hxx
+++ b/sc/inc/attarray.hxx
@@ -221,6 +221,7 @@ public:
     bool    Reserve( SCSIZE nReserve );
     SCSIZE  Count() const { return mvData.size(); }
     SCSIZE  Count( SCROW nRow1, SCROW nRow2 ) const;
+    bool    HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) const;
 
 private:
     const ScPatternAttr* SetPatternAreaImpl( SCROW nStartRow, SCROW nEndRow, 
const ScPatternAttr* pPattern,
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 0b5fb0aa8ff2..2cf4bdd66573 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -161,6 +161,11 @@ public:
     bool        HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) 
const;
     bool        HasAttrib( SCROW nRow, HasAttrFlags nMask, SCROW* nStartRow = 
nullptr, SCROW* nEndRow = nullptr ) const;
 
+    std::unique_ptr<ScAttrIterator> CreateAttrIterator( SCROW nStartRow, SCROW 
nEndRow ) const;
+
+    bool        IsAllAttrEqual( const ScColumnData& rCol, SCROW nStartRow, 
SCROW nEndRow ) const;
+    bool        HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) const;
+
     void        ClearSelectionItems( const sal_uInt16* pWhich, const 
ScMarkData& rMark, SCCOL nCol );
     void        ChangeSelectionIndent( bool bIncrement, const ScMarkData& 
rMark, SCCOL nCol );
 };
@@ -207,7 +212,6 @@ friend class ScCountIfCellIterator;
 friend class ScFormulaGroupIterator;
 friend class ScCellIterator;
 friend class ScHorizontalCellIterator;
-friend class ScHorizontalAttrIterator;
 friend class ScColumnTextWidthIterator;
 friend class ScDocumentImport;
 friend class sc::DocumentStreamAccess;
@@ -299,7 +303,6 @@ public:
     bool    GetLastVisibleAttr( SCROW& rLastRow ) const;
     bool    HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const;
     bool    IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW 
nEndRow ) const;
-    bool    IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW 
nEndRow ) const;
 
     bool    TestInsertCol( SCROW nStartRow, SCROW nEndRow) const;
     bool TestInsertRow( SCROW nStartRow, SCSIZE nSize ) const;
@@ -348,8 +351,6 @@ public:
         sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, ScPasteFunc 
nFunction, bool bSkipEmpty,
         const ScColumn& rSrcCol );
 
-    std::unique_ptr<ScAttrIterator> CreateAttrIterator( SCROW nStartRow, SCROW 
nEndRow ) const;
-
     void UpdateSelectionFunction(
         const ScRangeList& rRanges, ScFunctionData& rData, const 
ScFlatBoolRowSegments& rHiddenRows );
 
@@ -835,11 +836,16 @@ inline bool ScColumn::IsEmptyAttr() const
     return pAttrArray->IsEmpty();
 }
 
-inline bool ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, 
SCROW nEndRow ) const
+inline bool ScColumnData::IsAllAttrEqual( const ScColumnData& rCol, SCROW 
nStartRow, SCROW nEndRow ) const
 {
     return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow );
 }
 
+inline bool ScColumnData::HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) 
const
+{
+    return pAttrArray->HasNonDefPattern( nStartRow, nEndRow );
+}
+
 inline bool ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW 
nStartRow, SCROW nEndRow ) const
 {
     return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index f9640ab74c6d..734e2d0dcd75 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -821,6 +821,15 @@ public:
 
     SC_DLLPUBLIC SCCOL ClampToAllocatedColumns(SCTAB nTab, SCCOL nCol) const;
     SC_DLLPUBLIC SCCOL GetAllocatedColumnsCount(SCTAB nTab) const;
+    // Limits nCol to the last column that can possibly have a non-default 
pattern. The purpose
+    // is to avoid checking unallocated columns if they don't have attributes 
set, so this is
+    // never less than ClampToAllocatedColumns().
+    SCCOL ClampToMaxNonDefPatternColumn(SCTAB nTab, SCCOL nCol, SCROW nRow1, 
SCROW nRow2) const;
+    SCCOL ClampToMaxNonDefPatternColumn(SCTAB nTab, SCCOL nCol) const
+        { return ClampToMaxNonDefPatternColumn(nTab, nCol, 0, MaxRow()); }
+    SCCOL GetMaxNonDefPatternColumnsCount(SCTAB nTab, SCROW nRow1, SCROW 
nRow2) const;
+    SCCOL GetMaxNonDefPatternColumnsCount(SCTAB nTab) const
+        { return GetMaxNonDefPatternColumnsCount(nTab, 0, MaxRow()); }
 
     SC_DLLPUBLIC ScDBCollection* GetDBCollection() const { return 
pDBCollection.get();}
     void                         SetDBCollection( 
std::unique_ptr<ScDBCollection> pNewDBCollection,
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 7fe49f2722b7..0ad96d4319fd 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -260,9 +260,6 @@ friend class ScCellIterator;
 friend class ScQueryCellIterator;
 friend class ScCountIfCellIterator;
 friend class ScHorizontalCellIterator;
-friend class ScHorizontalAttrIterator;
-friend class ScDocAttrIterator;
-friend class ScAttrRectIterator;
 friend class ScColumnTextWidthIterator;
 friend class ScDocumentImport;
 friend class sc::DocumentStreamAccess;
@@ -1106,6 +1103,12 @@ public:
     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(); }
+    SCCOL ClampToMaxNonDefPatternColumn(SCCOL nCol, SCROW nRow1, SCROW nRow2) 
const;
+    SCCOL ClampToMaxNonDefPatternColumn(SCCOL nCol) const
+        { return ClampToMaxNonDefPatternColumn(nCol, 0, rDocument.MaxRow()); }
+    SCCOL GetMaxNonDefPatternColumnsCount(SCROW nRow1, SCROW nRow2) const;
+    SCCOL GetMaxNonDefPatternColumnsCount() const
+        { return GetMaxNonDefPatternColumnsCount(0, rDocument.MaxRow()); }
 
     /**
      * Serializes the sheet's geometry data.
diff --git a/sc/qa/unit/subsequent_export_test2.cxx 
b/sc/qa/unit/subsequent_export_test2.cxx
index eff1f3b07963..be7469523e67 100644
--- a/sc/qa/unit/subsequent_export_test2.cxx
+++ b/sc/qa/unit/subsequent_export_test2.cxx
@@ -184,6 +184,7 @@ public:
     void testTdf142578();
     void testTdf145059();
     void testTdf130104_XLSXIndent();
+    void testWholeRowBold();
 
     CPPUNIT_TEST_SUITE(ScExportTest2);
 
@@ -301,6 +302,7 @@ public:
     CPPUNIT_TEST(testTdf142578);
     CPPUNIT_TEST(testTdf145059);
     CPPUNIT_TEST(testTdf130104_XLSXIndent);
+    CPPUNIT_TEST(testWholeRowBold);
 
     CPPUNIT_TEST_SUITE_END();
 
@@ -3066,6 +3068,37 @@ void ScExportTest2::testTdf130104_XLSXIndent()
     xDocSh->DoClose();
 }
 
+void ScExportTest2::testWholeRowBold()
+{
+    ScDocShellRef xDocSh1 = loadDoc(u"blank.", FORMAT_ODS);
+    CPPUNIT_ASSERT_MESSAGE("Failed to open empty doc", xDocSh1.is());
+    ScDocument* pDoc = &xDocSh1->GetDocument();
+
+    // Make entire second row row bold.
+    ScPatternAttr boldAttr(pDoc->GetPool());
+    boldAttr.GetItemSet().Put(SvxWeightItem(WEIGHT_BOLD, ATTR_FONT_WEIGHT));
+    pDoc->ApplyPatternAreaTab(0, 1, pDoc->MaxCol(), 1, 0, boldAttr);
+
+    ScDocShellRef xDocSh2 = saveAndReload(*xDocSh1, FORMAT_ODS);
+    CPPUNIT_ASSERT(xDocSh2.is());
+    pDoc = &xDocSh2->GetDocument();
+    // TODO CPPUNIT_ASSERT_EQUAL(SCCOL(INITIALCOLCOUNT), 
pDoc->GetAllocatedColumnsCount(0));
+    vcl::Font aFont;
+    pDoc->GetPattern(pDoc->MaxCol(), 1, 0)->GetFont(aFont, SC_AUTOCOL_RAW);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD, 
aFont.GetWeight());
+
+    ScDocShellRef xDocSh3 = saveAndReload(*xDocSh2, FORMAT_XLSX);
+    CPPUNIT_ASSERT(xDocSh3.is());
+    pDoc = &xDocSh3->GetDocument();
+    // TODO CPPUNIT_ASSERT_EQUAL(SCCOL(INITIALCOLCOUNT), 
pDoc->GetAllocatedColumnsCount(0));
+    pDoc->GetPattern(pDoc->MaxCol(), 1, 0)->GetFont(aFont, SC_AUTOCOL_RAW);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD, 
aFont.GetWeight());
+
+    xDocSh1->DoClose();
+    xDocSh2->DoClose();
+    xDocSh3->DoClose();
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest2);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 980fd23d783d..a3066631aa47 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -114,6 +114,7 @@ public:
     void testHorizontalIterator();
     void testValueIterator();
     void testHorizontalAttrIterator();
+    void testIteratorsUnallocatedColumnsAttributes();
 
     /**
      * More direct test for cell broadcaster management, used to track formula
@@ -244,6 +245,7 @@ public:
     CPPUNIT_TEST(testHorizontalIterator);
     CPPUNIT_TEST(testValueIterator);
     CPPUNIT_TEST(testHorizontalAttrIterator);
+    CPPUNIT_TEST(testIteratorsUnallocatedColumnsAttributes);
     CPPUNIT_TEST(testCellBroadcaster);
     CPPUNIT_TEST(testFuncParam);
     CPPUNIT_TEST(testNamedRange);
@@ -1366,6 +1368,58 @@ void Test::testHorizontalAttrIterator()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testIteratorsUnallocatedColumnsAttributes()
+{
+    m_pDoc->InsertTab(0, "Tab1");
+
+    // Make entire second row and third row bold.
+    ScPatternAttr boldAttr(m_pDoc->GetPool());
+    boldAttr.GetItemSet().Put(SvxWeightItem(WEIGHT_BOLD, ATTR_FONT_WEIGHT));
+    m_pDoc->ApplyPatternAreaTab(0, 1, m_pDoc->MaxCol(), 2, 0, boldAttr);
+
+    // That shouldn't need allocating more columns, just changing the default 
attribute.
+    CPPUNIT_ASSERT_EQUAL(SCCOL(INITIALCOLCOUNT), 
m_pDoc->GetAllocatedColumnsCount(0));
+    vcl::Font aFont;
+    const ScPatternAttr* pattern = m_pDoc->GetPattern(m_pDoc->MaxCol(), 1, 0);
+    pattern->GetFont(aFont, SC_AUTOCOL_RAW);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD, 
aFont.GetWeight());
+
+    // Test iterators.
+    ScDocAttrIterator docit( *m_pDoc, 0, INITIALCOLCOUNT - 1, 1, 
INITIALCOLCOUNT, 2 );
+    SCCOL col1, col2;
+    SCROW row1, row2;
+    CPPUNIT_ASSERT_EQUAL( pattern, docit.GetNext( col1, row1, row2 ));
+    CPPUNIT_ASSERT_EQUAL( SCCOL(INITIALCOLCOUNT - 1), col1 );
+    CPPUNIT_ASSERT_EQUAL( SCROW(1), row1 );
+    CPPUNIT_ASSERT_EQUAL( SCROW(2), row2 );
+    CPPUNIT_ASSERT_EQUAL( pattern, docit.GetNext( col1, row1, row2 ));
+    CPPUNIT_ASSERT_EQUAL( INITIALCOLCOUNT, col1 );
+    CPPUNIT_ASSERT_EQUAL( SCROW(1), row1 );
+    CPPUNIT_ASSERT_EQUAL( SCROW(2), row2 );
+    CPPUNIT_ASSERT( docit.GetNext( col1, row1, row2 ) == nullptr );
+
+    ScAttrRectIterator rectit( *m_pDoc, 0, INITIALCOLCOUNT - 1, 1, 
INITIALCOLCOUNT, 2 );
+    CPPUNIT_ASSERT_EQUAL( pattern, rectit.GetNext( col1, col2, row1, row2 ));
+    CPPUNIT_ASSERT_EQUAL( SCCOL(INITIALCOLCOUNT - 1), col1 );
+    CPPUNIT_ASSERT_EQUAL( INITIALCOLCOUNT, col2 );
+    CPPUNIT_ASSERT_EQUAL( SCROW(1), row1 );
+    CPPUNIT_ASSERT_EQUAL( SCROW(2), row2 );
+    CPPUNIT_ASSERT( rectit.GetNext( col1, col2, row1, row2 ) == nullptr );
+
+    ScHorizontalAttrIterator horit( *m_pDoc, 0, INITIALCOLCOUNT - 1, 1, 
INITIALCOLCOUNT, 2 );
+    CPPUNIT_ASSERT_EQUAL( pattern, horit.GetNext( col1, col2, row1 ));
+    CPPUNIT_ASSERT_EQUAL( SCCOL(INITIALCOLCOUNT - 1), col1 );
+    CPPUNIT_ASSERT_EQUAL( INITIALCOLCOUNT, col2 );
+    CPPUNIT_ASSERT_EQUAL( SCROW(1), row1 );
+    CPPUNIT_ASSERT_EQUAL( pattern, horit.GetNext( col1, col2, row1 ));
+    CPPUNIT_ASSERT_EQUAL( SCCOL(INITIALCOLCOUNT - 1), col1 );
+    CPPUNIT_ASSERT_EQUAL( INITIALCOLCOUNT, col2 );
+    CPPUNIT_ASSERT_EQUAL( SCROW(2), row1 );
+    CPPUNIT_ASSERT( horit.GetNext( col1, col2, row1 ) == nullptr );
+
+    m_pDoc->DeleteTab(0);
+}
+
 namespace {
 
 bool broadcasterShifted(const ScDocument& rDoc, const ScAddress& rFrom, const 
ScAddress& rTo)
diff --git a/sc/source/core/data/attarray.cxx b/sc/source/core/data/attarray.cxx
index f2b4fff835d5..a7ee5ff2276e 100644
--- a/sc/source/core/data/attarray.cxx
+++ b/sc/source/core/data/attarray.cxx
@@ -2681,4 +2681,24 @@ SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW 
nEndRow ) const
     return nIndex2 - nIndex1 + 1;
 }
 
+bool ScAttrArray::HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) const
+{
+    if ( mvData.empty() )
+        return false;
+
+    SCSIZE  nIndex1, nIndex2;
+
+    if( !Search( nStartRow, nIndex1 ) )
+        return false;
+
+    if( !Search( nEndRow, nIndex2 ) )
+        nIndex2 = mvData.size() - 1;
+
+    const ScPatternAttr* defPattern = rDocument.GetDefPattern();
+    for( SCSIZE index = nIndex1; index <= nIndex2; ++index )
+        if( mvData[index].pPattern != defPattern )
+            return true;
+    return false;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 8d38fa54ea45..9e12ad32cacf 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1919,7 +1919,7 @@ void ScColumn::MixData(
     CellStorageModified();
 }
 
-std::unique_ptr<ScAttrIterator> ScColumn::CreateAttrIterator( SCROW nStartRow, 
SCROW nEndRow ) const
+std::unique_ptr<ScAttrIterator> ScColumnData::CreateAttrIterator( SCROW 
nStartRow, SCROW nEndRow ) const
 {
     return std::make_unique<ScAttrIterator>( pAttrArray.get(), nStartRow, 
nEndRow, GetDoc().GetDefPattern() );
 }
diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx
index 28543f720c16..35148072f387 100644
--- a/sc/source/core/data/dociter.cxx
+++ b/sc/source/core/data/dociter.cxx
@@ -2394,7 +2394,7 @@ ScHorizontalAttrIterator::ScHorizontalAttrIterator( 
ScDocument& rDocument, SCTAB
     assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
     assert(rDoc.maTabs[nTab]);
 
-    nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol);
+    nEndCol = rDoc.maTabs[nTab]->ClampToMaxNonDefPatternColumn(nEndCol);
 
     nRow = nStartRow;
     nCol = nStartCol;
@@ -2423,14 +2423,13 @@ void ScHorizontalAttrIterator::InitForNextRow(bool 
bInitialization)
         SCCOL nPos = i - nStartCol;
         if ( bInitialization || pNextEnd[nPos] < nRow )
         {
-            const ScAttrArray* pArray = 
rDoc.maTabs[nTab]->aCol[i].pAttrArray.get();
-            assert(pArray);
+            const ScAttrArray& pArray = 
rDoc.maTabs[nTab]->ColumnData(i).AttrArray();
 
             SCSIZE nIndex;
             if (bInitialization)
             {
-                if ( pArray->Count() )
-                    pArray->Search( nStartRow, nIndex );
+                if ( pArray.Count() )
+                    pArray.Search( nStartRow, nIndex );
                 else
                     nIndex = 0;
                 pIndices[nPos] = nIndex;
@@ -2439,16 +2438,16 @@ void ScHorizontalAttrIterator::InitForNextRow(bool 
bInitialization)
             else
                 nIndex = ++pIndices[nPos];
 
-            if ( !nIndex && !pArray->Count() )
+            if ( !nIndex && !pArray.Count() )
             {
                 pNextEnd[nPos] = rDoc.MaxRow();
                 assert( pNextEnd[nPos] >= nRow && "Sequence out of order" );
                 ppPatterns[nPos] = nullptr;
             }
-            else if ( nIndex < pArray->Count() )
+            else if ( nIndex < pArray.Count() )
             {
-                const ScPatternAttr* pPattern = 
pArray->mvData[nIndex].pPattern;
-                SCROW nThisEnd = pArray->mvData[nIndex].nEndRow;
+                const ScPatternAttr* pPattern = pArray.mvData[nIndex].pPattern;
+                SCROW nThisEnd = pArray.mvData[nIndex].nEndRow;
 
                 if ( IsDefaultItem( pPattern ) )
                     pPattern = nullptr;
@@ -2644,11 +2643,14 @@ ScDocAttrIterator::ScDocAttrIterator(ScDocument& 
rDocument, SCTAB nTable,
     nEndRow( nRow2 ),
     nCol( nCol1 )
 {
-    if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab]
-        && nCol < rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
+    if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab] )
     {
-        nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol);
-        pColIter = rDoc.maTabs[nTab]->aCol[nCol].CreateAttrIterator( 
nStartRow, nEndRow );
+        SCCOL attrColCount = 
rDoc.maTabs[nTab]->GetMaxNonDefPatternColumnsCount(nStartRow, nEndRow);
+        if( nCol < attrColCount )
+        {
+            nEndCol = std::min<SCCOL>(nEndCol,attrColCount - 1);
+            pColIter = rDoc.maTabs[nTab]->ColumnData(nCol).CreateAttrIterator( 
nStartRow, nEndRow );
+        }
     }
 }
 
@@ -2669,7 +2671,7 @@ const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& 
rCol, SCROW& rRow1, SCRO
 
         ++nCol;
         if ( nCol <= nEndCol )
-            pColIter = rDoc.maTabs[nTab]->aCol[nCol].CreateAttrIterator( 
nStartRow, nEndRow );
+            pColIter = rDoc.maTabs[nTab]->ColumnData(nCol).CreateAttrIterator( 
nStartRow, nEndRow );
         else
             pColIter.reset();
     }
@@ -2776,18 +2778,19 @@ ScAttrRectIterator::ScAttrRectIterator(ScDocument& 
rDocument, SCTAB nTable,
     nIterStartCol( nCol1 ),
     nIterEndCol( nCol1 )
 {
-    if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab]
-        && nCol1 < rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
+    if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab] )
     {
-        nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol);
-        pColIter = rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( 
nStartRow, nEndRow );
-        while ( nIterEndCol < nEndCol &&
-                rDoc.maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
-                    rDoc.maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow 
) )
-            ++nIterEndCol;
+        SCCOL attrColCount = 
rDoc.maTabs[nTab]->GetMaxNonDefPatternColumnsCount(nStartRow, nEndRow);
+        if( nCol1 < attrColCount )
+        {
+            nEndCol = std::min<SCCOL>(nEndCol,attrColCount - 1);
+            pColIter = 
rDoc.maTabs[nTab]->ColumnData(nIterStartCol).CreateAttrIterator( nStartRow, 
nEndRow );
+            while ( nIterEndCol < nEndCol &&
+                    rDoc.maTabs[nTab]->ColumnData(nIterEndCol).IsAllAttrEqual(
+                        rDoc.maTabs[nTab]->ColumnData(nIterEndCol+1), 
nStartRow, nEndRow ) )
+                ++nIterEndCol;
+        }
     }
-    else
-        pColIter = nullptr;
 }
 
 ScAttrRectIterator::~ScAttrRectIterator()
@@ -2799,7 +2802,7 @@ void ScAttrRectIterator::DataChanged()
     if (pColIter)
     {
         SCROW nNextRow = pColIter->GetNextRow();
-        pColIter = rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( 
nNextRow, nEndRow );
+        pColIter = 
rDoc.maTabs[nTab]->ColumnData(nIterStartCol).CreateAttrIterator( nNextRow, 
nEndRow );
     }
 }
 
@@ -2820,10 +2823,10 @@ const ScPatternAttr* ScAttrRectIterator::GetNext( 
SCCOL& rCol1, SCCOL& rCol2,
         if ( nIterStartCol <= nEndCol )
         {
             nIterEndCol = nIterStartCol;
-            pColIter = 
rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
+            pColIter = 
rDoc.maTabs[nTab]->ColumnData(nIterStartCol).CreateAttrIterator( nStartRow, 
nEndRow );
             while ( nIterEndCol < nEndCol &&
-                    rDoc.maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
-                        rDoc.maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, 
nEndRow ) )
+                    rDoc.maTabs[nTab]->ColumnData(nIterEndCol).IsAllAttrEqual(
+                        rDoc.maTabs[nTab]->ColumnData(nIterEndCol+1), 
nStartRow, nEndRow ) )
                 ++nIterEndCol;
         }
         else
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 6d9e966eb39a..f48f47ca8a16 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2644,6 +2644,21 @@ ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, 
SCCOL nColEnd) const
     return ScColumnsRange(ScColumnsRange::Iterator(beginIter), 
ScColumnsRange::Iterator(endIter));
 }
 
+SCCOL ScTable::ClampToMaxNonDefPatternColumn(SCCOL nCol, SCROW nRow1, SCROW 
nRow2) const
+{
+    // The purpose so to avoid unallocated columns if possible, so don't check 
allocated ones.
+    if( nCol < GetAllocatedColumnsCount())
+        return nCol;
+    return std::min<SCCOL>(nCol, GetMaxNonDefPatternColumnsCount( nRow1, nRow2 
) - 1 );
+}
+
+SCCOL ScTable::GetMaxNonDefPatternColumnsCount(SCROW nRow1, SCROW nRow2) const
+{
+    if( aDefaultColData.HasNonDefPattern(nRow1, nRow2))
+        return GetDoc().GetMaxColCount();
+    return GetAllocatedColumnsCount();
+}
+
 // out-of-line the cold part of the CreateColumnIfNotExists function
 void ScTable::CreateColumnIfNotExistsImpl( const SCCOL nScCol ) const
 {

Reply via email to