[Libreoffice-commits] core.git: sc/inc sc/source

Dennis Francis dennisfrancis.in at gmail.com
Thu Nov 10 15:12:02 UTC 2016


 sc/inc/attarray.hxx              |   38 +++
 sc/inc/column.hxx                |    2 
 sc/inc/table.hxx                 |    4 
 sc/source/core/data/attarray.cxx |  423 +++++++++++++++++++++++++++++++++------
 sc/source/core/data/column.cxx   |   22 +-
 sc/source/core/data/column2.cxx  |    2 
 sc/source/core/data/column3.cxx  |    4 
 sc/source/core/data/dociter.cxx  |   14 +
 sc/source/core/data/document.cxx |   27 +-
 sc/source/core/data/fillinfo.cxx |   18 +
 sc/source/core/data/table1.cxx   |    5 
 sc/source/core/data/table2.cxx   |    7 
 12 files changed, 477 insertions(+), 89 deletions(-)

New commits:
commit 06d3294502413a231e5c5265609862c7f67a2f2b
Author: Dennis Francis <dennisfrancis.in at gmail.com>
Date:   Fri Apr 15 21:43:42 2016 +0530

    Refactor ScAttrArray for tdf#50916
    
    For a default column, now ScAttrArray does not store the default
    format. So the case of default pattern from 0 to MAXROW is represented
    as nCount = 0 and pData = nullptr in ScAttrArray.
    
    A new ScAttrArray object (aNextColAttrArray) is introduced as a member
    of ScTable. This is used to store the formatting of *unallocated*
    columns (whose indices are from aCol.size() to MAXCOL).
    
    In next patches for this bug, I plan to refactor table*.cxx functions
    related to formatting such that :
    
    1) In formatting setter functions, if colspan of the input range
       spans the colrange(aCol.size() to MAXCOL) then instead of
       allocating columns, apply that formatting to aNextColAttrArray.
    
    2) In formatting getter (const) functions, if requested colspan has some
       intersection with the colrange(aCol.size() to MAXCOL) then use the
       formatting info stored in aNextColAttrArray to calculate the formatting
       of the input range.
    
    3) In general setter (non-const) functions if we really need to allocate
       new columns (example, when data is entered), use the formatting info
       stored in aNextColAttrArray to create pAttrArray of the new column.
    
    Change-Id: Ieb56f853209b396d92fdb2c27e39361703576423
    Reviewed-on: https://gerrit.libreoffice.org/27828
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Eike Rathke <erack at redhat.com>

diff --git a/sc/inc/attarray.hxx b/sc/inc/attarray.hxx
index 2b44040..49626ea 100644
--- a/sc/inc/attarray.hxx
+++ b/sc/inc/attarray.hxx
@@ -100,12 +100,13 @@ friend class ScHorizontalAttrIterator;
 
     void RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow,
                               const ScPatternAttr* pPattern, ScEditDataArray* pDataArray );
+    void SetDefaultIfNotInit( SCSIZE nNeeded = 1 );
 
     ScAttrArray(const ScAttrArray&) = delete;
     ScAttrArray& operator=(const ScAttrArray&) = delete;
 
 public:
-            ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc );
+            ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc, ScAttrArray* pNextColAttrArray = nullptr, bool bCreateEmpty = false );
             ~ScAttrArray();
 
     void    SetTab(SCTAB nNewTab)   { nTab = nNewTab; }
@@ -205,23 +206,30 @@ public:
 class ScAttrIterator
 {
     const ScAttrArray*  pArray;
+    const ScPatternAttr* pDefPattern;
     SCSIZE              nPos;
     SCROW               nRow;
     SCROW               nEndRow;
 public:
-    inline              ScAttrIterator( const ScAttrArray* pNewArray, SCROW nStart, SCROW nEnd );
+    inline              ScAttrIterator( const ScAttrArray* pNewArray, SCROW nStart, SCROW nEnd, const ScPatternAttr* pDefaultPattern );
     inline const ScPatternAttr* Next( SCROW& rTop, SCROW& rBottom );
     inline const ScPatternAttr* Resync( SCROW nRow, SCROW& rTop, SCROW& rBottom );
     SCROW               GetNextRow() const { return nRow; }
 };
 
-inline ScAttrIterator::ScAttrIterator( const ScAttrArray* pNewArray, SCROW nStart, SCROW nEnd ) :
+inline ScAttrIterator::ScAttrIterator( const ScAttrArray* pNewArray, SCROW nStart, SCROW nEnd, const ScPatternAttr* pDefaultPattern ) :
     pArray( pNewArray ),
+    pDefPattern( pDefaultPattern ),
     nRow( nStart ),
     nEndRow( nEnd )
 {
-    if ( nStart > 0 )
-        pArray->Search( nStart, nPos );
+    if ( pArray->nCount )
+    {
+        if ( nStart > 0 )
+            pArray->Search( nStart, nPos );
+        else
+            nPos = 0;
+    }
     else
         nPos = 0;
 }
