[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.1' - 33 commits - desktop/inc editeng/source sc/CppunitTest_sc_tiledrendering.mk sc/inc sc/Library_sc.mk sc/qa sc/source sw/source vcl/headless vcl/inc

Andras Timar andras.timar at collabora.com
Tue Jun 21 03:21:46 UTC 2016


 desktop/inc/lib/init.hxx                     |   43 ++
 editeng/source/editeng/editeng.cxx           |    1 
 sc/CppunitTest_sc_tiledrendering.mk          |    1 
 sc/Library_sc.mk                             |    1 
 sc/inc/document.hxx                          |    2 
 sc/inc/fillinfo.hxx                          |   54 +++
 sc/inc/markarr.hxx                           |    1 
 sc/inc/markdata.hxx                          |   24 +
 sc/inc/markmulti.hxx                         |   84 +++++
 sc/inc/segmenttree.hxx                       |    2 
 sc/qa/unit/tiledrendering/tiledrendering.cxx |   55 +++
 sc/source/core/data/column.cxx               |   52 +--
 sc/source/core/data/column3.cxx              |    2 
 sc/source/core/data/documen2.cxx             |   34 +-
 sc/source/core/data/fillinfo.cxx             |  414 +++++++++++++--------------
 sc/source/core/data/markarr.cxx              |   11 
 sc/source/core/data/markdata.cxx             |  371 +++++++++++++++++++-----
 sc/source/core/data/markmulti.cxx            |  348 ++++++++++++++++++++++
 sc/source/core/data/segmenttree.cxx          |    2 
 sc/source/core/data/table1.cxx               |   11 
 sc/source/ui/inc/viewdata.hxx                |    8 
 sc/source/ui/unoobj/docuno.cxx               |    3 
 sc/source/ui/view/formatsh.cxx               |   11 
 sc/source/ui/view/gridwin4.cxx               |   93 +++++-
 sc/source/ui/view/tabview3.cxx               |   42 ++
 sc/source/ui/view/viewdata.cxx               |    2 
 sw/source/core/crsr/viscrs.cxx               |    3 
 sw/source/uibase/docvw/SidebarTxtControl.cxx |    5 
 sw/source/uibase/docvw/SidebarWin.cxx        |    6 
 vcl/headless/svpinst.cxx                     |   61 +++
 vcl/inc/headless/svpinst.hxx                 |    9 
 31 files changed, 1375 insertions(+), 381 deletions(-)

New commits:
commit 71deb1dacf61e5f9a1d95e14453885178d5a6f53
Author: Andras Timar <andras.timar at collabora.com>
Date:   Wed Jun 1 23:24:01 2016 +0200

    Linux x86 build fix
    
    Change-Id: I34a393745265b8daca832c7df896bea090bb2554
    (cherry picked from commit 72d1b6663a340e745af42aaf94541e4c1309b434)

diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index 3bc285a..24f45db 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -1061,7 +1061,7 @@ void ScGridWindow::PaintTile( VirtualDevice& rDevice,
     firstCol = (firstCol >= 0 ? firstCol : nStartCol);
     lastCol = (lastCol >= 0 ? lastCol : nEndCol);
 
-    auto capacity = std::min(nEndRow + 3, 1002);
+    auto capacity = std::min(nEndRow + 3, sal_Int32(1002));
     ScTableInfo aTabInfo(capacity);
     pDoc->FillInfo(aTabInfo, nStartCol, nStartRow, lastCol, lastRow, nTab, fPPTX, fPPTY, false, false, NULL);
 
commit aff7d0ff0fc241e7d062cae4a9f6b47f365a1aea
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Wed Jun 1 10:07:59 2016 -0400

    LOK: calc tile rendering
    
    Change-Id: I122922ac18a652dbbce01932eaaad92ded45098d
    Reviewed-on: https://gerrit.libreoffice.org/25782
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit bd63faaedc6d268ca1f4552aa6d18fc74e23809c)

diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index f949ef6..3bc285a 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -1061,7 +1061,8 @@ void ScGridWindow::PaintTile( VirtualDevice& rDevice,
     firstCol = (firstCol >= 0 ? firstCol : nStartCol);
     lastCol = (lastCol >= 0 ? lastCol : nEndCol);
 
-    ScTableInfo aTabInfo(nEndRow + 3);
+    auto capacity = std::min(nEndRow + 3, 1002);
+    ScTableInfo aTabInfo(capacity);
     pDoc->FillInfo(aTabInfo, nStartCol, nStartRow, lastCol, lastRow, nTab, fPPTX, fPPTY, false, false, NULL);
 
     ScOutputData aOutputData(&rDevice, OUTTYPE_WINDOW, aTabInfo, pDoc, nTab,
commit 69ef944d9a2d868a596699658f28121edd674f23
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Sat May 28 10:20:10 2016 -0400

    bccu#1845 - Calc tile rendering very slow
    
    For some reason trying to draw exactly the
    region of the tile results in black tiles.
    That is, when the top rows and left columns
    are not drawn, black tiles show.
    
    This patch still reduces the time to render
    a given tile by limiting the bottom-most row
    and right-most column to the max necessary.
    For large tabs rendering the first few 100
    rows is very fast (<100ms at most).
    
    More work is necessary to reduce drawing time
    for large sheets (when rendering tiles at the
    bottom). Still, even those slow bottom-rows
    are now faster with this patch.
    
    Currently the slowest function by far is
    ScGridWindow::DrawContent.
    
    Change-Id: I6e88c7b3a1c483bf43bfcfb38f4b41ffc08a9744
    Reviewed-on: https://gerrit.libreoffice.org/25586
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit 56e290acca0f51f1aa888f9e7787cfcdc6bb8fd9)

diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index 923316a..f949ef6 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -970,8 +970,10 @@ void ScGridWindow::PaintTile( VirtualDevice& rDevice,
     // page break zoom, and aLogicMode in ScViewData
     pViewData->SetZoom(aFracX, aFracY, true);
 
-    double fTilePosXPixel = static_cast<double>(nTilePosX) * nOutputWidth / nTileWidth;
-    double fTilePosYPixel = static_cast<double>(nTilePosY) * nOutputHeight / nTileHeight;
+    const double fTilePosXPixel = static_cast<double>(nTilePosX) * nOutputWidth / nTileWidth;
+    const double fTilePosYPixel = static_cast<double>(nTilePosY) * nOutputHeight / nTileHeight;
+    const double fTileBottomPixel = static_cast<double>(nTilePosY + nTileHeight) * nOutputHeight / nTileHeight;
+    const double fTileRightPixel = static_cast<double>(nTilePosX + nTileWidth) * nOutputWidth / nTileWidth;
 
     SCTAB nTab = pViewData->GetTabNo();
     ScDocument* pDoc = pViewData->GetDocument();
@@ -982,14 +984,88 @@ void ScGridWindow::PaintTile( VirtualDevice& rDevice,
     // size of the document including drawings, charts, etc.
     pDoc->GetTiledRenderingArea(nTab, nEndCol, nEndRow);
 
-    double fPPTX = pViewData->GetPPTX();
-    double fPPTY = pViewData->GetPPTY();
+    const double fPPTX = pViewData->GetPPTX();
+    const double fPPTY = pViewData->GetPPTY();
 
-    ScTableInfo aTabInfo(nEndRow + 2);
-    pDoc->FillInfo(aTabInfo, nStartCol, nStartRow, nEndCol, nEndRow, nTab, fPPTX, fPPTY, false, false, NULL);
+    // Calculate the tile's first and last rows.
+    SCROW firstRow = -1;
+    SCROW lastRow = -1;
+    double fTopOffsetPixel = 0;
+
+    // Find the first and last rows to paint this tile.
+    sal_uInt16 nDocHeight = ScGlobal::nStdRowHeight;
+    SCROW nDocHeightEndRow = -1;
+    for (SCROW nY = nStartRow; nY <= nEndRow; ++nY)
+    {
+        if (nY > nDocHeightEndRow)
+        {
+            if (ValidRow(nY))
+                nDocHeight = pDoc->GetRowHeight( nY, nTab, nullptr, &nDocHeightEndRow );
+            else
+                nDocHeight = ScGlobal::nStdRowHeight;
+        }
+
+        auto rowHeight = static_cast<sal_uInt16>(nDocHeight * fPPTY);
+        if (fTopOffsetPixel + rowHeight >= fTilePosYPixel)
+        {
+            if (firstRow < 0)
+            {
+                firstRow = nY;
+            }
+            else if (fTopOffsetPixel + rowHeight > fTileBottomPixel)
+            {
+                lastRow = nY;
+                break;
+            }
+        }
+
+        fTopOffsetPixel += rowHeight;
+    }
+
+    firstRow = (firstRow >= 0 ? firstRow : nStartRow);
+    lastRow = (lastRow >= 0 ? lastRow : nEndRow);
+
+    // Find the first and last cols to paint this tile.
+    SCCOL firstCol = -1;
+    SCCOL lastCol = -1;
+    double fLeftOffsetPixel = 0;
+    for (SCCOL nArrCol=nStartCol+3; nArrCol<=nEndCol+2; ++nArrCol)
+    {
+        SCCOL nX = nArrCol-1;
+        if ( ValidCol(nX) )
+        {
+            if (!pDoc->ColHidden(nX, nTab))
+            {
+                sal_uInt16 nColWidth = (sal_uInt16) (pDoc->GetColWidth( nX, nTab ) * fPPTX);
+                if (!nColWidth)
+                    nColWidth = 1;
+
+                if (fLeftOffsetPixel + nColWidth >= fTilePosXPixel)
+                {
+                    if (firstCol < 0)
+                    {
+                        firstCol = nX;
+                    }
+                    else if (fLeftOffsetPixel + nColWidth > fTileRightPixel)
+                    {
+                        lastCol = nX;
+                        break;
+                    }
+                }
+
+                fLeftOffsetPixel += nColWidth;
+            }
+        }
+    }
+
+    firstCol = (firstCol >= 0 ? firstCol : nStartCol);
+    lastCol = (lastCol >= 0 ? lastCol : nEndCol);
+
+    ScTableInfo aTabInfo(nEndRow + 3);
+    pDoc->FillInfo(aTabInfo, nStartCol, nStartRow, lastCol, lastRow, nTab, fPPTX, fPPTY, false, false, NULL);
 
     ScOutputData aOutputData(&rDevice, OUTTYPE_WINDOW, aTabInfo, pDoc, nTab,
-            -fTilePosXPixel, -fTilePosYPixel, nStartCol, nStartRow, nEndCol, nEndRow,
+            -fTilePosXPixel, -fTilePosYPixel, nStartCol, firstRow, lastCol, lastRow,
             fPPTX, fPPTY);
 
     // setup the SdrPage so that drawinglayer works correctly
commit 25146c5f86369f4d77265bc34f66f65b76459ad1
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Wed May 25 23:28:04 2016 -0400

    widen table-info capacity and count to SCSIZE
    
    Change-Id: Id659978e71c7027bc1c58f0bc276da38e1ada4ba
    Reviewed-on: https://gerrit.libreoffice.org/25488
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit 04a18136b186753cd303057155141957c9a90500)

diff --git a/sc/inc/fillinfo.hxx b/sc/inc/fillinfo.hxx
index 419f1c9..3b42dff 100644
--- a/sc/inc/fillinfo.hxx
+++ b/sc/inc/fillinfo.hxx
@@ -195,11 +195,11 @@ struct ScTableInfo
 {
     svx::frame::Array   maArray;
     RowInfo*            mpRowInfo;
-    sal_uInt16          mnArrCount;
-    sal_uInt16          mnArrCapacity;
+    SCSIZE              mnArrCount;
+    SCSIZE              mnArrCapacity;
     bool                mbPageMode;
 
-    explicit            ScTableInfo(const sal_uInt16 capacity = 1024);
+    explicit            ScTableInfo(const SCSIZE capacity = 1024);
                         ~ScTableInfo();
     ScTableInfo(const ScTableInfo&) = delete;
     const ScTableInfo& operator=(const ScTableInfo&) = delete;
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 3235c30..cd39a36 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -1126,7 +1126,7 @@ void ScDocument::FillInfo(
         rArray.MirrorSelfX( true, false );
 }
 
-ScTableInfo::ScTableInfo(const sal_uInt16 capacity)
+ScTableInfo::ScTableInfo(const SCSIZE capacity)
     : mpRowInfo(new RowInfo[capacity])
     , mnArrCount(0)
     , mnArrCapacity(capacity)
@@ -1137,7 +1137,7 @@ ScTableInfo::ScTableInfo(const sal_uInt16 capacity)
 
 ScTableInfo::~ScTableInfo()
 {
-    for( sal_uInt16 nIdx = 0; nIdx < mnArrCapacity; ++nIdx )
+    for( SCSIZE nIdx = 0; nIdx < mnArrCapacity; ++nIdx )
         delete [] mpRowInfo[ nIdx ].pCellInfo;
     delete [] mpRowInfo;
 }
commit 372a984116506aad0af8502889c05f8dc6b42fe2
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Tue May 24 22:01:38 2016 -0400

    lok don't supress start/end when there is selection
    
    Change-Id: I347d90cfa5432e18b9a0091ab575c0833538d941
    Reviewed-on: https://gerrit.libreoffice.org/25422
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit bc304ac66e56e6040bb810cfd23efbc35235eccb)

diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx
index e25b334..50344ee 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -364,8 +364,7 @@ void SwSelPaintRects::Show(std::vector<OString>* pSelectionRectangles)
         // being edited.
         if (comphelper::LibreOfficeKit::isActive() && !pView->GetTextEditObject())
         {
-            // If pSelectionRectangles is set, we're just collecting the text selections -> don't emit start/end.
-            if (!empty() && !pSelectionRectangles)
+            if (!empty())
             {
                 // The selection may be a complex polygon, emit the logical
                 // start/end cursor rectangle of the selection as separate
commit 255b41e622a89ff4bddd799839e0478b4fdfb14a
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Sat May 21 23:10:35 2016 -0400

    sc lok bccu#1610 - Tiles not rendering in large spreadsheets
    
    Variable max info rows instead of hard-coded allows
    for collecting info on more rows.
    
    FillInfo, however, is extremely slow for large
    row count (a few thousand) and needs improving.
    
    Reviewed-on: https://gerrit.libreoffice.org/25293
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit 4c338a328d6be0450bfdcb08876abfd149cb80ca)
    
    Change-Id: Ib0e475513bc3ba98fff66a5b9d405aeba1057331

diff --git a/sc/inc/fillinfo.hxx b/sc/inc/fillinfo.hxx
index d35bb8e..419f1c9 100644
--- a/sc/inc/fillinfo.hxx
+++ b/sc/inc/fillinfo.hxx
@@ -195,10 +195,11 @@ struct ScTableInfo
 {
     svx::frame::Array   maArray;
     RowInfo*            mpRowInfo;
-    sal_uInt16              mnArrCount;
+    sal_uInt16          mnArrCount;
+    sal_uInt16          mnArrCapacity;
     bool                mbPageMode;
 
-    explicit            ScTableInfo();
+    explicit            ScTableInfo(const sal_uInt16 capacity = 1024);
                         ~ScTableInfo();
     ScTableInfo(const ScTableInfo&) = delete;
     const ScTableInfo& operator=(const ScTableInfo&) = delete;
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 4fdcbf6..3235c30 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -46,8 +46,6 @@
 #include <memory>
 #include <o3tl/make_unique.hxx>
 
-const sal_uInt16 ROWINFO_MAX = 1024;
-
 enum FillInfoLinePos
     {
         FILP_TOP,
@@ -209,7 +207,7 @@ bool isRotateItemUsed(ScDocumentPool *pPool)
     return false;
 }
 
-void initRowInfo(ScDocument* pDoc, RowInfo* pRowInfo,
+void initRowInfo(ScDocument* pDoc, RowInfo* pRowInfo, const SCSIZE nMaxRow,
         double fRowScale, SCROW nRow1, SCTAB nTab, SCROW& rYExtra, SCSIZE& rArrRow, SCROW& rRow2)
 {
     sal_uInt16 nDocHeight = ScGlobal::nStdRowHeight;
@@ -249,7 +247,7 @@ void initRowInfo(ScDocument* pDoc, RowInfo* pRowInfo,
             pThisRowInfo->nRotMaxCol    = SC_ROTMAX_NONE;
 
             ++rArrRow;
-            if (rArrRow >= ROWINFO_MAX)
+            if (rArrRow >= nMaxRow)
             {
                 OSL_FAIL("FillInfo: Range too big" );
                 rYExtra = nSignedY;                         // End
@@ -434,7 +432,7 @@ void ScDocument::FillInfo(
 
     nArrRow=0;
     SCROW nYExtra = nRow2+1;
-    initRowInfo(this, pRowInfo, fRowScale, nRow1,
+    initRowInfo(this, pRowInfo, rTabInfo.mnArrCapacity, fRowScale, nRow1,
             nTab, nYExtra, nArrRow, nRow2);
     nArrCount = nArrRow;                                      // incl. Dummys
 
@@ -1128,17 +1126,18 @@ void ScDocument::FillInfo(
         rArray.MirrorSelfX( true, false );
 }
 
-ScTableInfo::ScTableInfo()
-    : mpRowInfo(new RowInfo[ROWINFO_MAX])
+ScTableInfo::ScTableInfo(const sal_uInt16 capacity)
+    : mpRowInfo(new RowInfo[capacity])
     , mnArrCount(0)
+    , mnArrCapacity(capacity)
     , mbPageMode(false)
 {
-    memset(mpRowInfo, 0, ROWINFO_MAX*sizeof(RowInfo));
+    memset(mpRowInfo, 0, mnArrCapacity * sizeof(RowInfo));
 }
 
 ScTableInfo::~ScTableInfo()
 {
-    for( sal_uInt16 nIdx = 0; nIdx < ROWINFO_MAX; ++nIdx )
+    for( sal_uInt16 nIdx = 0; nIdx < mnArrCapacity; ++nIdx )
         delete [] mpRowInfo[ nIdx ].pCellInfo;
     delete [] mpRowInfo;
 }
diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index f927b4f..923316a 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -985,8 +985,8 @@ void ScGridWindow::PaintTile( VirtualDevice& rDevice,
     double fPPTX = pViewData->GetPPTX();
     double fPPTY = pViewData->GetPPTY();
 
-    ScTableInfo aTabInfo;
-    pDoc->FillInfo(aTabInfo, nStartCol, nStartRow, nEndCol, nEndRow, nTab, fPPTX, fPPTY, false, false);
+    ScTableInfo aTabInfo(nEndRow + 2);
+    pDoc->FillInfo(aTabInfo, nStartCol, nStartRow, nEndCol, nEndRow, nTab, fPPTX, fPPTY, false, false, NULL);
 
     ScOutputData aOutputData(&rDevice, OUTTYPE_WINDOW, aTabInfo, pDoc, nTab,
             -fTilePosXPixel, -fTilePosYPixel, nStartCol, nStartRow, nEndCol, nEndRow,
commit b4f78d525d97315e7ceb2f4a247916c370cf0030
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Sat Apr 9 20:39:48 2016 +0100

    coverity#738785 reorg to silence Uninitialized pointer field
    
    (cherry picked from commit 3ac0778c0a2b2f693a1029b7b05c1be4f71944a9)
    
    Change-Id: If2225e77215e2a6fb6b9e9dfc6021a2c20babe50
    Reviewed-on: https://gerrit.libreoffice.org/25292
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit 4475acb6e52652890e5470c4cd1f4e1aaa84fbb5)

diff --git a/sc/inc/fillinfo.hxx b/sc/inc/fillinfo.hxx
index 94bd6b1..d35bb8e 100644
--- a/sc/inc/fillinfo.hxx
+++ b/sc/inc/fillinfo.hxx
@@ -29,8 +29,6 @@
 #include "colorscale.hxx"
 #include "cellvalue.hxx"
 
-#include <boost/noncopyable.hpp>
-
 class SfxItemSet;
 class SvxBrushItem;
 class SvxBoxItem;
@@ -96,8 +94,42 @@ struct ScIconSetInfo
     bool mbShowValue;
 };
 
-struct CellInfo : boost::noncopyable
+struct CellInfo
 {
+    CellInfo()
+        : pPatternAttr(nullptr)
+        , pConditionSet(nullptr)
+        , pBackground(nullptr)   // TODO: omit?
+        , pLinesAttr(nullptr)
+        , mpTLBRLine(nullptr)
+        , mpBLTRLine(nullptr)
+        , pShadowAttr(nullptr)
+        , pHShadowOrigin(nullptr)
+        , pVShadowOrigin(nullptr)
+        , eHShadowPart(SC_SHADOW_HSTART)
+        , eVShadowPart(SC_SHADOW_HSTART)
+        , nClipMark(SC_CLIPMARK_NONE)
+        , nWidth(0)
+        , nRotateDir(SC_ROTDIR_NONE)
+        , bMarked(false)
+        , bEmptyCellText(false)
+        , bMerged(false)
+        , bHOverlapped(false)
+        , bVOverlapped(false)
+        , bAutoFilter(false)
+        , bPivotButton(false)
+        , bPivotPopupButton(false)
+        , bFilterActive(false)
+        , bPrinted(false)       // view-internal
+        , bHideGrid(false)      // view-internal
+        , bEditEngine(false)    // view-internal
+    {
+    }
+
+    ~CellInfo() = default;
+    CellInfo(const CellInfo&) = delete;
+    const CellInfo& operator=(const CellInfo&) = delete;
+
     ScRefCellValue              maCell;
 
     const ScPatternAttr*        pPatternAttr;
@@ -139,8 +171,13 @@ struct CellInfo : boost::noncopyable
 
 const SCCOL SC_ROTMAX_NONE = SCCOL_MAX;
 
-struct RowInfo : boost::noncopyable
+struct RowInfo
 {
+    RowInfo() = default;
+    ~RowInfo() = default;
+    RowInfo(const RowInfo&) = delete;
+    const RowInfo& operator=(const RowInfo&) = delete;
+
     CellInfo*           pCellInfo;
 
     sal_uInt16          nHeight;
@@ -154,7 +191,7 @@ struct RowInfo : boost::noncopyable
     bool                bChanged:1;           // TRUE, if not tested
 };
 
-struct ScTableInfo : boost::noncopyable
+struct ScTableInfo
 {
     svx::frame::Array   maArray;
     RowInfo*            mpRowInfo;
@@ -163,6 +200,8 @@ struct ScTableInfo : boost::noncopyable
 
     explicit            ScTableInfo();
                         ~ScTableInfo();
+    ScTableInfo(const ScTableInfo&) = delete;
+    const ScTableInfo& operator=(const ScTableInfo&) = delete;
 };
 
 #endif
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index e9c7d4a..4fdcbf6 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -157,11 +157,11 @@ class RowInfoFiller
     {
         alignArray(nRow);
 
-        RowInfo* pThisRowInfo = &mpRowInfo[mnArrY];
-        CellInfo* pInfo = &pThisRowInfo->pCellInfo[mnArrX];
-        pInfo->maCell = rCell;
-        pThisRowInfo->bEmptyText = false;
-        pInfo->bEmptyCellText = false;
+        RowInfo& rThisRowInfo = mpRowInfo[mnArrY];
+        CellInfo& rInfo = rThisRowInfo.pCellInfo[mnArrX];
+        rInfo.maCell = rCell;
+        rThisRowInfo.bEmptyText = false;
+        rInfo.bEmptyCellText = false;
         ++mnArrY;
     }
 
@@ -266,55 +266,27 @@ void initCellInfo(RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nRotMax, bool bPain
         const SvxShadowItem* pDefShadow, SCROW nBlockStartY, SCROW nBlockEndY,
         SCCOL nBlockStartX, SCCOL nBlockEndX)
 {
-    for (SCSIZE nArrRow = 0; nArrRow < nArrCount; nArrRow++)
+    for (SCSIZE nArrRow = 0; nArrRow < nArrCount; ++nArrRow)
     {
-        RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
-        SCROW nY = pThisRowInfo->nRowNo;
-        pThisRowInfo->pCellInfo = new CellInfo[ nRotMax+1+2 ];  // to delete the caller!
+        RowInfo& rThisRowInfo = pRowInfo[nArrRow];
+        SCROW nY = rThisRowInfo.nRowNo;
+        rThisRowInfo.pCellInfo = new CellInfo[nRotMax + 1 + 2];  // to delete the caller!
 
-        for (SCCOL nArrCol = 0; nArrCol <= nRotMax+2; nArrCol++)          // Preassign cell info
+        for (SCCOL nArrCol = 0; nArrCol <= nRotMax+2; ++nArrCol) // Preassign cell info
         {
-            SCCOL nX;
-            if (nArrCol>0)
-                nX = nArrCol-1;
-            else
-                nX = MAXCOL+1;      // invalid
-
-            CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrCol];
-            pInfo->bEmptyCellText = true;
-            pInfo->maCell.clear();
+            CellInfo& rInfo = rThisRowInfo.pCellInfo[nArrCol];
             if (bPaintMarks)
-                pInfo->bMarked = ( nX >= nBlockStartX && nX <= nBlockEndX
-                                && nY >= nBlockStartY && nY <= nBlockEndY );
-            else
-                pInfo->bMarked = false;
-            pInfo->nWidth = 0;
-
-            pInfo->nClipMark    = SC_CLIPMARK_NONE;
-            pInfo->bMerged      = false;
-            pInfo->bHOverlapped = false;
-            pInfo->bVOverlapped = false;
-            pInfo->bAutoFilter  = false;
-            pInfo->bPivotButton  = false;
-            pInfo->bPivotPopupButton = false;
-            pInfo->bFilterActive = false;
-            pInfo->nRotateDir   = SC_ROTDIR_NONE;
-
-            pInfo->bPrinted     = false;                    //  view-internal
-            pInfo->bHideGrid    = false;                    //  view-internal
-            pInfo->bEditEngine  = false;                    //  view-internal
-
-            pInfo->pBackground  = nullptr;                     //TODO: omit?
-            pInfo->pPatternAttr = nullptr;
-            pInfo->pConditionSet= nullptr;
-
-            pInfo->pLinesAttr   = nullptr;
-            pInfo->mpTLBRLine   = nullptr;
-            pInfo->mpBLTRLine   = nullptr;
-
-            pInfo->pShadowAttr    = pDefShadow;
-            pInfo->pHShadowOrigin = nullptr;
-            pInfo->pVShadowOrigin = nullptr;
+            {
+                SCCOL nX;
+                if (nArrCol>0)
+                    nX = nArrCol-1;
+                else
+                    nX = MAXCOL+1;      // invalid
+                rInfo.bMarked = (nX >= nBlockStartX && nX <= nBlockEndX &&
+                                 nY >= nBlockStartY && nY <= nBlockEndY);
+            }
+            rInfo.bEmptyCellText = true;
+            rInfo.pShadowAttr    = pDefShadow;
         }
     }
 }
commit 3521850fb44778aa644b4eb5511bbf0276bf51f4
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Mar 30 02:55:18 2016 +0200

    add TODO comment for a bug
    
    This bug is the first one that was discovered because it is now much
    easier to see which parts of the code work on cells, pattern areas and
    whole columns/rows.
    
    Change-Id: I8f22bf421298947d65bfc2fc9c986d85169e6545
    Reviewed-on: https://gerrit.libreoffice.org/23636
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    (cherry picked from commit 2c69316037e29db52393d898100e6593a6cd5a24)
    Reviewed-on: https://gerrit.libreoffice.org/25291
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit 7547ff2c31066ec1b115dcee5500b892b3d3a881)

diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 0b9734d..e9c7d4a 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -363,6 +363,8 @@ bool handleConditionalFormat(ScConditionalFormatList* pCondFormList, const std::
                 pInfo->pConditionSet = &pStyleSheet->GetItemSet();
                 bAnyCondition = true;
 
+                // TODO: moggi: looks like there is a but around bHidden and bHideFormula
+                //              They are normally for the whole pattern and not for a single cell
                 // we need to check already here for protected cells
                 const SfxPoolItem* pItem;
                 if ( bTabProtect && pInfo->pConditionSet->GetItemState( ATTR_PROTECTION, true, &pItem ) == SfxItemState::SET )
commit fc834ce7bc3f0c2605af1cd989de0500543ea45f
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Mar 30 02:41:07 2016 +0200

    extract another function from ScDocument::FillInfo
    
    Change-Id: Ief094beebbff2bce9f087853cbda6adeeafe07fc
    Reviewed-on: https://gerrit.libreoffice.org/23635
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    (cherry picked from commit b22e51d0c60f959c2db77bd3d23119b53bd87545)
    Reviewed-on: https://gerrit.libreoffice.org/25290
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit ce571823e2be946308c814f600449e62f1b3a87d)

diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 1ee57b0..0b9734d 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -338,6 +338,68 @@ void initColWidths(RowInfo* pRowInfo, ScDocument* pDoc, double fColScale, SCTAB
     }
 }
 
+bool handleConditionalFormat(ScConditionalFormatList* pCondFormList, const std::vector<sal_uInt32> rCondFormats,
+        CellInfo* pInfo, ScStyleSheetPool* pStlPool,
+        const ScAddress& rAddr, bool& bHidden, bool& bHideFormula, bool bTabProtect)
+{
+    bool bFound = false;
+    bool bAnyCondition = false;
+    for(std::vector<sal_uInt32>::const_iterator itr = rCondFormats.begin();
+            itr != rCondFormats.end() && !bFound; ++itr)
+    {
+        ScConditionalFormat* pCondForm = pCondFormList->GetFormat(*itr);
+        if(!pCondForm)
+            continue;
+
+        ScCondFormatData aData = pCondForm->GetData(
+                pInfo->maCell, rAddr);
+        if (!aData.aStyleName.isEmpty())
+        {
+            SfxStyleSheetBase* pStyleSheet =
+                pStlPool->Find( aData.aStyleName, SFX_STYLE_FAMILY_PARA );
+            if ( pStyleSheet )
+            {
+                //TODO: cache Style-Sets !!!
+                pInfo->pConditionSet = &pStyleSheet->GetItemSet();
+                bAnyCondition = true;
+
+                // we need to check already here for protected cells
+                const SfxPoolItem* pItem;
+                if ( bTabProtect && pInfo->pConditionSet->GetItemState( ATTR_PROTECTION, true, &pItem ) == SfxItemState::SET )
+                {
+                    const ScProtectionAttr* pProtAttr = static_cast<const ScProtectionAttr*>(pItem);
+                    bHidden = pProtAttr->GetHideCell();
+                    bHideFormula = pProtAttr->GetHideFormula();
+
+                }
+                bFound = true;
+
+            }
+            // if style is not there, treat like no condition
+        }
+
+        if(aData.pColorScale)
+        {
+            pInfo->pColorScale.reset(aData.pColorScale);
+            bFound = true;
+        }
+
+        if(aData.pDataBar)
+        {
+            pInfo->pDataBar.reset(aData.pDataBar);
+            bFound = true;
+        }
+
+        if(aData.pIconSet)
+        {
+            pInfo->pIconSet.reset(aData.pIconSet);
+            bFound = true;
+        }
+    }
+
+    return bAnyCondition;
+}
+
 }
 
 void ScDocument::FillInfo(
@@ -564,61 +626,10 @@ void ScDocument::FillInfo(
                                     pThisRowInfo->bEmptyBack = false;
                                 }
 
-                                if ( bContainsCondFormat )
+                                if (bContainsCondFormat)
                                 {
-                                    bool bFound = false;
-                                    for(std::vector<sal_uInt32>::const_iterator itr = rCondFormats.begin();
-                                            itr != rCondFormats.end() && !bFound; ++itr)
-                                    {
-                                        ScConditionalFormat* pCondForm = pCondFormList->GetFormat(*itr);
-                                        if(!pCondForm)
-                                            continue;
-
-                                        ScCondFormatData aData = pCondForm->GetData(
-                                            pInfo->maCell, ScAddress(nX, nCurRow, nTab));
-                                        if (!aData.aStyleName.isEmpty())
-                                        {
-                                            SfxStyleSheetBase* pStyleSheet =
-                                                pStlPool->Find( aData.aStyleName, SFX_STYLE_FAMILY_PARA );
-                                            if ( pStyleSheet )
-                                            {
-                                                //TODO: cache Style-Sets !!!
-                                                pInfo->pConditionSet = &pStyleSheet->GetItemSet();
-                                                bAnyCondition = true;
-
-                                                // we need to check already here for protected cells
-                                                const SfxPoolItem* pItem;
-                                                if ( bTabProtect && pInfo->pConditionSet->GetItemState( ATTR_PROTECTION, true, &pItem ) == SfxItemState::SET )
-                                                {
-                                                    const ScProtectionAttr* pProtAttr = static_cast<const ScProtectionAttr*>(pItem);
-                                                    bHidden = pProtAttr->GetHideCell();
-                                                    bHideFormula = pProtAttr->GetHideFormula();
-
-                                                }
-                                                bFound = true;
-
-                                            }
-                                            // if style is not there, treat like no condition
-                                        }
-
-                                        if(aData.pColorScale)
-                                        {
-                                            pInfo->pColorScale.reset(aData.pColorScale);
-                                            bFound = true;
-                                        }
-
-                                        if(aData.pDataBar)
-                                        {
-                                            pInfo->pDataBar.reset(aData.pDataBar);
-                                            bFound = true;
-                                        }
-
-                                        if(aData.pIconSet)
-                                        {
-                                            pInfo->pIconSet.reset(aData.pIconSet);
-                                            bFound = true;
-                                        }
-                                    }
+                                    bAnyCondition |= handleConditionalFormat(pCondFormList, rCondFormats, pInfo, pStlPool, ScAddress(nX, nCurRow, nTab),
+                                            bHidden, bHideFormula, bTabProtect);
                                 }
 
                                 if (bHidden || (bFormulaMode && bHideFormula && pInfo->maCell.meType == CELLTYPE_FORMULA))
commit 0f4abdf32ebc7bbf5b5168e589d093ae2914a3a6
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Mar 30 02:25:16 2016 +0200

    stylistic changes in ScDocument::FillInfo
    
    Change-Id: I98bb25d414106259a809698941a000d6d0bc35e0
    Reviewed-on: https://gerrit.libreoffice.org/23634
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    Tested-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    (cherry picked from commit b27428d2136e67ee7c7449a7db562a957af390d6)
    Reviewed-on: https://gerrit.libreoffice.org/25289
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit 09a64f221b09683e636247b20b0b1ccdd8900039)

diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index cbb4dd1..1ee57b0 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -470,8 +470,9 @@ void ScDocument::FillInfo(
                         --nCurRow;                      // 1 more on top
                     else
                         nArrRow = 1;
+
                     SCROW nThisRow = nCurRow;                   // end of range
-                    SCSIZE  nIndex;
+                    SCSIZE nIndex;
                     (void) pThisAttrArr->Search( nCurRow, nIndex );
 
                     do
@@ -599,6 +600,7 @@ void ScDocument::FillInfo(
                                             }
                                             // if style is not there, treat like no condition
                                         }
+
                                         if(aData.pColorScale)
                                         {
                                             pInfo->pColorScale.reset(aData.pColorScale);
@@ -610,6 +612,7 @@ void ScDocument::FillInfo(
                                             pInfo->pDataBar.reset(aData.pDataBar);
                                             bFound = true;
                                         }
+
                                         if(aData.pIconSet)
                                         {
                                             pInfo->pIconSet.reset(aData.pIconSet);
commit 871fe705a88ab674dddc00c5547fe3f0b60cf9ee
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Mar 30 02:24:54 2016 +0200

    limit scope of another variable in ScDocument::FillInfo
    
    Change-Id: Ic53bcaa5e33f221a643de4e854990769b5c04a74
    Reviewed-on: https://gerrit.libreoffice.org/23633
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    (cherry picked from commit 8f0668a0e18f4fa01864ede5fa3f66b36bd4ad85)
    Reviewed-on: https://gerrit.libreoffice.org/25288
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit a7402aee62c5ddcf57bf1e7ef6c3ed7d43636650)

diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 2aade2a..cbb4dd1 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -465,7 +465,6 @@ void ScDocument::FillInfo(
                     ScAttrArray* pThisAttrArr = pThisCol->pAttrArray;       // Attribute
                     nArrRow = 0;
 
-                    const ScPatternAttr* pPattern;
                     SCROW nCurRow=nRow1;                  // single rows
                     if (nCurRow>0)
                         --nCurRow;                      // 1 more on top
@@ -478,7 +477,7 @@ void ScDocument::FillInfo(
                     do
                     {
                         nThisRow=pThisAttrArr->pData[nIndex].nRow;              // End of range
-                        pPattern=pThisAttrArr->pData[nIndex].pPattern;
+                        const ScPatternAttr* pPattern=pThisAttrArr->pData[nIndex].pPattern;
 
                         const SvxBrushItem* pBackground = static_cast<const SvxBrushItem*>(
                                                         &pPattern->GetItem(ATTR_BACKGROUND));
commit a9c3ce484c46132658dbb1e4162cc67ddc0e3e88
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Mar 30 02:15:07 2016 +0200

    limit the scope of a few variable in ScDocument::FillInfo
    
    This makes the code at least a little bit easier to read as we can now
    see much easier when a variable is used to transport state between loops
    and when it is just a variable local to a loop
    
    Reviewed-on: https://gerrit.libreoffice.org/23632
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    (cherry picked from commit 36eec4d179898302578c428564f1b60406c0716c)
    Reviewed-on: https://gerrit.libreoffice.org/25287
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit 5345c0f7ae6d2cad6814dc112c68ba3e6239fd8f)
    
    Change-Id: Ib92ff1596bda35f9892accc820bc3596bafb7d96

diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 7ec3453..2aade2a 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -209,27 +209,28 @@ bool isRotateItemUsed(ScDocumentPool *pPool)
     return false;
 }
 
-void initRowInfo(ScDocument* pDoc, RowInfo* pRowInfo, SCROW& rY,
+void initRowInfo(ScDocument* pDoc, RowInfo* pRowInfo,
         double fRowScale, SCROW nRow1, SCTAB nTab, SCROW& rYExtra, SCSIZE& rArrRow, SCROW& rRow2)
 {
     sal_uInt16 nDocHeight = ScGlobal::nStdRowHeight;
     SCROW nDocHeightEndRow = -1;
     for (SCsROW nSignedY=((SCsROW)nRow1)-1; nSignedY<=(SCsROW)rYExtra; nSignedY++)
     {
+        SCROW nY;
         if (nSignedY >= 0)
-            rY = (SCROW) nSignedY;
+            nY = (SCROW) nSignedY;
         else
-            rY = MAXROW+1;          // invalid
+            nY = MAXROW+1;          // invalid
 
-        if (rY > nDocHeightEndRow)
+        if (nY > nDocHeightEndRow)
         {
-            if (ValidRow(rY))
-                nDocHeight = pDoc->GetRowHeight( rY, nTab, nullptr, &nDocHeightEndRow );
+            if (ValidRow(nY))
+                nDocHeight = pDoc->GetRowHeight( nY, nTab, nullptr, &nDocHeightEndRow );
             else
                 nDocHeight = ScGlobal::nStdRowHeight;
         }
 
-        if ( rArrRow==0 || nDocHeight || rY > MAXROW )
+        if ( rArrRow==0 || nDocHeight || nY > MAXROW )
         {
             RowInfo* pThisRowInfo = &pRowInfo[rArrRow];
             pThisRowInfo->pCellInfo = nullptr;                 // is loaded below
@@ -238,7 +239,7 @@ void initRowInfo(ScDocument* pDoc, RowInfo* pRowInfo, SCROW& rY,
             if (!nHeight)
                 nHeight = 1;
 
-            pThisRowInfo->nRowNo        = rY;               //TODO: case < 0 ?
+            pThisRowInfo->nRowNo        = nY;               //TODO: case < 0 ?
             pThisRowInfo->nHeight       = nHeight;
             pThisRowInfo->bEmptyBack    = true;
             pThisRowInfo->bEmptyText    = true;
@@ -360,11 +361,6 @@ void ScDocument::FillInfo(
     const SvxShadowItem* pDefShadow =
             static_cast<const SvxShadowItem*>( &pPool->GetDefaultItem( ATTR_SHADOW ) );
 
-    SCROW nThisRow;
-    SCCOL nX;
-    SCROW nY;
-    SCsROW nSignedY;
-    SCCOL nArrCol;
     SCSIZE nArrRow;
     SCSIZE nArrCount;
     bool bAnyMerged = false;
@@ -402,53 +398,8 @@ void ScDocument::FillInfo(
 
     nArrRow=0;
     SCROW nYExtra = nRow2+1;
-    sal_uInt16 nDocHeight = ScGlobal::nStdRowHeight;
-    SCROW nDocHeightEndRow = -1;
-    for (nSignedY=((SCsROW)nRow1)-1; nSignedY<=(SCsROW)nYExtra; nSignedY++)
-    {
-        if (nSignedY >= 0)
-            nY = (SCROW) nSignedY;
-        else
-            nY = MAXROW+1;          // invalid
-
-        if (nY > nDocHeightEndRow)
-        {
-            if (ValidRow(nY))
-                nDocHeight = GetRowHeight( nY, nTab, nullptr, &nDocHeightEndRow );
-            else
-                nDocHeight = ScGlobal::nStdRowHeight;
-        }
-
-        if ( nArrRow==0 || nDocHeight || nY > MAXROW )
-        {
-            RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
-            pThisRowInfo->pCellInfo = nullptr;                 // is loaded below
-
-            sal_uInt16 nHeight = (sal_uInt16) ( nDocHeight * fRowScale );
-            if (!nHeight)
-                nHeight = 1;
-
-            pThisRowInfo->nRowNo        = nY;               //TODO: case < 0 ?
-            pThisRowInfo->nHeight       = nHeight;
-            pThisRowInfo->bEmptyBack    = true;
-            pThisRowInfo->bEmptyText    = true;
-            pThisRowInfo->bChanged      = true;
-            pThisRowInfo->bAutoFilter   = false;
-            pThisRowInfo->bPivotButton  = false;
-            pThisRowInfo->nRotMaxCol    = SC_ROTMAX_NONE;
-
-            ++nArrRow;
-            if (nArrRow >= ROWINFO_MAX)
-            {
-                OSL_FAIL("FillInfo: Range too big" );
-                nYExtra = nSignedY;                         // End
-                nRow2 = nYExtra - 1;                        // Adjust range
-            }
-        }
-        else
-            if (nSignedY==(SCsROW) nYExtra)                 // hidden additional line?
-                ++nYExtra;
-    }
+    initRowInfo(this, pRowInfo, fRowScale, nRow1,
+            nTab, nYExtra, nArrRow, nRow2);
     nArrCount = nArrRow;                                      // incl. Dummys
 
     // Rotated text...
@@ -482,9 +433,9 @@ void ScDocument::FillInfo(
     if(pCondFormList)
         pCondFormList->startRendering();
 
-    for (nArrCol=0; nArrCol<=nCol2+2; nArrCol++)                    // left & right + 1
+    for (SCCOL nArrCol=0; nArrCol<=nCol2+2; nArrCol++)                    // left & right + 1
     {
-        nX = (nArrCol>0) ? nArrCol-1 : MAXCOL+1;                    // negative -> invalid
+        SCCOL nX = (nArrCol>0) ? nArrCol-1 : MAXCOL+1;                    // negative -> invalid
 
         if ( ValidCol(nX) )
         {
@@ -520,7 +471,7 @@ void ScDocument::FillInfo(
                         --nCurRow;                      // 1 more on top
                     else
                         nArrRow = 1;
-                    nThisRow=nCurRow;                   // end of range
+                    SCROW nThisRow = nCurRow;                   // end of range
                     SCSIZE  nIndex;
                     (void) pThisAttrArr->Search( nCurRow, nIndex );
 
@@ -757,7 +708,7 @@ void ScDocument::FillInfo(
     {
         for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
         {
-            for (nArrCol=nCol1; nArrCol<=nCol2+2; nArrCol++)                  // 1 more left and right
+            for (SCCOL nArrCol=nCol1; nArrCol<=nCol2+2; nArrCol++)                  // 1 more left and right
             {
                 CellInfo* pInfo = &pRowInfo[nArrRow].pCellInfo[nArrCol];
                 SCCOL nCol = (nArrCol>0) ? nArrCol-1 : MAXCOL+1;
@@ -820,9 +771,9 @@ void ScDocument::FillInfo(
         for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
         {
             RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
-            nSignedY = nArrRow ? pThisRowInfo->nRowNo : ((SCsROW)nRow1)-1;
+            SCsROW nSignedY = nArrRow ? pThisRowInfo->nRowNo : ((SCsROW)nRow1)-1;
 
-            for (nArrCol=nCol1; nArrCol<=nCol2+2; nArrCol++)                  // 1 more left and right
+            for (SCCOL nArrCol=nCol1; nArrCol<=nCol2+2; nArrCol++)                  // 1 more left and right
             {
                 SCsCOL nSignedX = ((SCsCOL) nArrCol) - 1;
                 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrCol];
@@ -885,7 +836,7 @@ void ScDocument::FillInfo(
             bool bTop = ( nArrRow == 0 );
             bool bBottom = ( nArrRow+1 == nArrCount );
 
-            for (nArrCol=nCol1; nArrCol<=nCol2+2; nArrCol++)                  // 1 more left and right
+            for (SCCOL nArrCol=nCol1; nArrCol<=nCol2+2; nArrCol++)                  // 1 more left and right
             {
                 bool bLeft = ( nArrCol == nCol1 );
                 bool bRight = ( nArrCol == nCol2+2 );
commit 1f194348d5d19db7e8cbb226c4a45388b9942b63
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Wed Mar 30 01:50:53 2016 +0200

    extract another function from ScDocument::FillInfo
    
    Change-Id: Iac607e1fe915c8bc90316508c98855a60117d435
    Reviewed-on: https://gerrit.libreoffice.org/23631
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    (cherry picked from commit 772e66406b90bdb898e73b4fa944a6e55a42683b)
    Reviewed-on: https://gerrit.libreoffice.org/25286
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit b2a02da8e7866dd5ce61bf5cff56d6066f3e4a06)

diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index aaa05fd..7ec3453 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -318,6 +318,25 @@ void initCellInfo(RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nRotMax, bool bPain
     }
 }
 
+void initColWidths(RowInfo* pRowInfo, ScDocument* pDoc, double fColScale, SCTAB nTab, SCCOL nCol2, SCCOL nRotMax)
+{
+    for (SCCOL nArrCol=nCol2+3; nArrCol<=nRotMax+2; nArrCol++)    // Add remaining widths
+    {
+        SCCOL nX = nArrCol-1;
+        if ( ValidCol(nX) )
+        {
+            if (!pDoc->ColHidden(nX, nTab))
+            {
+                sal_uInt16 nThisWidth = (sal_uInt16) (pDoc->GetColWidth( nX, nTab ) * fColScale);
+                if (!nThisWidth)
+                    nThisWidth = 1;
+
+                pRowInfo[0].pCellInfo[nArrCol].nWidth = nThisWidth;
+            }
+        }
+    }
+}
+
 }
 
 void ScDocument::FillInfo(
@@ -457,21 +476,7 @@ void ScDocument::FillInfo(
     initCellInfo(pRowInfo, nArrCount, nRotMax, bPaintMarks, pDefShadow,
             nBlockStartY, nBlockEndY, nBlockStartX, nBlockEndX);
 
-    for (nArrCol=nCol2+3; nArrCol<=nRotMax+2; nArrCol++)    // Add remaining widths
-    {
-        nX = nArrCol-1;
-        if ( ValidCol(nX) )
-        {
-            if (!ColHidden(nX, nTab))
-            {
-                sal_uInt16 nThisWidth = (sal_uInt16) (GetColWidth( nX, nTab ) * fColScale);
-                if (!nThisWidth)
-                    nThisWidth = 1;
-
-                pRowInfo[0].pCellInfo[nArrCol].nWidth = nThisWidth;
-            }
-        }
-    }
+    initColWidths(pRowInfo, this, fColScale, nTab, nCol2, nRotMax);
 
     ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
     if(pCondFormList)
commit 2914372543828b73de08ad6c50be984d7dbdb484
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Sun Mar 27 05:11:20 2016 +0200

    extract another function from ScDocument::FillInfo
    
    Change-Id: If6f898d514dc454a7f1c5448769a95269e9066d7
    Reviewed-on: https://gerrit.libreoffice.org/23550
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    (cherry picked from commit 5ecda97eeab36ceab022458345f2c61c31ab2d94)
    Reviewed-on: https://gerrit.libreoffice.org/25285
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit 40b2e53d22347e625cd22f0ac8fd6c79165b3703)

diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index f298f26..aaa05fd 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -261,6 +261,63 @@ void initRowInfo(ScDocument* pDoc, RowInfo* pRowInfo, SCROW& rY,
     }
 }
 
+void initCellInfo(RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nRotMax, bool bPaintMarks,
+        const SvxShadowItem* pDefShadow, SCROW nBlockStartY, SCROW nBlockEndY,
+        SCCOL nBlockStartX, SCCOL nBlockEndX)
+{
+    for (SCSIZE nArrRow = 0; nArrRow < nArrCount; nArrRow++)
+    {
+        RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
+        SCROW nY = pThisRowInfo->nRowNo;
+        pThisRowInfo->pCellInfo = new CellInfo[ nRotMax+1+2 ];  // to delete the caller!
+
+        for (SCCOL nArrCol = 0; nArrCol <= nRotMax+2; nArrCol++)          // Preassign cell info
+        {
+            SCCOL nX;
+            if (nArrCol>0)
+                nX = nArrCol-1;
+            else
+                nX = MAXCOL+1;      // invalid
+
+            CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrCol];
+            pInfo->bEmptyCellText = true;
+            pInfo->maCell.clear();
+            if (bPaintMarks)
+                pInfo->bMarked = ( nX >= nBlockStartX && nX <= nBlockEndX
+                                && nY >= nBlockStartY && nY <= nBlockEndY );
+            else
+                pInfo->bMarked = false;
+            pInfo->nWidth = 0;
+
+            pInfo->nClipMark    = SC_CLIPMARK_NONE;
+            pInfo->bMerged      = false;
+            pInfo->bHOverlapped = false;
+            pInfo->bVOverlapped = false;
+            pInfo->bAutoFilter  = false;
+            pInfo->bPivotButton  = false;
+            pInfo->bPivotPopupButton = false;
+            pInfo->bFilterActive = false;
+            pInfo->nRotateDir   = SC_ROTDIR_NONE;
+
+            pInfo->bPrinted     = false;                    //  view-internal
+            pInfo->bHideGrid    = false;                    //  view-internal
+            pInfo->bEditEngine  = false;                    //  view-internal
+
+            pInfo->pBackground  = nullptr;                     //TODO: omit?
+            pInfo->pPatternAttr = nullptr;
+            pInfo->pConditionSet= nullptr;
+
+            pInfo->pLinesAttr   = nullptr;
+            pInfo->mpTLBRLine   = nullptr;
+            pInfo->mpBLTRLine   = nullptr;
+
+            pInfo->pShadowAttr    = pDefShadow;
+            pInfo->pHShadowOrigin = nullptr;
+            pInfo->pVShadowOrigin = nullptr;
+        }
+    }
+}
+
 }
 
 void ScDocument::FillInfo(
@@ -397,57 +454,8 @@ void ScDocument::FillInfo(
 
     //  Allocate cell information only after the test rotation
     //  to nRotMax due to nRotateDir Flag
-
-    for (nArrRow=0; nArrRow<nArrCount; nArrRow++)
-    {
-        RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
-        nY = pThisRowInfo->nRowNo;
-        pThisRowInfo->pCellInfo = new CellInfo[ nRotMax+1+2 ];  // to delete the caller!
-
-        for (nArrCol=0; nArrCol<=nRotMax+2; nArrCol++)          // Preassign cell info
-        {
-            if (nArrCol>0)
-                nX = nArrCol-1;
-            else
-                nX = MAXCOL+1;      // invalid
-
-            CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrCol];
-            pInfo->bEmptyCellText = true;
-            pInfo->maCell.clear();
-            if (bPaintMarks)
-                pInfo->bMarked = ( nX >= nBlockStartX && nX <= nBlockEndX
-                                && nY >= nBlockStartY && nY <= nBlockEndY );
-            else
-                pInfo->bMarked = false;
-            pInfo->nWidth = 0;
-
-            pInfo->nClipMark    = SC_CLIPMARK_NONE;
-            pInfo->bMerged      = false;
-            pInfo->bHOverlapped = false;
-            pInfo->bVOverlapped = false;
-            pInfo->bAutoFilter  = false;
-            pInfo->bPivotButton  = false;
-            pInfo->bPivotPopupButton = false;
-            pInfo->bFilterActive = false;
-            pInfo->nRotateDir   = SC_ROTDIR_NONE;
-
-            pInfo->bPrinted     = false;                    //  view-internal
-            pInfo->bHideGrid    = false;                    //  view-internal
-            pInfo->bEditEngine  = false;                    //  view-internal
-
-            pInfo->pBackground  = nullptr;                     //TODO: omit?
-            pInfo->pPatternAttr = nullptr;
-            pInfo->pConditionSet= nullptr;
-
-            pInfo->pLinesAttr   = nullptr;
-            pInfo->mpTLBRLine   = nullptr;
-            pInfo->mpBLTRLine   = nullptr;
-
-            pInfo->pShadowAttr    = pDefShadow;
-            pInfo->pHShadowOrigin = nullptr;
-            pInfo->pVShadowOrigin = nullptr;
-        }
-    }
+    initCellInfo(pRowInfo, nArrCount, nRotMax, bPaintMarks, pDefShadow,
+            nBlockStartY, nBlockEndY, nBlockStartX, nBlockEndX);
 
     for (nArrCol=nCol2+3; nArrCol<=nRotMax+2; nArrCol++)    // Add remaining widths
     {
commit 3b8c064b359a0902e21ba67f87a059fa32aa1af4
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Tue Mar 29 18:59:24 2016 +0200

    that should not have become part of the previous commit
    
    Change-Id: Ia116e5f9fdbd34cd1017ec1f2dabf6e581c4c707
    (cherry picked from commit 789a3e61785a2458429890e28ad9a37fab8cdade)
    Reviewed-on: https://gerrit.libreoffice.org/25284
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit 7c942ee446ff357d2cd874913b15b4d641ed1ba6)

diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 5281a7d..f298f26 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -489,16 +489,17 @@ void ScDocument::FillInfo(
 
                 ScColumn* pThisCol = &maTabs[nTab]->aCol[nX];                   // Column data
 
-                nArrRow = 0;
+                nArrRow = 1;
                 // Iterate between rows nY1 and nY2 and pick up non-empty
                 // cells that are not hidden.
                 RowInfoFiller aFunc(*this, nTab, pRowInfo, nArrCol, nArrRow);
                 sc::ParseAllNonEmpty(
-                    pThisCol->maCells.begin(), pThisCol->maCells, std::max<SCROW>(0 , nRow1 - 1), nYExtra, aFunc);
+                    pThisCol->maCells.begin(), pThisCol->maCells, nRow1, nRow2, aFunc);
 
                 if (nX+1 >= nCol1)                                // Attribute/Blockmark from nX1-1
                 {
                     ScAttrArray* pThisAttrArr = pThisCol->pAttrArray;       // Attribute
+                    nArrRow = 0;
 
                     const ScPatternAttr* pPattern;
                     SCROW nCurRow=nRow1;                  // single rows
commit 08efe5d4add290543349b4a800ce77d9965feea5
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Sun Mar 27 04:56:55 2016 +0200

    extract another function from ScDocument::FillInfo
    
    (cherry picked from commit a70824f0220b88f3f209266f8e1cba98dc89ca8f)
    
    Reviewed-on: https://gerrit.libreoffice.org/25283
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit c8774715d10707989267b550841984cd50b07e74)
    
    Change-Id: Ifd39ec5ad7aebac532ea7145274005507a5b177f

diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 0979781..5281a7d 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -135,7 +135,7 @@ class RowInfoFiller
     SCTAB mnTab;
     RowInfo* mpRowInfo;
     SCCOL mnArrX;
-    SCSIZE& mrArrY;
+    SCSIZE mnArrY;
     SCROW mnHiddenEndRow;
     bool mbHiddenRow;
 
@@ -149,25 +149,25 @@ class RowInfoFiller
 
     void alignArray(size_t nRow)
     {
-        while (mpRowInfo[mrArrY].nRowNo < static_cast<SCROW>(nRow))
-            ++mrArrY;
+        while (mpRowInfo[mnArrY].nRowNo < static_cast<SCROW>(nRow))
+            ++mnArrY;
     }
 
     void setInfo(size_t nRow, const ScRefCellValue& rCell)
     {
         alignArray(nRow);
 
-        RowInfo* pThisRowInfo = &mpRowInfo[mrArrY];
+        RowInfo* pThisRowInfo = &mpRowInfo[mnArrY];
         CellInfo* pInfo = &pThisRowInfo->pCellInfo[mnArrX];
         pInfo->maCell = rCell;
         pThisRowInfo->bEmptyText = false;
         pInfo->bEmptyCellText = false;
-        ++mrArrY;
+        ++mnArrY;
     }
 
 public:
     RowInfoFiller(ScDocument& rDoc, SCTAB nTab, RowInfo* pRowInfo, SCCOL nArrX, SCSIZE& rArrY) :
-        mrDoc(rDoc), mnTab(nTab), mpRowInfo(pRowInfo), mnArrX(nArrX), mrArrY(rArrY),
+        mrDoc(rDoc), mnTab(nTab), mpRowInfo(pRowInfo), mnArrX(nArrX), mnArrY(rArrY),
         mnHiddenEndRow(-1), mbHiddenRow(false) {}
 
     void operator() (size_t nRow, double fVal)
@@ -209,6 +209,58 @@ bool isRotateItemUsed(ScDocumentPool *pPool)
     return false;
 }
 
+void initRowInfo(ScDocument* pDoc, RowInfo* pRowInfo, SCROW& rY,
+        double fRowScale, SCROW nRow1, SCTAB nTab, SCROW& rYExtra, SCSIZE& rArrRow, SCROW& rRow2)
+{
+    sal_uInt16 nDocHeight = ScGlobal::nStdRowHeight;
+    SCROW nDocHeightEndRow = -1;
+    for (SCsROW nSignedY=((SCsROW)nRow1)-1; nSignedY<=(SCsROW)rYExtra; nSignedY++)
+    {
+        if (nSignedY >= 0)
+            rY = (SCROW) nSignedY;
+        else
+            rY = MAXROW+1;          // invalid
+
+        if (rY > nDocHeightEndRow)
+        {
+            if (ValidRow(rY))
+                nDocHeight = pDoc->GetRowHeight( rY, nTab, nullptr, &nDocHeightEndRow );
+            else
+                nDocHeight = ScGlobal::nStdRowHeight;
+        }
+
+        if ( rArrRow==0 || nDocHeight || rY > MAXROW )
+        {
+            RowInfo* pThisRowInfo = &pRowInfo[rArrRow];
+            pThisRowInfo->pCellInfo = nullptr;                 // is loaded below
+
+            sal_uInt16 nHeight = (sal_uInt16) ( nDocHeight * fRowScale );
+            if (!nHeight)
+                nHeight = 1;
+
+            pThisRowInfo->nRowNo        = rY;               //TODO: case < 0 ?
+            pThisRowInfo->nHeight       = nHeight;
+            pThisRowInfo->bEmptyBack    = true;
+            pThisRowInfo->bEmptyText    = true;
+            pThisRowInfo->bChanged      = true;
+            pThisRowInfo->bAutoFilter   = false;
+            pThisRowInfo->bPivotButton  = false;
+            pThisRowInfo->nRotMaxCol    = SC_ROTMAX_NONE;
+
+            ++rArrRow;
+            if (rArrRow >= ROWINFO_MAX)
+            {
+                OSL_FAIL("FillInfo: Range too big" );
+                rYExtra = nSignedY;                         // End
+                rRow2 = rYExtra - 1;                        // Adjust range
+            }
+        }
+        else
+            if (nSignedY==(SCsROW) rYExtra)                 // hidden additional line?
+                ++rYExtra;
+    }
+}
+
 }
 
 void ScDocument::FillInfo(
@@ -329,7 +381,7 @@ void ScDocument::FillInfo(
     bool bAnyItem = isRotateItemUsed(pPool);
 
     SCCOL nRotMax = nCol2;
-    if ( bAnyItem && HasAttrib( 0,nRow1,nTab, MAXCOL,nRow2+1,nTab,
+    if ( bAnyItem && HasAttrib( 0, nRow1, nTab, MAXCOL, nRow2+1, nTab,
                                 HASATTR_ROTATE | HASATTR_CONDITIONAL ) )
     {
         //TODO: check Conditionals also for HASATTR_ROTATE ????
@@ -437,18 +489,17 @@ void ScDocument::FillInfo(
 
                 ScColumn* pThisCol = &maTabs[nTab]->aCol[nX];                   // Column data
 
-                nArrRow = 1;
+                nArrRow = 0;
                 // Iterate between rows nY1 and nY2 and pick up non-empty
                 // cells that are not hidden.
                 RowInfoFiller aFunc(*this, nTab, pRowInfo, nArrCol, nArrRow);
                 sc::ParseAllNonEmpty(
-                    pThisCol->maCells.begin(), pThisCol->maCells, nRow1, nRow2, aFunc);
+                    pThisCol->maCells.begin(), pThisCol->maCells, std::max<SCROW>(0 , nRow1 - 1), nYExtra, aFunc);
 
                 if (nX+1 >= nCol1)                                // Attribute/Blockmark from nX1-1
                 {
                     ScAttrArray* pThisAttrArr = pThisCol->pAttrArray;       // Attribute
 
-                    nArrRow = 0;
                     const ScPatternAttr* pPattern;
                     SCROW nCurRow=nRow1;                  // single rows
                     if (nCurRow>0)
commit 1edd1a36624a0986d742e55ea3666d8c5a13a1ab
Author: Dennis Francis <dennisfrancis.in at gmail.com>
Date:   Sat Feb 6 03:12:20 2016 +0530

    Refactor ScMarkData for tdf#50916
    
    Made the container for storing multimarks dynamic.
    Also let the full row marks to be stored in a dedicated
    ScMarkArray object rather than in the multimarks container.
    
    Unit tests for ScMarkData and ScMultiSel will come in a follow up
    patch.
    
    Reviewed-on: https://gerrit.libreoffice.org/22163
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    (cherry picked from commit bc20c6d0f397c0c1aef6ef7d6f750c2f81af8db6)
    
    Reviewed-on: https://gerrit.libreoffice.org/25282
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>
    (cherry picked from commit b921fbc46e7593fd2d5e5d5c88508522937fdae0)
    
    Change-Id: I300ff80bebd6f4f39c284c1e8cb7deece82c1bec

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 8304a9a..60ff984 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -165,6 +165,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
     sc/source/core/data/listenercontext \
     sc/source/core/data/markarr \
     sc/source/core/data/markdata \
+    sc/source/core/data/markmulti \
     sc/source/core/data/mtvelements \
     sc/source/core/data/olinetab \
     sc/source/core/data/pagepar \
diff --git a/sc/inc/markarr.hxx b/sc/inc/markarr.hxx
index 2988fe4..386b97a 100644
--- a/sc/inc/markarr.hxx
+++ b/sc/inc/markarr.hxx
@@ -41,6 +41,7 @@ friend class ScDocument;                // for FillInfo
 
 public:
             ScMarkArray();
+            ScMarkArray( ScMarkArray&& rArray );
             ~ScMarkArray();
     void    Reset( bool bMarked = false );
     bool    GetMark( SCROW nRow ) const;
diff --git a/sc/inc/markdata.hxx b/sc/inc/markdata.hxx
index 20777a6..0392971 100644
--- a/sc/inc/markdata.hxx
+++ b/sc/inc/markdata.hxx
@@ -21,6 +21,8 @@
 #define INCLUDED_SC_INC_MARKDATA_HXX
 
 #include "address.hxx"
+#include "rangelst.hxx"
+#include "markmulti.hxx"
 #include "scdllapi.h"
 
 #include <set>
@@ -49,12 +51,17 @@ private:
 
     ScRange         aMarkRange;             // area
     ScRange         aMultiRange;            // maximum area altogether
-    ScMarkArray*    pMultiSel;              // multi selection
+    ScMultiSel      aMultiSel;              // multi selection
     bool            bMarked:1;                // rectangle marked
     bool            bMultiMarked:1;
 
     bool            bMarking:1;               // area is being marked -> no MarkToMulti
     bool            bMarkIsNeg:1;             // cancel if multi selection
+    ScRangeList     aTopEnvelope;             // list of ranges in the top envelope of the multi selection
+    ScRangeList     aBottomEnvelope;          // list of ranges in the bottom envelope of the multi selection
+    ScRangeList     aLeftEnvelope;            // list of ranges in the left envelope of the multi selection
+    ScRangeList     aRightEnvelope;           // list of ranges in the right envelope of the multi selection
+
 
 public:
                 ScMarkData();
@@ -66,7 +73,8 @@ public:
     void        ResetMark();
     void        SetMarkArea( const ScRange& rRange );
 
-    void        SetMultiMarkArea( const ScRange& rRange, bool bMark = true );
+    // bSetupMulti must be set to true only for recursive calls to SetMultiMarkArea
+    void        SetMultiMarkArea( const ScRange& rRange, bool bMark = true, bool bSetupMulti = false );
 
     void        MarkToMulti();
     void        MarkToSimple();
@@ -96,7 +104,8 @@ public:
     bool        GetMarkingFlag() const          { return bMarking;    }
 
     //  for FillInfo / Document etc.
-    const ScMarkArray* GetArray() const         { return pMultiSel; }
+    const ScMultiSel& GetMultiSelData() const   { return aMultiSel;   }
+    ScMarkArray GetMarkArray( SCCOL nCol ) const;
 
     bool        IsCellMarked( SCCOL nCol, SCROW nRow, bool bNoSimple = false ) const;
     void        FillRangeListWithMarks( ScRangeList* pList, bool bClear ) const;
@@ -122,6 +131,15 @@ public:
     void        InsertTab( SCTAB nTab );
     void        DeleteTab( SCTAB nTab );
 
+    // Generate envelopes if mutimarked and fills the passed ScRange object with
+    // the smallest range that includes the marked area plus its envelopes.
+    void        GetSelectionCover( ScRange& rRange );
+    // Get top, bottom, left and right envelopes
+    const ScRangeList& GetTopEnvelope() const    { return aTopEnvelope;    }
+    const ScRangeList& GetBottomEnvelope() const { return aBottomEnvelope; }
+    const ScRangeList& GetLeftEnvelope() const   { return aLeftEnvelope;   }
+    const ScRangeList& GetRightEnvelope() const  { return aRightEnvelope;  }
+
     // iterators for table access
     typedef std::set<SCTAB>::iterator iterator;
     typedef std::set<SCTAB>::const_iterator const_iterator;
diff --git a/sc/inc/markmulti.hxx b/sc/inc/markmulti.hxx
new file mode 100644
index 0000000..22f0ee5
--- /dev/null
+++ b/sc/inc/markmulti.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SC_INC_MARKMULTI_HXX
+#define INCLUDED_SC_INC_MARKMULTI_HXX
+
+#include "address.hxx"
+#include "segmenttree.hxx"
+#include "markarr.hxx"
+
+#include <map>
+
+class ScMultiSel
+{
+
+private:
+    typedef std::map<SCCOL, ScMarkArray> MapType;
+    MapType aMultiSelContainer;
+    ScMarkArray aRowSel;
+
+friend class ScMultiSelIter;
+
+public:
+    ScMultiSel();
+    ScMultiSel( const ScMultiSel& rMultiSel );
+    ~ScMultiSel();
+
+    ScMultiSel& operator=(const ScMultiSel& rMultiSel);
+    ScMultiSel& operator=(const ScMultiSel&& rMultiSel) = delete;
+
+    SCCOL size() const
+    {
+        return static_cast<SCCOL>( aMultiSelContainer.size() );
+    }
+
+    bool HasMarks( SCCOL nCol ) const;
+    bool HasOneMark( SCCOL nCol, SCROW& rStartRow, SCROW& rEndRow ) const;
+    bool GetMark( SCCOL nCol, SCROW nRow ) const;
+    bool IsAllMarked( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const;
+    bool HasEqualRowsMarked( SCCOL nCol1, SCCOL nCol2 ) const;
+    SCsROW GetNextMarked( SCCOL nCol, SCsROW nRow, bool bUp ) const;
+    void SetMarkArea( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow, bool bMark );
+    bool IsRowMarked( SCROW nRow ) const;
+    bool IsRowRangeMarked( SCROW nStartRow, SCROW nEndRow ) const;
+    bool IsEmpty() const { return ( !aMultiSelContainer.size() && !aRowSel.HasMarks() ); }
+    ScMarkArray GetMarkArray( SCCOL nCol ) const;
+    void Clear();
+    void MarkAllCols( SCROW nStartRow, SCROW nEndRow );
+    bool HasAnyMarks() const;
+};
+
+class ScMultiSelIter
+{
+
+private:
+    ScFlatBoolRowSegments aRowSegs;
+    SCROW nNextSegmentStart;
+public:
+    ScMultiSelIter( const ScMultiSel& rMultiSel, SCCOL nCol );
+    ~ScMultiSelIter();
+
+    bool Next( SCROW& rTop, SCROW& rBottom );
+    const ScFlatBoolRowSegments& GetRowSegments() const { return aRowSegs; }
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/segmenttree.hxx b/sc/inc/segmenttree.hxx
index 72d45b6..3a2d128 100644
--- a/sc/inc/segmenttree.hxx
+++ b/sc/inc/segmenttree.hxx
@@ -68,7 +68,7 @@ public:
 
     bool setTrue(SCROW nRow1, SCROW nRow2);
     bool setFalse(SCROW nRow1, SCROW nRow2);
-    bool getRangeData(SCROW nRow, RangeData& rData);
+    bool getRangeData(SCROW nRow, RangeData& rData) const;
     bool getRangeDataLeaf(SCROW nRow, RangeData& rData);
     void removeSegment(SCROW nRow1, SCROW nRow2);
     void insertSegment(SCROW nRow, SCROW nSize, bool bSkipStartBoundary);
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index d4b5a2e..18b4622 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -314,8 +314,8 @@ bool ScColumn::HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) c
 
     if (rMark.IsMultiMarked())
     {
-        ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
-        while (aMarkIter.Next( nTop, nBottom ) && !bFound)
+        ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
+        while (aMultiIter.Next( nTop, nBottom ) && !bFound)
         {
             if (pAttrArray->HasAttrib( nTop, nBottom, nMask ))
                 bFound = true;
@@ -339,11 +339,11 @@ void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkD
 
     if ( rMark.IsMultiMarked() )
     {
-        const ScMarkArray* pArray = rMark.GetArray() + nCol;
-        if ( pArray->HasMarks() )
+        const ScMultiSel& rMultiSel = rMark.GetMultiSelData();
+        if ( rMultiSel.HasMarks( nCol ) )
         {
-            ScMarkArrayIter aMarkIter( pArray );
-            while (aMarkIter.Next( nTop, nBottom ))
+            ScMultiSelIter aMultiIter( rMultiSel, nCol );
+            while (aMultiIter.Next( nTop, nBottom ))
                 pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep );
         }
     }
@@ -430,8 +430,8 @@ SCsROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData
 
     if ( rMark.IsMultiMarked() )
     {
-        ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
-        while (aMarkIter.Next( nTop, nBottom ))
+        ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
+        while (aMultiIter.Next( nTop, nBottom ))
         {
             pAttrArray->ApplyCacheArea( nTop, nBottom, pCache, pDataArray );
             bFound = true;
@@ -453,8 +453,8 @@ void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
 
     if ( pAttrArray && rMark.IsMultiMarked() )
     {
-        ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
-        while (aMarkIter.Next( nTop, nBottom ))
+        ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
+        while (aMultiIter.Next( nTop, nBottom ))
             pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
     }
 }
@@ -466,8 +466,8 @@ void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& r
 
     if ( pAttrArray && rMark.IsMultiMarked() )
     {
-        ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
-        while (aMarkIter.Next( nTop, nBottom ))
+        ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
+        while (aMultiIter.Next( nTop, nBottom ))
             pAttrArray->ClearItems(nTop, nBottom, pWhich);
     }
 }
@@ -479,8 +479,8 @@ void ScColumn::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rM
 
     if ( rMark.IsMultiMarked() )
     {
-        ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
-        while (aMarkIter.Next( nTop, nBottom ))
+        ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
+        while (aMultiIter.Next( nTop, nBottom ))
             DeleteArea(nTop, nBottom, nDelFlag, bBroadcast);
     }
 }
@@ -569,8 +569,8 @@ void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData&
 
     if ( rMark.IsMultiMarked() )
     {
-        ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
-        while (aMarkIter.Next( nTop, nBottom ))
+        ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
+        while (aMultiIter.Next( nTop, nBottom ))
             pAttrArray->ApplyStyleArea(nTop, nBottom, const_cast<ScStyleSheet*>(&rStyle));
     }
 }
@@ -586,8 +586,8 @@ void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark,
 
     if (rMark.IsMultiMarked())
     {
-        ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
-        while (aMarkIter.Next( nTop, nBottom ))
+        ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
+        while (aMultiIter.Next( nTop, nBottom ))
             pAttrArray->ApplyLineStyleArea(nTop, nBottom, pLine, bColorOnly );
     }
 }
@@ -611,10 +611,10 @@ const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, bool&
     const ScStyleSheet* pStyle = nullptr;
     const ScStyleSheet* pNewStyle;
 
-    ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
+    ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
     SCROW nTop;
     SCROW nBottom;
-    while (bEqual && aMarkIter.Next( nTop, nBottom ))
+    while (bEqual && aMultiIter.Next( nTop, nBottom ))
     {
         ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
         SCROW nRow;
@@ -1635,7 +1635,7 @@ void ScColumn::CopyToColumn(
         SCROW nStart, nEnd;
         if (pMarkData && pMarkData->IsMultiMarked())
         {
-            ScMarkArrayIter aIter( pMarkData->GetArray()+nCol );
+            ScMultiSelIter aIter( pMarkData->GetMultiSelData(), nCol );
 
             while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 )
             {
@@ -3467,7 +3467,10 @@ SCsROW ScColumn::SearchStyle(
     if (bInSelection)
     {
         if (rMark.IsMultiMarked())
-            return pAttrArray->SearchStyle(nRow, pSearchStyle, bUp, rMark.GetArray()+nCol);
+        {
+            ScMarkArray aArray(rMark.GetMarkArray(nCol));
+            return pAttrArray->SearchStyle(nRow, pSearchStyle, bUp, &aArray);
+        }
         else
             return -1;
     }
@@ -3482,8 +3485,11 @@ bool ScColumn::SearchStyleRange(
     if (bInSelection)
     {
         if (rMark.IsMultiMarked())
+        {
+            ScMarkArray aArray(rMark.GetMarkArray(nCol));
             return pAttrArray->SearchStyleRange(
-                rRow, rEndRow, pSearchStyle, bUp, rMark.GetArray() + nCol);
+                rRow, rEndRow, pSearchStyle, bUp, &aArray);
+        }
         else
             return false;
     }
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 4737121..c48c5a4 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1117,7 +1117,7 @@ void ScColumn::MixMarked(
 
     if (rMark.IsMultiMarked())
     {
-        ScMarkArrayIter aIter( rMark.GetArray()+nCol );
+        ScMultiSelIter aIter( rMark.GetMultiSelData(), nCol );
         while (aIter.Next( nRow1, nRow2 ))
             MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol);
     }
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 33319cb..0979781 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -624,17 +624,17 @@ void ScDocument::FillInfo(
                     if (pMarkData && pMarkData->IsMultiMarked())
                     {
                         //  Block marks
-                        const ScMarkArray* pThisMarkArr = pMarkData->GetArray()+nX;
+                        ScMarkArray aThisMarkArr(pMarkData->GetMarkArray( nX ));
                         nArrRow = 1;
                         nCurRow = nRow1;                                      // single rows
                         nThisRow = nRow1;                                     // End of range
 
-                        if ( pThisMarkArr->Search( nRow1, nIndex ) )
+                        if ( aThisMarkArr.Search( nRow1, nIndex ) )
                         {
                             do
                             {
-                                nThisRow=pThisMarkArr->pData[nIndex].nRow;      // End of range
-                                const bool bThisMarked=pThisMarkArr->pData[nIndex].bMarked;
+                                nThisRow=aThisMarkArr.pData[nIndex].nRow;      // End of range
+                                const bool bThisMarked=aThisMarkArr.pData[nIndex].bMarked;
 
                                 do
                                 {
@@ -661,7 +661,7 @@ void ScDocument::FillInfo(
                                 while (nCurRow <= nThisRow && nCurRow <= nRow2);
                                 ++nIndex;
                             }
-                            while ( nIndex < pThisMarkArr->nCount && nThisRow < nRow2 );
+                            while ( nIndex < aThisMarkArr.nCount && nThisRow < nRow2 );
                         }
                     }
                 }
@@ -801,10 +801,10 @@ void ScDocument::FillInfo(
                                     && nStartY <= (SCsROW) nBlockEndY );
                     if (pMarkData && pMarkData->IsMultiMarked() && !bCellMarked)
                     {
-                        const ScMarkArray* pThisMarkArr = pMarkData->GetArray()+nStartX;
+                        ScMarkArray aThisMarkArr(pMarkData->GetMarkArray( nStartX ));
                         SCSIZE nIndex;
-                        if ( pThisMarkArr->Search( nStartY, nIndex ) )
-                            bCellMarked=pThisMarkArr->pData[nIndex].bMarked;
+                        if ( aThisMarkArr.Search( nStartY, nIndex ) )
+                            bCellMarked=aThisMarkArr.pData[nIndex].bMarked;
                     }
 
                     pInfo->bMarked = bCellMarked;
diff --git a/sc/source/core/data/markarr.cxx b/sc/source/core/data/markarr.cxx
index f21ce8d..66bfa0e 100644
--- a/sc/source/core/data/markarr.cxx
+++ b/sc/source/core/data/markarr.cxx
@@ -33,6 +33,17 @@ ScMarkArray::ScMarkArray() :
     // special case "no marks" with pData = NULL
 }
 
+// Move constructor
+ScMarkArray::ScMarkArray( ScMarkArray&& rArray ) :
+    nCount( rArray.nCount ),
+    nLimit( rArray.nLimit ),
+    pData( rArray.pData )
+{
+    rArray.nCount = 0;
+    rArray.nLimit = 0;
+    rArray.pData = nullptr;
+}
+
 ScMarkArray::~ScMarkArray()
 {
     delete[] pData;
diff --git a/sc/source/core/data/markdata.cxx b/sc/source/core/data/markdata.cxx
index 137a2e4..154a693 100644
--- a/sc/source/core/data/markdata.cxx
+++ b/sc/source/core/data/markdata.cxx
@@ -19,19 +19,21 @@
 
 #include "markdata.hxx"
 #include "markarr.hxx"
+#include "markmulti.hxx"
 #include "rangelst.hxx"
+#include "segmenttree.hxx"
 #include <columnspanset.hxx>
 #include <fstalgorithm.hxx>
+#include <unordered_map>
 
 #include <osl/diagnose.h>
 
 #include <mdds/flat_segment_tree.hpp>
 
-// STATIC DATA -----------------------------------------------------------
 
 ScMarkData::ScMarkData() :
     maTabMarked(),
-    pMultiSel( nullptr )
+    aMultiSel()
 {
     ResetMark();
 }
@@ -40,19 +42,16 @@ ScMarkData::ScMarkData(const ScMarkData& rData) :
     maTabMarked( rData.maTabMarked ),
     aMarkRange( rData.aMarkRange ),
     aMultiRange( rData.aMultiRange ),
-    pMultiSel( nullptr )
+    aMultiSel( rData.aMultiSel ),
+    aTopEnvelope( rData.aTopEnvelope ),
+    aBottomEnvelope( rData.aBottomEnvelope ),
+    aLeftEnvelope( rData.aLeftEnvelope ),
+    aRightEnvelope( rData.aRightEnvelope )
 {
     bMarked      = rData.bMarked;
     bMultiMarked = rData.bMultiMarked;
     bMarking     = rData.bMarking;
     bMarkIsNeg   = rData.bMarkIsNeg;
-
-    if (rData.pMultiSel)
-    {
-        pMultiSel = new ScMarkArray[MAXCOLCOUNT];
-        for (SCCOL j=0; j<MAXCOLCOUNT; j++)
-            rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] );
-    }
 }
 
 ScMarkData& ScMarkData::operator=(const ScMarkData& rData)
@@ -60,40 +59,37 @@ ScMarkData& ScMarkData::operator=(const ScMarkData& rData)
     if ( &rData == this )
         return *this;
 
-    delete[] pMultiSel;
-    pMultiSel = nullptr;
-
     aMarkRange   = rData.aMarkRange;
     aMultiRange  = rData.aMultiRange;
     bMarked      = rData.bMarked;
     bMultiMarked = rData.bMultiMarked;
     bMarking     = rData.bMarking;
     bMarkIsNeg   = rData.bMarkIsNeg;
+    aTopEnvelope = rData.aTopEnvelope;
+    aBottomEnvelope = rData.aBottomEnvelope;
+    aLeftEnvelope   = rData.aLeftEnvelope;
+    aRightEnvelope  = rData.aRightEnvelope;
 
     maTabMarked = rData.maTabMarked;
-
-    if (rData.pMultiSel)
-    {
-        pMultiSel = new ScMarkArray[MAXCOLCOUNT];
-        for (SCCOL j=0; j<MAXCOLCOUNT; j++)
-            rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] );
-    }
+    aMultiSel = rData.aMultiSel;
 
     return *this;
 }
 
 ScMarkData::~ScMarkData()
 {
-    delete[] pMultiSel;
 }
 
 void ScMarkData::ResetMark()
 {
-    delete[] pMultiSel;
-    pMultiSel = nullptr;
+    aMultiSel.Clear();
 
     bMarked = bMultiMarked = false;
     bMarking = bMarkIsNeg = false;
+    aTopEnvelope.RemoveAll();
+    aBottomEnvelope.RemoveAll();
+    aLeftEnvelope.RemoveAll();
+    aRightEnvelope.RemoveAll();
 }
 
 void ScMarkData::SetMarkArea( const ScRange& rRange )
@@ -121,17 +117,18 @@ void ScMarkData::GetMultiMarkArea( ScRange& rRange ) const
     rRange = aMultiRange;
 }
 
-void ScMarkData::SetMultiMarkArea( const ScRange& rRange, bool bMark )
+void ScMarkData::SetMultiMarkArea( const ScRange& rRange, bool bMark, bool bSetupMulti )
 {
-    if (!pMultiSel)
+    if ( aMultiSel.IsEmpty() )
     {
-        pMultiSel = new ScMarkArray[MAXCOL+1];
-
         // if simple mark range is set, copy to multi marks
-        if ( bMarked && !bMarkIsNeg )
+        if ( bMarked && !bMarkIsNeg && !bSetupMulti )
         {
             bMarked = false;
-            SetMultiMarkArea( aMarkRange );
+            SCCOL nStartCol = aMarkRange.aStart.Col();
+            SCCOL nEndCol = aMarkRange.aEnd.Col();
+            PutInOrder( nStartCol, nEndCol );
+            SetMultiMarkArea( aMarkRange, true, true );
         }
     }
 
@@ -142,9 +139,7 @@ void ScMarkData::SetMultiMarkArea( const ScRange& rRange, bool bMark )
     PutInOrder( nStartRow, nEndRow );
     PutInOrder( nStartCol, nEndCol );
 
-    SCCOL nCol;
-    for (nCol=nStartCol; nCol<=nEndCol; nCol++)
-        pMultiSel[nCol].SetMarkArea( nStartRow, nEndRow, bMark );
+    aMultiSel.SetMarkArea( nStartCol, nEndCol, nStartRow, nEndRow, bMark );
 
     if ( bMultiMarked )                 // Update aMultiRange
     {
@@ -247,27 +242,25 @@ void ScMarkData::MarkToSimple()
 
     if ( bMultiMarked )
     {
-        OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
-
         ScRange aNew = aMultiRange;
 
         bool bOk = false;
         SCCOL nStartCol = aNew.aStart.Col();
         SCCOL nEndCol   = aNew.aEnd.Col();
 
-        while ( nStartCol < nEndCol && !pMultiSel[nStartCol].HasMarks() )
+        while ( nStartCol < nEndCol && !aMultiSel.HasMarks( nStartCol ) )
             ++nStartCol;
-        while ( nStartCol < nEndCol && !pMultiSel[nEndCol].HasMarks() )
+        while ( nStartCol < nEndCol && !aMultiSel.HasMarks( nEndCol ) )
             --nEndCol;
 
         // Rows are only taken from MarkArray
         SCROW nStartRow, nEndRow;
-        if ( pMultiSel[nStartCol].HasOneMark( nStartRow, nEndRow ) )
+        if ( aMultiSel.HasOneMark( nStartCol, nStartRow, nEndRow ) )
         {
             bOk = true;
             SCROW nCmpStart, nCmpEnd;
             for (SCCOL nCol=nStartCol+1; nCol<=nEndCol && bOk; nCol++)
-                if ( !pMultiSel[nCol].HasOneMark( nCmpStart, nCmpEnd )
+                if ( !aMultiSel.HasOneMark( nCol, nCmpStart, nCmpEnd )
                         || nCmpStart != nStartRow || nCmpEnd != nEndRow )
                     bOk = false;
         }
@@ -298,8 +291,7 @@ bool ScMarkData::IsCellMarked( SCCOL nCol, SCROW nRow, bool bNoSimple ) const
     {
         //TODO: test here for negative Marking ?
 
-        OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
-        return pMultiSel[nCol].GetMark( nRow );
+        return aMultiSel.GetMark( nCol, nRow );
     }
 
     return false;
@@ -315,7 +307,7 @@ bool ScMarkData::IsColumnMarked( SCCOL nCol ) const
                     aMarkRange.aStart.Row() == 0    && aMarkRange.aEnd.Row() == MAXROW )
         return true;
 
-    if ( bMultiMarked && pMultiSel[nCol].IsAllMarked(0,MAXROW) )
+    if ( bMultiMarked && aMultiSel.IsAllMarked( nCol, 0, MAXROW ) )
         return true;
 
     return false;
@@ -332,13 +324,7 @@ bool ScMarkData::IsRowMarked( SCROW nRow ) const
         return true;
 
     if ( bMultiMarked )
-    {
-        OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
-        for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
-            if (!pMultiSel[nCol].GetMark(nRow))
-                return false;
-        return true;
-    }
+        return aMultiSel.IsRowMarked( nRow );
 
     return false;
 }
@@ -381,15 +367,13 @@ void ScMarkData::FillRangeListWithMarks( ScRangeList* pList, bool bClear ) const
 
     if ( bMultiMarked )
     {
-        OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
-
         SCTAB nTab = aMultiRange.aStart.Tab();
 
         SCCOL nStartCol = aMultiRange.aStart.Col();
         SCCOL nEndCol = aMultiRange.aEnd.Col();
         for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
         {
-            if (pMultiSel[nCol].HasMarks())
+            if (aMultiSel.HasMarks( nCol ))
             {
                 // Feeding column-wise fragments to ScRangeList::Join() is a
                 // huge bottleneck, speed this up for multiple columns
@@ -399,14 +383,14 @@ void ScMarkData::FillRangeListWithMarks( ScRangeList* pList, bool bClear ) const
                 SCCOL nToCol = nCol+1;
                 for ( ; nToCol <= nEndCol; ++nToCol)
                 {
-                    if (!pMultiSel[nCol].HasEqualRowsMarked( pMultiSel[nToCol]))
+                    if (!aMultiSel.HasEqualRowsMarked(nCol, nToCol))
                         break;
                 }
                 --nToCol;
                 ScRange aRange( nCol, 0, nTab, nToCol, 0, nTab );
                 SCROW nTop, nBottom;
-                ScMarkArrayIter aMarkIter( &pMultiSel[nCol] );
-                while ( aMarkIter.Next( nTop, nBottom ) )
+                ScMultiSelIter aMultiIter( aMultiSel, nCol );
+                while ( aMultiIter.Next( nTop, nBottom ) )
                 {
                     aRange.aStart.SetRow( nTop );
                     aRange.aEnd.SetRow( nBottom );
@@ -486,15 +470,17 @@ bool ScMarkData::IsAllMarked( const ScRange& rRange ) const
     if ( !bMultiMarked )
         return false;
 
-    OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
-
     SCCOL nStartCol = rRange.aStart.Col();
     SCROW nStartRow = rRange.aStart.Row();
     SCCOL nEndCol = rRange.aEnd.Col();
     SCROW nEndRow = rRange.aEnd.Row();
     bool bOk = true;
+
+    if ( nStartCol == 0 && nEndCol == MAXCOL )
+        return aMultiSel.IsRowRangeMarked( nStartRow, nEndRow );
+
     for (SCCOL nCol=nStartCol; nCol<=nEndCol && bOk; nCol++)
-        if ( !pMultiSel[nCol].IsAllMarked( nStartRow, nEndRow ) )
+        if ( !aMultiSel.IsAllMarked( nCol, nStartRow, nEndRow ) )
             bOk = false;
 
     return bOk;
@@ -505,9 +491,7 @@ SCsROW ScMarkData::GetNextMarked( SCCOL nCol, SCsROW nRow, bool bUp ) const
     if ( !bMultiMarked )
         return nRow;
 
-    OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
-
-    return pMultiSel[nCol].GetNextMarked( nRow, bUp );
+    return aMultiSel.GetNextMarked( nCol, nRow, bUp );
 }
 
 bool ScMarkData::HasMultiMarks( SCCOL nCol ) const
@@ -515,9 +499,7 @@ bool ScMarkData::HasMultiMarks( SCCOL nCol ) const
     if ( !bMultiMarked )
         return false;
 
-    OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
-
-    return pMultiSel[nCol].HasMarks();
+    return aMultiSel.HasMarks( nCol );
 }
 
 bool ScMarkData::HasAnyMultiMarks() const
@@ -525,13 +507,7 @@ bool ScMarkData::HasAnyMultiMarks() const
     if ( !bMultiMarked )
         return false;
 
-    OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
-
-    for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
-        if ( pMultiSel[nCol].HasMarks() )
-            return true;
-
-    return false;       // no
+    return aMultiSel.HasAnyMarks();
 }
 
 void ScMarkData::InsertTab( SCTAB nTab )
@@ -553,6 +529,261 @@ void ScMarkData::DeleteTab( SCTAB nTab )
     maTabMarked.swap(tabMarked);
 }
 
+static void lcl_AddRanges(ScRange& rRangeDest, const ScRange& rNewRange )
+{
+    SCCOL nStartCol = rNewRange.aStart.Col();
+    SCROW nStartRow = rNewRange.aStart.Row();
+    SCCOL nEndCol = rNewRange.aEnd.Col();
+    SCROW nEndRow = rNewRange.aEnd.Row();
+    PutInOrder( nStartRow, nEndRow );
+    PutInOrder( nStartCol, nEndCol );
+    if ( nStartCol < rRangeDest.aStart.Col() )
+        rRangeDest.aStart.SetCol( nStartCol );
+    if ( nStartRow < rRangeDest.aStart.Row() )
+        rRangeDest.aStart.SetRow( nStartRow );
+    if ( nEndCol > rRangeDest.aEnd.Col() )
+        rRangeDest.aEnd.SetCol( nEndCol );
+    if ( nEndRow > rRangeDest.aEnd.Row() )
+        rRangeDest.aEnd.SetRow( nEndRow );
+}
+
+void ScMarkData::GetSelectionCover( ScRange& rRange )
+{
+    if( bMultiMarked )
+    {
+        rRange = aMultiRange;
+        SCCOL nStartCol = aMultiRange.aStart.Col(), nEndCol = aMultiRange.aEnd.Col();
+        PutInOrder( nStartCol, nEndCol );
+        nStartCol = ( nStartCol == 0 ) ? nStartCol : nStartCol - 1;
+        nEndCol = ( nEndCol == MAXCOL ) ? nEndCol : nEndCol + 1;
+        std::unique_ptr<ScFlatBoolRowSegments> pPrevColMarkedRows;
+        std::unique_ptr<ScFlatBoolRowSegments> pCurColMarkedRows;
+        std::unordered_map<SCROW,ScFlatBoolColSegments> aRowToColSegmentsInTopEnvelope;
+        std::unordered_map<SCROW,ScFlatBoolColSegments> aRowToColSegmentsInBottomEnvelope;
+        ScFlatBoolRowSegments aNoRowsMarked;
+        aNoRowsMarked.setFalse( 0, MAXROW );
+
+        bool bPrevColUnMarked = false;
+
+        for ( SCCOL nCol=nStartCol; nCol <= nEndCol; nCol++ )
+        {
+            SCROW nTop, nBottom;
+            bool bCurColUnMarked = !aMultiSel.HasMarks( nCol );
+            if ( !bCurColUnMarked )
+            {
+                pCurColMarkedRows.reset( new ScFlatBoolRowSegments() );
+                pCurColMarkedRows->setFalse( 0, MAXROW );
+                ScMultiSelIter aMultiIter( aMultiSel, nCol );
+                ScFlatBoolRowSegments::ForwardIterator aPrevItr ( pPrevColMarkedRows.get() ? *pPrevColMarkedRows : aNoRowsMarked ); // For finding left envelope
+                ScFlatBoolRowSegments::ForwardIterator aPrevItr1( pPrevColMarkedRows.get() ? *pPrevColMarkedRows : aNoRowsMarked ); // For finding right envelope
+                SCROW nTopPrev = 0, nBottomPrev = 0; // For right envelope
+                while ( aMultiIter.Next( nTop, nBottom ) )
+                {
+                    pCurColMarkedRows->setTrue( nTop, nBottom );
+                    if( bPrevColUnMarked && ( nCol > nStartCol ))
+                    {
+                        ScRange aAddRange(nCol - 1, nTop, aMultiRange.aStart.Tab(),
+                                          nCol - 1, nBottom, aMultiRange.aStart.Tab());
+                        lcl_AddRanges( rRange, aAddRange ); // Left envelope
+                        aLeftEnvelope.Append( aAddRange );
+                    }
+                    else if( nCol > nStartCol )
+                    {
+                        SCROW nTop1 = nTop, nBottom1 = nTop;
+                        while( nTop1 <= nBottom && nBottom1 <= nBottom )
+                        {
+                            bool bRangeMarked = false;
+                            aPrevItr.getValue( nTop1, bRangeMarked );
+                            if( bRangeMarked )
+                            {
+                                nTop1 = aPrevItr.getLastPos() + 1;
+                                nBottom1 = nTop1;
+                            }
+                            else
+                            {
+                                nBottom1 = aPrevItr.getLastPos();
+                                if( nBottom1 > nBottom )
+                                    nBottom1 = nBottom;
+                                ScRange aAddRange( nCol - 1, nTop1, aMultiRange.aStart.Tab(),
+                                                   nCol - 1, nBottom1, aMultiRange.aStart.Tab() );
+                                lcl_AddRanges( rRange, aAddRange ); // Left envelope
+                                aLeftEnvelope.Append( aAddRange );
+                                nTop1 = ++nBottom1;
+                            }
+                        }
+                        while( nTopPrev <= nBottom && nBottomPrev <= nBottom )
+                        {
+                            bool bRangeMarked;
+                            aPrevItr1.getValue( nTopPrev, bRangeMarked );
+                            if( bRangeMarked )
+                            {
+                                nBottomPrev = aPrevItr1.getLastPos();
+                                if( nTopPrev < nTop )
+                                {
+                                    if( nBottomPrev >= nTop )
+                                    {
+                                        nBottomPrev = nTop - 1;
+                                        ScRange aAddRange( nCol, nTopPrev, aMultiRange.aStart.Tab(),
+                                                           nCol, nBottomPrev, aMultiRange.aStart.Tab());
+                                        lcl_AddRanges( rRange, aAddRange ); // Right envelope
+                                        aRightEnvelope.Append( aAddRange );
+                                        nTopPrev = nBottomPrev = (nBottom + 1);
+                                    }
+                                    else
+                                    {
+                                        ScRange aAddRange( nCol, nTopPrev, aMultiRange.aStart.Tab(),
+                                                           nCol, nBottomPrev, aMultiRange.aStart.Tab());
+                                        lcl_AddRanges( rRange, aAddRange ); // Right envelope
+                                        aRightEnvelope.Append( aAddRange );
+                                        nTopPrev = ++nBottomPrev;
+                                    }
+                                }
+                                else
+                                    nTopPrev = nBottomPrev = ( nBottom + 1 );
+                            }
+                            else
+                            {
+                                nBottomPrev = aPrevItr1.getLastPos();
+                                nTopPrev = ++nBottomPrev;
+                            }
+                        }
+                    }
+                    if( nTop )
+                    {
+                        ScRange aAddRange( nCol, nTop - 1, aMultiRange.aStart.Tab(),
+                                           nCol, nTop - 1, aMultiRange.aStart.Tab());
+                        lcl_AddRanges( rRange, aAddRange ); // Top envelope
+                        aRowToColSegmentsInTopEnvelope[nTop - 1].setTrue( nCol, nCol );
+                    }
+                    if( nBottom < MAXROW )
+                    {
+                        ScRange aAddRange(nCol, nBottom + 1, aMultiRange.aStart.Tab(),
+                                          nCol, nBottom + 1, aMultiRange.aStart.Tab());
+                        lcl_AddRanges( rRange, aAddRange ); // Bottom envelope
+                        aRowToColSegmentsInBottomEnvelope[nBottom + 1].setTrue( nCol, nCol );
+                    }
+                }
+
+                while( nTopPrev <= MAXROW && nBottomPrev <= MAXROW && ( nCol > nStartCol ) )
+                {
+                    bool bRangeMarked;
+                    aPrevItr1.getValue( nTopPrev, bRangeMarked );
+                    if( bRangeMarked )
+                    {
+                        nBottomPrev = aPrevItr1.getLastPos();
+                        ScRange aAddRange(nCol, nTopPrev, aMultiRange.aStart.Tab(),
+                                          nCol, nBottomPrev, aMultiRange.aStart.Tab());
+                        lcl_AddRanges( rRange, aAddRange ); // Right envelope
+                        aRightEnvelope.Append( aAddRange );
+                        nTopPrev = ++nBottomPrev;
+                    }
+                    else
+                    {
+                        nBottomPrev = aPrevItr1.getLastPos();
+                        nTopPrev = ++nBottomPrev;
+                    }
+                }
+            }
+            else if( nCol > nStartCol )
+            {
+                bPrevColUnMarked = true;
+                SCROW nTopPrev = 0, nBottomPrev = 0;
+                bool bRangeMarked = false;
+                ScFlatBoolRowSegments::ForwardIterator aPrevItr( pPrevColMarkedRows.get() ? *pPrevColMarkedRows : aNoRowsMarked );
+                while( nTopPrev <= MAXROW && nBottomPrev <= MAXROW )
+                {
+                    aPrevItr.getValue(nTopPrev, bRangeMarked);
+                    if( bRangeMarked )
+                    {
+                        nBottomPrev = aPrevItr.getLastPos();
+                        ScRange aAddRange(nCol, nTopPrev, aMultiRange.aStart.Tab(),
+                                          nCol, nBottomPrev, aMultiRange.aStart.Tab());
+                        lcl_AddRanges( rRange, aAddRange ); // Right envelope
+                        aRightEnvelope.Append( aAddRange );
+                        nTopPrev = ++nBottomPrev;
+                    }
+                    else
+                    {
+                        nBottomPrev = aPrevItr.getLastPos();
+                        nTopPrev = ++nBottomPrev;
+                    }
+                }
+            }
+            if ( bCurColUnMarked )
+                pPrevColMarkedRows.reset( nullptr );
+            else
+                pPrevColMarkedRows.reset( pCurColMarkedRows.release() );
+        }
+        for( auto& rKV : aRowToColSegmentsInTopEnvelope )
+        {
+            SCCOL nStart = nStartCol;
+            ScFlatBoolColSegments::RangeData aRange;
+            while( nStart <= nEndCol )
+            {
+                if( !rKV.second.getRangeData( nStart, aRange ) )
+                    break;
+                if( aRange.mbValue ) // is marked
+                    aTopEnvelope.Append( ScRange( aRange.mnCol1, rKV.first, aMultiRange.aStart.Tab(),
+                                                  aRange.mnCol2, rKV.first, aMultiRange.aStart.Tab() ) );
+                nStart = aRange.mnCol2 + 1;
+            }
+        }
+        for( auto& rKV : aRowToColSegmentsInBottomEnvelope )
+        {
+            SCCOL nStart = nStartCol;
+            ScFlatBoolColSegments::RangeData aRange;
+            while( nStart <= nEndCol )
+            {
+                if( !rKV.second.getRangeData( nStart, aRange ) )
+                    break;
+                if( aRange.mbValue ) // is marked
+                    aBottomEnvelope.Append( ScRange( aRange.mnCol1, rKV.first, aMultiRange.aStart.Tab(),
+                                                     aRange.mnCol2, rKV.first, aMultiRange.aStart.Tab() ) );
+                nStart = aRange.mnCol2 + 1;
+            }
+        }
+    }
+    else if( bMarked )
+    {
+        aMarkRange.PutInOrder();
+        SCROW nRow1, nRow2, nRow1New, nRow2New;
+        SCCOL nCol1, nCol2, nCol1New, nCol2New;
+        SCTAB nTab1, nTab2;
+        aMarkRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+        nCol1New = nCol1;
+        nCol2New = nCol2;
+        nRow1New = nRow1;
+        nRow2New = nRow2;
+        // Each envelope will have zero or more ranges for single rectangle selection.
+        if( nCol1 > 0 )
+        {
+            aLeftEnvelope.Append( ScRange( nCol1 - 1, nRow1, nTab1, nCol1 - 1, nRow2, nTab2 ) );
+            --nCol1New;
+        }
+        if( nRow1 > 0 )
+        {
+            aTopEnvelope.Append( ScRange( nCol1, nRow1 - 1, nTab1, nCol2, nRow1 - 1, nTab2 ) );
+            --nRow1New;
+        }
+        if( nCol2 < MAXCOL )
+        {
+            aRightEnvelope.Append( ScRange( nCol2 + 1, nRow1, nTab1, nCol2 + 1, nRow2, nTab2 ) );
+            ++nCol2New;
+        }
+        if( nRow2 < MAXROW )
+        {
+            aBottomEnvelope.Append( ScRange( nCol1, nRow2 + 1, nTab1, nCol2, nRow2 + 1, nTab2 ) );
+            ++nRow2New;
+        }
+        rRange = ScRange( nCol1New, nRow1New, nTab1, nCol2New, nRow2New, nTab2 );
+    }
+}
+
+ScMarkArray ScMarkData::GetMarkArray( SCCOL nCol ) const
+{
+    return aMultiSel.GetMarkArray( nCol );
+}
+
 //iterators
 ScMarkData::iterator ScMarkData::begin()
 {
diff --git a/sc/source/core/data/markmulti.cxx b/sc/source/core/data/markmulti.cxx
new file mode 100644
index 0000000..07502c1
--- /dev/null
+++ b/sc/source/core/data/markmulti.cxx
@@ -0,0 +1,348 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list