@@ -229,6 +237,21 @@ inline ScAttrIterator::ScAttrIterator( const ScAttrArray* pNewArray, SCROW nStar
 inline const ScPatternAttr* ScAttrIterator::Next( SCROW& rTop, SCROW& rBottom )
 {
     const ScPatternAttr* pRet;
+    if ( !pArray->nCount )
+    {
+        if ( !nPos )
+        {
+            ++nPos;
+            if ( nRow > MAXROW )
+                return nullptr;
+            rTop = nRow;
+            rBottom = std::min( nEndRow, MAXROW );
+            nRow = rBottom + 1;
+            return pDefPattern;
+        }
+        return nullptr;
+    }
+
     if ( nPos < pArray->nCount && nRow <= nEndRow )
     {
         rTop = nRow;
@@ -245,6 +268,11 @@ inline const ScPatternAttr* ScAttrIterator::Next( SCROW& rTop, SCROW& rBottom )
 inline const ScPatternAttr* ScAttrIterator::Resync( SCROW nRowP, SCROW& rTop, SCROW& rBottom )
 {
     nRow = nRowP;
+    if ( !pArray->nCount )
+    {
+        nPos = 0;
+        return Next( rTop, rBottom );
+    }
     // Chances are high that the pattern changed on nRowP introduced a span
     // starting right there. Assume that Next() was called so nPos already
     // advanced. Another high chance is that the change extended a previous or
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 345dea2..c5940b0 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -186,7 +186,7 @@ public:
                 ScColumn();
                 ~ScColumn();
 
-    void        Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc);
+    void        Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc, bool bEmptyAttrArray = false);
 
     ScDocument& GetDoc() { return *pDocument;}
     const ScDocument& GetDoc() const { return *pDocument;}
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 350dcbd..aab1453 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -25,6 +25,7 @@
 #include <tools/gen.hxx>
 #include <tools/color.hxx>
 #include <com/sun/star/uno/Sequence.hxx>
+#include "attarray.hxx"
 #include "column.hxx"
 #include "colcontainer.hxx"
 #include "sortparam.hxx"
@@ -206,7 +207,10 @@ private:
     bool            mbPageBreaksValid:1;
     bool            mbForceBreaks:1;
 
+    ScAttrArray     aNextColAttrArray;
+
 friend class ScDocument;                    // for FillInfo
+friend class ScColumn;
 friend class ScValueIterator;
 friend class ScHorizontalValueIterator;
 friend class ScDBQueryDataIterator;
diff --git a/sc/source/core/data/attarray.cxx b/sc/source/core/data/attarray.cxx
index 2afe4c3..c402dde 100644
--- a/sc/source/core/data/attarray.cxx
+++ b/sc/source/core/data/attarray.cxx
@@ -49,16 +49,40 @@
 
 using ::editeng::SvxBorderLine;
 
-ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc ) :
+ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc, ScAttrArray* pNextColAttrArray, bool bCreateEmpty ) :
     nCol( nNewCol ),
     nTab( nNewTab ),
     pDocument( pDoc ),
-    nCount(1),
-    nLimit(1),
-    pData(new ScAttrEntry[1])
+    nCount(0),
+    nLimit(0),
+    pData(nullptr)
 {
-    pData[0].nRow = MAXROW;
-    pData[0].pPattern = pDocument->GetDefPattern(); // no put
+    if ( nCol != -1 && !bCreateEmpty && pNextColAttrArray )
+    {
+        nCount = pNextColAttrArray->nCount;
+        nLimit = pNextColAttrArray->nCount;
+        if ( nCount )
+        {
+            bool bNumFormatChanged;
+            ScAddress aAdrStart( nCol, 0, nTab );
+            ScAddress aAdrEnd( nCol, 0, nTab );
+            pData = new ScAttrEntry[nCount];
+            for ( size_t nIdx = 0; nIdx < nCount; ++nIdx )
+            {
+                pData[nIdx].nRow = pNextColAttrArray->pData[nIdx].nRow;
+                ScPatternAttr aNewPattern( *(pNextColAttrArray->pData[nIdx].pPattern) );
+                pData[nIdx].pPattern = static_cast<const ScPatternAttr*>( &pDocument->GetPool()->Put( aNewPattern ) );
+                bNumFormatChanged = false;
+                if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+                     pData[nIdx].pPattern->GetItemSet(), pDocument->GetDefPattern()->GetItemSet() ) )
+                {
+                    aAdrStart.SetRow( nIdx ? pData[nIdx-1].nRow+1 : 0 );
+                    aAdrEnd.SetRow( pData[nIdx].nRow );
+                    pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+                }
+            }
+        }
+    }
 }
 
 ScAttrArray::~ScAttrArray()
@@ -102,6 +126,19 @@ void ScAttrArray::TestData() const
 }
 #endif
 
+void ScAttrArray::SetDefaultIfNotInit( SCSIZE nNeeded )
+{
+    if ( pData )
+        return;
+
+    SCSIZE nNewLimit = ( SC_ATTRARRAY_DELTA > nNeeded ) ? SC_ATTRARRAY_DELTA : nNeeded;
+    pData = new ScAttrEntry[nNewLimit];
+    pData[0].nRow = MAXROW;
+    pData[0].pPattern = pDocument->GetDefPattern(); // no put
+    nCount = 1;
+    nLimit = nNewLimit;
+}
+
 void ScAttrArray::Reset( const ScPatternAttr* pPattern )
 {
     ScDocumentPool*      pDocPool = pDocument->GetPool();
@@ -112,13 +149,16 @@ void ScAttrArray::Reset( const ScPatternAttr* pPattern )
     {
         // ensure that attributing changes text width of cell
         const ScPatternAttr* pOldPattern = pData[i].pPattern;
-        bool bNumFormatChanged;
-        if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
-                    pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
+        if ( nCol != -1 )
         {
-            aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 );
-            aAdrEnd  .SetRow( pData[i].nRow );
-            pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+            bool bNumFormatChanged;
+            if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+                        pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
+            {
+                aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 );
+                aAdrEnd  .SetRow( pData[i].nRow );
+                pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+            }
         }
         pDocPool->Remove(*pOldPattern);
     }
@@ -203,6 +243,12 @@ bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
 
 const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
 {
+    if ( !pData )
+    {
+        if ( !ValidRow( nRow ) )
+            return nullptr;
+        return pDocument->GetDefPattern();
+    }
     SCSIZE i;
     if (Search( nRow, i ))
         return pData[i].pPattern;
@@ -213,6 +259,14 @@ const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
 const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
         SCROW& rEndRow, SCROW nRow ) const
 {
+    if ( !pData )
+    {
+        if ( !ValidRow( nRow ) )
+            return nullptr;
+        rStartRow = 0;
+        rEndRow = MAXROW;
+        return pDocument->GetDefPattern();
+    }
     SCSIZE nIndex;
     if ( Search( nRow, nIndex ) )
     {
@@ -338,6 +392,7 @@ void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, bool bP
 void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow,
                                        const ScPatternAttr* pPattern, ScEditDataArray* pDataArray )
 {
+    assert( nCol != -1 );
     for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
     {
         ScAddress aPos(nCol, nRow, nTab);
@@ -363,7 +418,21 @@ void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow,
 
 bool ScAttrArray::Reserve( SCSIZE nReserve )
 {
-    if ( nLimit < nReserve )
+    if ( !pData && nReserve )
+    {
+        if( ScAttrEntry* pNewData = new (std::nothrow) ScAttrEntry[nReserve] )
+        {
+            nLimit = nReserve;
+            nCount = 1;
+            pData = pNewData;
+            pData[0].nRow = MAXROW;
+            pData[0].pPattern = pDocument->GetDefPattern(); // no put
+            return true;
+        }
+        else
+            return false;
+    }
+    else if ( nLimit < nReserve )
     {
         if( ScAttrEntry* pNewData = new (std::nothrow) ScAttrEntry[nReserve] )
         {
@@ -393,6 +462,7 @@ void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPattern
         else
         {
             SCSIZE nNeeded = nCount + 2;
+            SetDefaultIfNotInit( nNeeded );
             if ( nLimit < nNeeded )
             {
                 nLimit += SC_ATTRARRAY_DELTA;
@@ -428,16 +498,18 @@ void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPattern
             // otherwise, conditional formats need to be reset or deleted
             while ( ns <= nEndRow )
             {
-                const SfxItemSet& rNewSet = pPattern->GetItemSet();
-                const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet();
-
-                bool bNumFormatChanged;
-                if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
-                        rNewSet, rOldSet ) )
+                if ( nCol != -1 )
                 {
-                    aAdrStart.SetRow( std::max(nStartRow,ns) );
-                    aAdrEnd  .SetRow( std::min(nEndRow,pData[nx].nRow) );
-                    pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+                    const SfxItemSet& rNewSet = pPattern->GetItemSet();
+                    const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet();
+                    bool bNumFormatChanged;
+                    if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+                            rNewSet, rOldSet ) )
+                    {
+                        aAdrStart.SetRow( std::max(nStartRow,ns) );
+                        aAdrEnd  .SetRow( std::min(nEndRow,pData[nx].nRow) );
+                        pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+                    }
                 }
                 ns = pData[nx].nRow + 1;
                 nx++;
@@ -544,7 +616,7 @@ void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPattern
 
                 // Remove character attributes from these cells if the pattern
                 // is applied during normal session.
-                if (pDataArray)
+                if (pDataArray && nCol != -1)
                     RemoveCellCharAttribs(nStartRow, nEndRow, pPattern, pDataArray);
 
                 nCount++;
@@ -564,6 +636,7 @@ void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet*
 {
     if (ValidRow(nStartRow) && ValidRow(nEndRow))
     {
+        SetDefaultIfNotInit();
         SCSIZE nPos;
         SCROW nStart=0;
         if (!Search( nStartRow, nPos ))
@@ -599,18 +672,21 @@ void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet*
             }
             else
             {
-                // ensure attributing changes text width of cell; otherwise
-                // there aren't (yet) template format changes
-                const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
-                const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
-
-                bool bNumFormatChanged;
-                if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
-                        rNewSet, rOldSet ) )
+                if ( nCol != -1 )
                 {
-                    aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
-                    aAdrEnd  .SetRow( pData[nPos].nRow );
-                    pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+                    // ensure attributing changes text width of cell; otherwise
+                    // there aren't (yet) template format changes
+                    const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
+                    const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
+
+                    bool bNumFormatChanged;
+                    if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+                            rNewSet, rOldSet ) )
+                    {
+                        aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
+                        aAdrEnd  .SetRow( pData[nPos].nRow );
+                        pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+                    }
                 }
 
                 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
@@ -658,6 +734,7 @@ void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
     {
         SCSIZE nPos;
         SCROW nStart=0;
+        SetDefaultIfNotInit();
         if (!Search( nStartRow, nPos ))
         {
             OSL_FAIL("Search failure");
@@ -786,6 +863,7 @@ void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCac
     {
         SCSIZE nPos;
         SCROW nStart=0;
+        SetDefaultIfNotInit();
         if (!Search( nStartRow, nPos ))
         {
             OSL_FAIL("Search Failure");
@@ -814,18 +892,21 @@ void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCac
                 }
                 else
                 {
-                    // ensure attributing changes text-width of cell
+                    if ( nCol != -1 )
+                    {
+                        // ensure attributing changes text-width of cell
 
-                    const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
-                    const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
+                        const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
+                        const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
 
-                    bool bNumFormatChanged;
-                    if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
-                            rNewSet, rOldSet ) )
-                    {
-                        aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
-                        aAdrEnd  .SetRow( pData[nPos].nRow );
-                        pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+                        bool bNumFormatChanged;
+                        if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+                                rNewSet, rOldSet ) )
+                        {
+                            aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
+                            aAdrEnd  .SetRow( pData[nPos].nRow );
+                            pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+                        }
                     }
 
                     pDocument->GetPool()->Remove(*pData[nPos].pPattern);
@@ -906,9 +987,9 @@ void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
 {
     if (ValidRow(nStartRow) && ValidRow(nEndRow))
     {
-        SCSIZE nPos;
+        SCSIZE nPos = 0;
         SCROW nStart=0;
-        if (!Search( nStartRow, nPos ))
+        if ( pData && !Search( nStartRow, nPos ) )
         {
             OSL_FAIL("Search failure");
             return;
@@ -917,7 +998,11 @@ void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
         do
         {
             // similar patterns must not be repeated
-            const ScPatternAttr* pPattern = pData[nPos].pPattern;
+            const ScPatternAttr* pPattern = nullptr;
+            if ( pData )
+                pPattern = pData[nPos].pPattern;
+            else
+                pPattern = pDocument->GetDefPattern();
             if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
             {
                 const SfxItemSet& rThisSet = pPattern->GetItemSet();
@@ -941,7 +1026,10 @@ void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
                 rState.pOld1 = pPattern;
             }
 
-            nStart = pData[nPos].nRow + 1;
+            if ( pData )
+                nStart = pData[nPos].nRow + 1;
+            else
+                nStart = MAXROW + 1;
             ++nPos;
         }
         while (nStart <= nEndRow);
@@ -1055,7 +1143,7 @@ void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLine
         pPattern = GetPattern( nStartRow );
         lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true, 0 );
     }
-    else
+    else if ( pData ) // non-default pattern
     {
         pPattern = GetPattern( nStartRow );
         lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true,
@@ -1076,6 +1164,10 @@ void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLine
         pPattern = GetPattern( nEndRow );
         lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false, 0 );
     }
+    else
+    {
+        lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pDocument->GetDefPattern(), bLeft, nDistRight, true, 0 );
+    }
 }
 
 // apply border
@@ -1157,7 +1249,7 @@ void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInf
 {
     if (nStartRow == nEndRow)
         ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0 );
-    else
+    else if ( pData )
     {
         ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
                         true, nEndRow-nStartRow );
@@ -1188,12 +1280,19 @@ void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInf
 
         ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, false, 0 );
     }
+    else
+    {
+        ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0 );
+    }
 }
 
 // Test if field contains specific attribute
 
 bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) const
 {
+    if ( !pData )
+        return false;
+
     SCSIZE nStartIndex;
     SCSIZE nEndIndex;
     Search( nRow1, nStartIndex );
@@ -1255,7 +1354,7 @@ bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) cons
 
             bool bContainsCondFormat =
                     !static_cast<const ScCondFormatItem&>(pPattern->GetItem( ATTR_CONDITIONAL )).GetCondFormatData().empty();
-            if ( bContainsCondFormat )
+            if ( bContainsCondFormat && nCol != -1 ) // pDocument->GetCondResult() is valid only for real columns.
             {
                 SCROW nRowStartCond = std::max<SCROW>( nRow1, i ? pData[i-1].nRow + 1: 0 );
                 SCROW nRowEndCond = std::min<SCROW>( nRow2, pData[i].nRow );
@@ -1340,12 +1439,17 @@ bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) cons
 
 bool ScAttrArray::IsMerged( SCROW nRow ) const
 {
-    SCSIZE nIndex;
-    Search(nRow, nIndex);
-    const ScMergeAttr& rItem =
-        static_cast<const ScMergeAttr&>(pData[nIndex].pPattern->GetItem(ATTR_MERGE));
+    if ( pData )
+    {
+        SCSIZE nIndex;
+        Search(nRow, nIndex);
+        const ScMergeAttr& rItem =
+            static_cast<const ScMergeAttr&>(pData[nIndex].pPattern->GetItem(ATTR_MERGE));
+
+        return rItem.IsMerged();
+    }
 
-    return rItem.IsMerged();
+    return static_cast<const ScMergeAttr&>(pDocument->GetDefPattern()->GetItem(ATTR_MERGE)).IsMerged();
 }
 
 /**
@@ -1355,6 +1459,8 @@ bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
                                 SCCOL& rPaintCol, SCROW& rPaintRow,
                                 bool bRefresh )
 {
+    assert( nCol != -1 );
+    SetDefaultIfNotInit();
     const ScPatternAttr* pPattern;
     const ScMergeAttr* pItem;
     SCSIZE nStartIndex;
@@ -1404,6 +1510,8 @@ bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
 
 void ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
 {
+    assert( nCol != -1 );
+    SetDefaultIfNotInit();
     const ScPatternAttr* pPattern;
     const ScMergeAttr* pItem;
     SCSIZE nIndex;
@@ -1461,6 +1569,7 @@ void ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
 void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
                         const ScPatternAttr* pWantedPattern, bool bDefault )
 {
+    SetDefaultIfNotInit();
     const ScPatternAttr*    pOldPattern;
     const ScMergeFlagAttr*  pItem;
 
@@ -1515,6 +1624,7 @@ void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
 
 bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
 {
+    SetDefaultIfNotInit();
     const ScPatternAttr* pOldPattern;
 
     ScMF    nOldValue;
@@ -1551,6 +1661,7 @@ bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
 
 bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
 {
+    SetDefaultIfNotInit();
     const ScPatternAttr* pOldPattern;
 
     ScMF    nOldValue;
@@ -1587,6 +1698,7 @@ bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags )
 
 void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
 {
+    SetDefaultIfNotInit();
     SCSIZE  nIndex;
     SCROW   nRow;
     SCROW   nThisRow;
@@ -1616,6 +1728,7 @@ void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16*
 
 void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement )
 {
+    SetDefaultIfNotInit();
     SCSIZE nIndex;
     Search( nStartRow, nIndex );
     SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
@@ -1680,6 +1793,14 @@ SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, bool bUp ) const
     long nRet = nRow;
     if (ValidRow(nRow))
     {
+        if ( !pData )
+        {
+            if ( bUp )
+                return -1;
+            else
+                return MAXROW+1;
+        }
+
         SCSIZE nIndex;
         Search(nRow, nIndex);
         while (static_cast<const ScProtectionAttr&>(pData[nIndex].pPattern->
@@ -1706,6 +1827,7 @@ SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, bool bUp ) const
 
 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
 {
+    SetDefaultIfNotInit();
     SCROW nStart = 0;
     SCSIZE nPos = 0;
     while (nPos < nCount)
@@ -1742,6 +1864,18 @@ void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBo
 
 bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle ) const
 {
+    if ( !pData )
+    {
+        const ScStyleSheet* pStyle = pDocument->GetDefPattern()->GetStyleSheet();
+        if ( pStyle )
+        {
+            pStyle->SetUsage( ScStyleSheet::USED );
+            if ( pStyle == &rStyle )
+                return true;
+        }
+        return false;
+    }
+
     bool    bIsUsed = false;
     SCSIZE  nPos    = 0;
 
@@ -1764,6 +1898,9 @@ bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle ) const
 
 bool ScAttrArray::IsEmpty() const
 {
+    if ( !pData )
+        return true;
+
     if (nCount == 1)
     {
         if ( pData[0].pPattern != pDocument->GetDefPattern() )
@@ -1777,6 +1914,9 @@ bool ScAttrArray::IsEmpty() const
 
 bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
 {
+    if ( !pData )
+        return false;
+
     OSL_ENSURE( nCount, "nCount == 0" );
 
     bool bFound = false;
@@ -1812,6 +1952,12 @@ const SCROW SC_VISATTR_STOP = 84;
 
 bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const
 {
+    if ( !pData )
+    {
+        rLastRow = nLastData;
+        return false;
+    }
+
     OSL_ENSURE( nCount, "nCount == 0" );
 
     //  #i30830# changed behavior:
@@ -1868,6 +2014,9 @@ bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const
 
 bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
 {
+    if ( !pData )
+        return pDocument->GetDefPattern()->IsVisible();
+
     SCSIZE nIndex;
     Search( nStartRow, nIndex );
     SCROW nThisStart = nStartRow;
@@ -1887,6 +2036,50 @@ bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
 bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
                                     SCROW nStartRow, SCROW nEndRow ) const
 {
+    if ( !pData && !rOther.pData )
+    {
+        const ScPatternAttr* pDefPattern1 = pDocument->GetDefPattern();
+        const ScPatternAttr* pDefPattern2 = rOther.pDocument->GetDefPattern();
+        return ( pDefPattern1 == pDefPattern2 || pDefPattern1->IsVisibleEqual( *pDefPattern2 ) );
+    }
+
+    {
+        const ScAttrArray* pNonDefault = nullptr;
+        const ScPatternAttr* pDefPattern = nullptr;
+        bool bDefNonDefCase = false;
+        if ( !pData && rOther.pData )
+        {
+            pNonDefault = &rOther;
+            pDefPattern = pDocument->GetDefPattern();
+            bDefNonDefCase = true;
+        }
+        else if ( pData && !rOther.pData )
+        {
+            pNonDefault = this;
+            pDefPattern = rOther.pDocument->GetDefPattern();
+            bDefNonDefCase = true;
+        }
+
+        if ( bDefNonDefCase )
+        {
+            bool bEqual = true;
+            SCSIZE nPos = 0;
+            if ( nStartRow > 0 )
+                pNonDefault->Search( nStartRow, nPos );
+
+            while ( nPos < pNonDefault->nCount && bEqual )
+            {
+                const ScPatternAttr* pNonDefPattern = pNonDefault->pData[nPos].pPattern;
+                bEqual = ( pNonDefPattern == pDefPattern ||
+                           pNonDefPattern->IsVisibleEqual( *pDefPattern ) );
+
+                if ( pNonDefault->pData[nPos].nRow >= nEndRow ) break;
+                ++nPos;
+            }
+            return bEqual;
+        }
+    }
+
     bool bEqual = true;
     SCSIZE nThisPos = 0;
     SCSIZE nOtherPos = 0;
@@ -1923,6 +2116,48 @@ bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
 bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
 {
     // summarised with IsVisibleEqual
+    if ( !pData && !rOther.pData )
+    {
+        const ScPatternAttr* pDefPattern1 = pDocument->GetDefPattern();
+        const ScPatternAttr* pDefPattern2 = rOther.pDocument->GetDefPattern();
+        return ( pDefPattern1 == pDefPattern2 );
+    }
+
+    {
+        const ScAttrArray* pNonDefault = nullptr;
+        const ScPatternAttr* pDefPattern = nullptr;
+        bool bDefNonDefCase = false;
+        if ( !pData && rOther.pData )
+        {
+            pNonDefault = &rOther;
+            pDefPattern = pDocument->GetDefPattern();
+            bDefNonDefCase = true;
+        }
+        else if ( pData && !rOther.pData )
+        {
+            pNonDefault = this;
+            pDefPattern = rOther.pDocument->GetDefPattern();
+            bDefNonDefCase = true;
+        }
+
+        if ( bDefNonDefCase )
+        {
+            bool bEqual = true;
+            SCSIZE nPos = 0;
+            if ( nStartRow > 0 )
+                pNonDefault->Search( nStartRow, nPos );
+
+            while ( nPos < pNonDefault->nCount && bEqual )
+            {
+                const ScPatternAttr* pNonDefPattern = pNonDefault->pData[nPos].pPattern;
+                bEqual = ( pNonDefPattern == pDefPattern );
+
+                if ( pNonDefault->pData[nPos].nRow >= nEndRow ) break;
+                ++nPos;
+            }
+            return bEqual;
+        }
+    }
 
     bool bEqual = true;
     SCSIZE nThisPos = 0;
@@ -1989,6 +2224,10 @@ bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const
 
     // MAXROW + 1 - nSize   = 1st row pushed out
 
+    if ( !pData )
+        return !static_cast<const ScMergeFlagAttr&>(pDocument->GetDefPattern()->
+                       GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped();
+
     SCSIZE nFirstLost = nCount-1;
     while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
         --nFirstLost;
@@ -2002,6 +2241,7 @@ bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const
 
 void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
 {
+    SetDefaultIfNotInit();
     if (!pData)
         return;
 
@@ -2013,6 +2253,8 @@ void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
 
     bool bDoMerge = static_cast<const ScMergeAttr&>( pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
 
+    assert( !bDoMerge || nCol != -1 );
+
     SCSIZE nRemove = 0;
     SCSIZE i;
     for (i = nIndex; i < nCount-1; i++)
@@ -2050,6 +2292,7 @@ void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
 
 void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
 {
+    SetDefaultIfNotInit();
     bool bFirst=true;
     SCSIZE nStartIndex = 0;
     SCSIZE nEndIndex = 0;
@@ -2097,6 +2340,7 @@ void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
 
 void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
 {
+    SetDefaultIfNotInit();
     ScDocumentPool* pDocPool = pDocument->GetPool();
     for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
         pDocPool->Remove(*pData[i].pPattern);
@@ -2107,7 +2351,9 @@ void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
 
 void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
 {
-    RemoveAreaMerge( nStartRow, nEndRow );  // remove from combined flags
+    SetDefaultIfNotInit();
+    if ( nCol != -1 )
+        RemoveAreaMerge( nStartRow, nEndRow );  // remove from combined flags
 
     if ( !HasAttrib( nStartRow, nEndRow, HasAttrFlags::Overlapped | HasAttrFlags::AutoFilter) )
         SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() );
@@ -2117,6 +2363,7 @@ void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
 
 void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
 {
+    SetDefaultIfNotInit();
     const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
 
     SCSIZE  nIndex;
@@ -2160,6 +2407,7 @@ void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
  */
 void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
 {
+    SetDefaultIfNotInit();
     SCROW nStart = nStartRow;
     for (SCSIZE i = 0; i < nCount; i++)
     {
@@ -2190,6 +2438,14 @@ void ScAttrArray::CopyArea(
     ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
     bool bSamePool = (pSourceDocPool==pDestDocPool);
 
+    if ( !pData )
+    {
+        const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>(
+                                             &pDestDocPool->GetDefaultItem( ATTR_PATTERN ));
+        rAttrArray.SetPatternArea(nDestStart, nDestEnd, pNewPattern);
+        return;
+    }
+
     for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
     {
         if (pData[i].nRow >= nStartRow)
@@ -2262,6 +2518,20 @@ void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttr
     ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
     bool bSamePool = (pSourceDocPool==pDestDocPool);
 
+    if ( !pData )
+    {
+        const ScPatternAttr* pNewPattern;
+        if (bSamePool)
+            pNewPattern = static_cast<const ScPatternAttr*>(
+                             &pDestDocPool->Put(*pDocument->GetDefPattern()));
+        else
+            pNewPattern = pDocument->GetDefPattern()->PutInPool( rAttrArray.pDocument, pDocument );
+
+        rAttrArray.SetPatternAreaSafe(nDestStart, nDestEnd, pNewPattern, false);
+        return;
+    }
+
+
     for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
     {
         if (pData[i].nRow >= nStartRow)
@@ -2297,6 +2567,15 @@ SCsROW ScAttrArray::SearchStyle(
             return nRow;
     }
 
+    if ( !pData )
+    {
+        if (pDocument->GetDefPattern()->GetStyleSheet() == pSearchStyle)
+            return nRow;
+
+        nRow = bUp ? -1 : MAXROW + 1;
+        return nRow;
+    }
+
     SCSIZE nIndex;
     Search(nRow, nIndex);
     const ScPatternAttr* pPattern = pData[nIndex].pPattern;
@@ -2354,6 +2633,33 @@ bool ScAttrArray::SearchStyleRange(
     SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
     if (ValidRow(nStartRow))
     {
+        if ( !pData )
+        {
+            rRow = nStartRow;
+            if (bUp)
+            {
+                rEndRow = 0;
+                if (pMarkArray)
+                {
+                    SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true );
+                    if (nMarkEnd>rEndRow)
+                        rEndRow = nMarkEnd;
+                }
+            }
+            else
+            {
+                rEndRow = MAXROW;
+                if (pMarkArray)
+                {
+                    SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false );
+                    if (nMarkEnd<rEndRow)
+                        rEndRow = nMarkEnd;
+                }
+            }
+
+            return true;
+        }
+
         SCSIZE nIndex;
         Search(nStartRow,nIndex);
 
@@ -2390,6 +2696,9 @@ bool ScAttrArray::SearchStyleRange(
 
 SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW nEndRow ) const
 {
+    if ( !pData )
+        return 1;
+
     SCSIZE  nIndex1, nIndex2;
 
     if( !Search( nStartRow, nIndex1 ) )
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index e8a537a..7ffafda 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -21,6 +21,7 @@
 #include "scitems.hxx"
 #include "formulacell.hxx"
 #include "document.hxx"
+#include "table.hxx"
 #include "docpool.hxx"
 #include "attarray.hxx"
 #include "patattr.hxx"
@@ -103,12 +104,15 @@ ScColumn::~ScColumn()
     delete pAttrArray;
 }
 
-void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
+void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc, bool bEmptyAttrArray)
 {
     nCol = nNewCol;
     nTab = nNewTab;
     pDocument = pDoc;
-    pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
+    if ( !bEmptyAttrArray )
+        pAttrArray = new ScAttrArray( nCol, nTab, pDocument, &pDocument->maTabs[nTab]->aNextColAttrArray, bEmptyAttrArray );
+    else
+        pAttrArray = new ScAttrArray( nCol, nTab, pDocument, nullptr, true );
 }
 
 SCsROW ScColumn::GetNextUnprotected( SCROW nRow, bool bUp ) const
@@ -385,7 +389,7 @@ const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRo
     const ScPatternAttr* pMaxPattern = nullptr;
     size_t nMaxCount = 0;
 
-    ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
+    ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow, pDocument->GetDefPattern() );
     const ScPatternAttr* pPattern;
     SCROW nAttrRow1 = 0, nAttrRow2 = 0;
 
@@ -613,7 +617,7 @@ const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, bool&
     SCROW nBottom;
     while (bEqual && aMultiIter.Next( nTop, nBottom ))
     {
-        ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
+        ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom, pDocument->GetDefPattern() );
         SCROW nRow;
         SCROW nDummy;
         const ScPatternAttr* pPattern;
@@ -639,7 +643,7 @@ const ScStyleSheet* ScColumn::GetAreaStyle( bool& rFound, SCROW nRow1, SCROW nRo
     const ScStyleSheet* pStyle = nullptr;
     const ScStyleSheet* pNewStyle;
 
-    ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 );
+    ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2, pDocument->GetDefPattern() );
     SCROW nRow;
     SCROW nDummy;
     const ScPatternAttr* pPattern;
@@ -1752,7 +1756,7 @@ void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
 void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
 {
     //  This is the scenario table, the data is copied into it
-    ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
+    ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW, pDocument->GetDefPattern() );
     SCROW nStart = -1, nEnd = -1;
     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
     while (pPattern)
@@ -1780,7 +1784,7 @@ void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
 void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
 {
     //  This is the scenario table, the data is copied to the other
-    ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
+    ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW, pDocument->GetDefPattern() );
     SCROW nStart = -1, nEnd = -1;
     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
     while (pPattern)
@@ -1805,7 +1809,7 @@ void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
 bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
 {
     bool bOk = true;
-    ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
+    ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW, pDocument->GetDefPattern() );
     SCROW nStart = 0, nEnd = 0;
     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
     while (pPattern && bOk)
@@ -1823,7 +1827,7 @@ void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
 {
     ScRange aRange( nCol, 0, nTab );
 
-    ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
+    ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW, pDocument->GetDefPattern() );
     SCROW nStart = -1, nEnd = -1;
     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
     while (pPattern)
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 581607e..b013569 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -786,7 +786,7 @@ void ScColumn::GetOptimalHeight(
     sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, sal_uInt16 nMinHeight, SCROW nMinStart )
 {
     ScFlatUInt16RowSegments& rHeights = rCxt.getHeightArray();
-    ScAttrIterator aIter( pAttrArray, nStartRow, nEndRow );
+    ScAttrIterator aIter( pAttrArray, nStartRow, nEndRow, pDocument->GetDefPattern() );
 
     SCROW nStart = -1;
     SCROW nEnd = -1;
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index b804260..8a81dcb 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1545,7 +1545,7 @@ void ScColumn::MixData(
 
 ScAttrIterator* ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
 {
-    return new ScAttrIterator( pAttrArray, nStartRow, nEndRow );
+    return new ScAttrIterator( pAttrArray, nStartRow, nEndRow, pDocument->GetDefPattern() );
 }
 
 namespace {
@@ -2347,7 +2347,7 @@ void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
     FormulaToValueHandler aFunc;
     sc::CellStoreType::const_iterator itPos = maCells.begin();
 
-    ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
+    ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow, pDocument->GetDefPattern() );
     SCROW nTop = -1;
     SCROW nBottom = -1;
     const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx
index a682a5e..8bbb121 100644
--- a/sc/source/core/data/dociter.cxx
+++ b/sc/source/core/data/dociter.cxx
@@ -2300,14 +2300,24 @@ void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization)
             SCSIZE nIndex;
             if (bInitialization)
             {
-                pArray->Search( nStartRow, nIndex );
+                if ( pArray->nCount )
+                    pArray->Search( nStartRow, nIndex );
+                else
+                    nIndex = 0;
                 pIndices[nPos] = nIndex;
                 pHorizEnd[nPos] = MAXCOL+1; // only for OSL_ENSURE
             }
             else
                 nIndex = ++pIndices[nPos];
 
-            if ( nIndex < pArray->nCount )
+            if ( !nIndex && !pArray->nCount )
+            {
+                SCROW nThisEnd = MAXROW;
+                pNextEnd[nPos] = nThisEnd;
+                OSL_ENSURE( pNextEnd[nPos] >= nRow, "Sequence out of order" );
+                ppPatterns[nPos] = nullptr;
+            }
+            else if ( nIndex < pArray->nCount )
             {
                 const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
                 SCROW nThisEnd = pArray->pData[nIndex].nRow;
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 0d653d0..3bf5e8a 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -5373,16 +5373,26 @@ void ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
 
             ScAttrArray* pAttrArray = maTabs[nTab]->aCol[nOldCol].pAttrArray;
             SCSIZE nIndex;
-            pAttrArray->Search( nOldRow, nIndex );
+            if ( pAttrArray->nCount )
+                pAttrArray->Search( nOldRow, nIndex );
+            else
+                nIndex = 0;
             SCROW nAttrPos = nOldRow;
             while (nAttrPos<=nEndRow)
             {
                 OSL_ENSURE( nIndex < pAttrArray->nCount, "Wrong index in AttrArray" );
 
-                if (static_cast<const ScMergeFlagAttr&>(pAttrArray->pData[nIndex].pPattern->
-                        GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped())
+                bool bHorOverlapped;
+                if ( pAttrArray->nCount )
+                    bHorOverlapped = static_cast<const ScMergeFlagAttr&>(pAttrArray->pData[nIndex].pPattern->
+                                                                         GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped();
+                else
+                    bHorOverlapped = static_cast<const ScMergeFlagAttr&>(GetDefPattern()->
+                                                                         GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped();
+                if ( bHorOverlapped )
                 {
-                    SCROW nLoopEndRow = std::min( nEndRow, pAttrArray->pData[nIndex].nRow );
+                    SCROW nEndRowSeg = (pAttrArray->nCount) ? pAttrArray->pData[nIndex].nRow : MAXROW;
+                    SCROW nLoopEndRow = std::min( nEndRow, nEndRowSeg );
                     for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
                     {
                         SCCOL nTempCol = nOldCol;
@@ -5394,8 +5404,13 @@ void ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
                             rStartCol = nTempCol;
                     }
                 }
-                nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
-                ++nIndex;
+                if ( pAttrArray->nCount )
+                {
+                    nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
+                    ++nIndex;
+                }
+                else
+                    nAttrPos = MAXROW + 1;
             }
         }
     }
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 9f2ebca..d8ec3ed 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -499,12 +499,24 @@ void ScDocument::FillInfo(
 
                     SCROW nThisRow;
                     SCSIZE nIndex;
-                    (void) pThisAttrArr->Search( nCurRow, nIndex );
+                    if ( pThisAttrArr->nCount )
+                        (void) pThisAttrArr->Search( nCurRow, nIndex );
+                    else
+                        nIndex = 0;
 
                     do
                     {
-                        nThisRow=pThisAttrArr->pData[nIndex].nRow;              // End of range
-                        const ScPatternAttr* pPattern=pThisAttrArr->pData[nIndex].pPattern;
+                        const ScPatternAttr* pPattern = nullptr;
+                        if ( pThisAttrArr->nCount )
+                        {
+                            nThisRow = pThisAttrArr->pData[nIndex].nRow;              // End of range
+                            pPattern = pThisAttrArr->pData[nIndex].pPattern;
+                        }
+                        else
+                        {
+                            nThisRow = MAXROW;
+                            pPattern = GetDefPattern();
+                        }
 
                         const SvxBrushItem* pBackground = static_cast<const SvxBrushItem*>(
                                                         &pPattern->GetItem(ATTR_BACKGROUND));
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 7d3d94a..bf227d3 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -287,7 +287,8 @@ ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const OUString& rNewName,
     bPrintEntireSheet(true),
     bActiveScenario(false),
     mbPageBreaksValid(false),
-    mbForceBreaks(false)
+    mbForceBreaks(false),
+    aNextColAttrArray(static_cast<SCCOL>(-1), nNewTab, pDoc, nullptr, true)
 {
 
     if (bColInfo)
@@ -328,7 +329,7 @@ ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const OUString& rNewName,
     }
 
     for (SCCOL k=0; k<=MAXCOL; k++)
-        aCol[k].Init( k, nTab, pDocument );
+        aCol[k].Init( k, nTab, pDocument, true );
 }
 
 ScTable::~ScTable()
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 55afa01..0f817d9 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1936,8 +1936,13 @@ bool ScTable::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
         OSL_FAIL("ScTable::ExtendMerge: invalid column number");
         return false;
     }
+    if ( nStartCol >= aCol.size() )
+    {
+        OSL_FAIL("ScTable::ExtendMerge: invalid nStartCol");
+        return false;
+    }
     bool bFound = false;
-    SCCOL nOldEndX = rEndCol;
+    SCCOL nOldEndX = std::min( rEndCol, static_cast<SCCOL>(aCol.size()-1) );
     SCROW nOldEndY = rEndRow;
     for (SCCOL i=nStartCol; i<=nOldEndX; i++)
         bFound |= aCol[i].ExtendMerge( i, nStartRow, nOldEndY, rEndCol, rEndRow, bRefresh );


More information about the Libreoffice-commits mailing list