[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.3' - 7 commits - desktop/qa include/sal sc/inc sc/sdi sc/source

Marco Cecchetti marco.cecchetti at collabora.com
Tue Apr 4 17:05:43 UTC 2017


 desktop/qa/desktop_lib/test_desktop_lib.cxx |    4 
 include/sal/log-areas.dox                   |    3 
 sc/inc/address.hxx                          |    2 
 sc/sdi/scalc.sdi                            |    2 
 sc/source/ui/inc/tabview.hxx                |    5 
 sc/source/ui/inc/viewdata.hxx               |   53 +++
 sc/source/ui/unoobj/docuno.cxx              |   20 +
 sc/source/ui/view/cellsh3.cxx               |    2 
 sc/source/ui/view/gridwin.cxx               |    7 
 sc/source/ui/view/tabview.cxx               |  426 +++++++++++++++++++++-------
 sc/source/ui/view/viewdata.cxx              |  269 +++++++++++++++++
 sc/source/ui/view/viewfunc.cxx              |   29 +
 12 files changed, 706 insertions(+), 116 deletions(-)

New commits:
commit 533a283eeda5d2751e49bbdadfdc673fcefb5e77
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Sun Apr 2 20:46:41 2017 +0200

    LOK - Calc: beyond row 65535 it is not possibile to resize a row
    
    The row parameter type was a unsigned short.
    
    Change-Id: I2da1a96d60988e8f1efeb49f55032fb84a8b562b

diff --git a/sc/sdi/scalc.sdi b/sc/sdi/scalc.sdi
index c19e12268024..735e18086e36 100644
--- a/sc/sdi/scalc.sdi
+++ b/sc/sdi/scalc.sdi
@@ -4461,7 +4461,7 @@ SfxInt32Item Row SID_RANGE_ROW
 
 
 SfxUInt16Item RowHeight FID_ROW_HEIGHT
-(SfxUInt16Item Row FN_PARAM_1,SfxUInt16Item Height FN_PARAM_2)
+(SfxInt32Item Row FN_PARAM_1,SfxUInt16Item Height FN_PARAM_2)
 [
     AutoUpdate = FALSE,
     FastCall = FALSE,
diff --git a/sc/source/ui/view/cellsh3.cxx b/sc/source/ui/view/cellsh3.cxx
index a9f4c2abab38..1674b121996f 100644
--- a/sc/source/ui/view/cellsh3.cxx
+++ b/sc/source/ui/view/cellsh3.cxx
@@ -546,7 +546,7 @@ void ScCellShell::Execute( SfxRequest& rReq )
                                  pReqArgs->HasItem( FN_PARAM_2, &pHeight ) )
                 {
                     std::vector<sc::ColRowSpan> aRanges;
-                    SCCOLROW nRow = static_cast<const SfxUInt16Item*>(pRow)->GetValue() - 1;
+                    SCCOLROW nRow = static_cast<const SfxInt32Item*>(pRow)->GetValue() - 1;
                     sal_uInt16 nHeight = static_cast<const SfxUInt16Item*>(pHeight)->GetValue();
                     ScMarkData& rMark = GetViewData()->GetMarkData();
 
commit 105ce60b5274c19bf4f359d31bd4ee37698620bc
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Wed Mar 29 13:57:31 2017 +0200

    LOK - Calc: lift row limit to 500k
    
    Due to previously intruduced optimizations, it is safe and fast enough
    to navigate through a 500k rows document.
    
    Change-Id: I8055672b58ea3c1e262f6e49d029eb0cf67086b5

diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx
index aa5d4f14017b..43cad11ef409 100644
--- a/sc/inc/address.hxx
+++ b/sc/inc/address.hxx
@@ -71,7 +71,7 @@ const SCCOL       MAXCOL         = MAXCOLCOUNT - 1;
 const SCTAB       MAXTAB         = MAXTABCOUNT - 1;
 const SCCOLROW    MAXCOLROW      = MAXROW;
 // Maximun tiled rendering values
-const SCROW       MAXTILEDROW    = 10000;
+const SCROW       MAXTILEDROW    = 500000;
 // Limit the initial tab count to prevent users to set the count too high,
 // which could cause the memory usage of blank documents to exceed the
 // available system memory.
commit f675f9531483cb59d34c13f3746010e438298704
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Wed Mar 29 13:50:18 2017 +0200

    LOK - Calc: row/column headers are updated faster
    
    Now the computation of the row/column headers data exploits the cached
    row/col positions in HeightHelper/WidthHelper.
    
    That makes updating row/column headers at the bottom of the document
    as fast as at the top even for very big spreadsheets.
    
    Change-Id: Ida0ed8d8885b71fe3206efbdaa62a0bb95153ed7

diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 20958267a291..2dfb036e6be7 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -636,7 +636,7 @@ void DesktopLOKTest::testRowColumnHeaders()
         if (bFirstHeader)
         {
             CPPUNIT_ASSERT(nSize <= nY);
-            CPPUNIT_ASSERT_EQUAL(OString("11"), aText);
+            CPPUNIT_ASSERT_EQUAL(OString("10"), aText);
             bFirstHeader = false;
         }
         else
@@ -663,7 +663,7 @@ void DesktopLOKTest::testRowColumnHeaders()
         if (bFirstHeader)
         {
             CPPUNIT_ASSERT(nSize <= nX);
-            CPPUNIT_ASSERT_EQUAL(OString("4"), aText);
+            CPPUNIT_ASSERT_EQUAL(OString("3"), aText);
             bFirstHeader = false;
         }
         else
diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index b702c3ca2324..e51c82c14970 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -127,6 +127,7 @@ certain functionality.
 @li @c sc.core.grouparealistener - sc::FormulaGroupAreaListener
 @li @c sc.filter - Calc filter
 @li @c sc.lok.docsize
+ at li @c sc.lok.header
 @li @c sc.lok.poshelper
 @li @c sc.opencl - OpenCL-related stuff in general
 @li @c sc.opencl.source - Generated OpenCL source code
diff --git a/sc/source/ui/inc/tabview.hxx b/sc/source/ui/inc/tabview.hxx
index 76643e101be5..076f53f05d4a 100644
--- a/sc/source/ui/inc/tabview.hxx
+++ b/sc/source/ui/inc/tabview.hxx
@@ -195,6 +195,11 @@ private:
 
     double              mfPendingTabBarWidth;       // Tab bar width relative to frame window width.
 
+    SCROW               mnLOKStartHeaderRow;
+    SCROW               mnLOKEndHeaderRow;
+    SCCOL               mnLOKStartHeaderCol;
+    SCCOL               mnLOKEndHeaderCol;
+
     bool                bMinimized:1;
     bool                bInUpdateHeader:1;
     bool                bInActivatePart:1;
diff --git a/sc/source/ui/view/tabview.cxx b/sc/source/ui/view/tabview.cxx
index 6e32e84aa9ac..de98051ff3c5 100644
--- a/sc/source/ui/view/tabview.cxx
+++ b/sc/source/ui/view/tabview.cxx
@@ -227,6 +227,8 @@ ScTabView::ScTabView( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell*
     nOldCurX( 0 ),
     nOldCurY( 0 ),
     mfPendingTabBarWidth( -1.0 ),
+    mnLOKStartHeaderRow( std::numeric_limits<SCROW>::min() ),
+    mnLOKEndHeaderRow( std::numeric_limits<SCROW>::min() ),
     bMinimized( false ),
     bInUpdateHeader( false ),
     bInActivatePart( false ),
@@ -2305,6 +2307,259 @@ void ScTabView::SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const std::vector<ed
     }
 }
 
+namespace
+{
+
+inline
+long lcl_GetRowHeightPx(ScDocument* pDoc, SCROW nRow, SCTAB nTab)
+{
+    const sal_uInt16 nSize = pDoc->GetRowHeight(nRow, nTab);
+    return ScViewData::ToPixel(nSize, 1.0 / TWIPS_PER_PIXEL);
+}
+
+inline
+long lcl_GetColWidthPx(ScDocument* pDoc, SCCOL nCol, SCTAB nTab)
+{
+    const sal_uInt16 nSize = pDoc->GetColWidth(nCol, nTab);
+    return ScViewData::ToPixel(nSize, 1.0 / TWIPS_PER_PIXEL);
+}
+
+} // anonymous namespace
+
+template<typename IndexType>
+class BoundsProvider
+{
+    typedef ScPositionHelper::value_type value_type;
+    typedef IndexType index_type;
+
+    static const index_type MAX_INDEX;
+
+    ScDocument* pDoc;
+    const SCTAB nTab;
+
+    index_type nFirstIndex;
+    index_type nSecondIndex;
+    long nFirstPositionPx;
+    long nSecondPositionPx;
+
+public:
+    BoundsProvider(ScDocument* pD, SCTAB nT)
+        : pDoc(pD)
+        , nTab(nT)
+    {}
+
+    void GetStartIndexAndPosition(index_type& nIndex, long& nPosition) const
+    {
+        nIndex = nFirstIndex;
+        nPosition = nFirstPositionPx;
+    }
+
+    void GetEndIndexAndPosition(index_type& nIndex, long& nPosition) const
+    {
+        nIndex = nSecondIndex;
+        nPosition = nSecondPositionPx;
+    }
+
+    void Compute(value_type aFirstNearest, value_type aSecondNearest,
+                 long nFirstBound, long nSecondBound);
+
+    void EnlargeStartBy(long nOffset);
+
+    void EnlargeEndBy(long nOffset);
+
+    void EnlargeBy(long nOffset)
+    {
+        EnlargeStartBy(nOffset);
+        EnlargeEndBy(nOffset);
+    }
+
+private:
+    long GetSize(SCROW nIndex) const
+    {
+        return lcl_GetRowHeightPx(pDoc, nIndex, nTab);
+    }
+
+    long GetSize(SCCOL nIndex) const
+    {
+        return lcl_GetColWidthPx(pDoc, nIndex, nTab);
+    }
+
+    void GetIndexAndPos(index_type nNearestIndex, long nNearestPosition,
+                        long nBound, index_type& nFoundIndex, long& nPosition,
+                        bool bTowards, long nDiff)
+    {
+        if (nDiff > 0) // nBound < nNearestPosition
+            GeIndexBackwards(nNearestIndex, nNearestPosition, nBound,
+                             nFoundIndex, nPosition, bTowards);
+        else
+            GetIndexTowards(nNearestIndex, nNearestPosition, nBound,
+                            nFoundIndex, nPosition, bTowards);
+    }
+
+    void GeIndexBackwards(index_type nNearestIndex, long nNearestPosition,
+                          long nBound, index_type& nFoundIndex, long& nPosition,
+                          bool bTowards);
+
+    void GetIndexTowards(index_type nNearestIndex, long nNearestPosition,
+                         long nBound, index_type& nFoundIndex, long& nPosition,
+                         bool bTowards);
+};
+
+template<typename IndexType>
+const IndexType BoundsProvider<IndexType>::MAX_INDEX;
+
+template<>
+const SCROW BoundsProvider<SCROW>::MAX_INDEX = MAXTILEDROW;
+
+template<>
+const SCCOL BoundsProvider<SCCOL>::MAX_INDEX = MAXCOL;
+
+template<typename IndexType>
+void BoundsProvider<IndexType>::Compute(
+            value_type aFirstNearest, value_type aSecondNearest,
+            long nFirstBound, long nSecondBound)
+{
+    SAL_INFO("sc.lok.header", "BoundsProvider: nFirstBound: " << nFirstBound
+            << ", nSecondBound: " << nSecondBound);
+
+    long nFirstDiff = aFirstNearest.second - nFirstBound;
+    long nSecondDiff = aSecondNearest.second - nSecondBound;
+    SAL_INFO("sc.lok.header", "BoundsProvider: rTopNearest: index: " << aFirstNearest.first
+            << ", pos: " << aFirstNearest.second << ", diff: " << nFirstDiff);
+    SAL_INFO("sc.lok.header", "BoundsProvider: rBottomNearest: index: " << aSecondNearest.first
+            << ", pos: " << aSecondNearest.second << ", diff: " << nSecondDiff);
+
+    bool bReverse = !(std::abs(nFirstDiff) < std::abs(nSecondDiff));
+
+    if(bReverse)
+    {
+        std::swap(aFirstNearest, aSecondNearest);
+        std::swap(nFirstBound, nSecondBound);
+        std::swap(nFirstDiff, nSecondDiff);
+    }
+
+    index_type nNearestIndex = aFirstNearest.first;
+    long nNearestPosition = aFirstNearest.second;
+    SAL_INFO("sc.lok.header", "BoundsProvider: nearest to first bound:  nNearestIndex: "
+            << nNearestIndex << ", nNearestPosition: " << nNearestPosition);
+
+    GetIndexAndPos(nNearestIndex, nNearestPosition, nFirstBound,
+                   nFirstIndex, nFirstPositionPx, !bReverse, nFirstDiff);
+    SAL_INFO("sc.lok.header", "BoundsProvider: nFirstIndex: " << nFirstIndex
+            << ", nFirstPositionPx: " << nFirstPositionPx);
+
+    if (std::abs(nSecondDiff) < std::abs(nSecondBound - nFirstPositionPx))
+    {
+        nNearestIndex = aSecondNearest.first;
+        nNearestPosition = aSecondNearest.second;
+    }
+    else
+    {
+        nNearestPosition = nFirstPositionPx;
+        nNearestIndex = nFirstIndex;
+        nSecondDiff = !bReverse ? -1 : 1;
+    }
+    SAL_INFO("sc.lok.header", "BoundsProvider: nearest to second bound: nNearestIndex: "
+            << nNearestIndex << ", nNearestPosition: " << nNearestPosition
+            << ", diff: " << nSecondDiff);
+
+    GetIndexAndPos(nNearestIndex, nNearestPosition, nSecondBound,
+                   nSecondIndex, nSecondPositionPx, bReverse, nSecondDiff);
+    SAL_INFO("sc.lok.header", "BoundsProvider: nSecondIndex: " << nSecondIndex
+            << ", nSecondPositionPx: " << nSecondPositionPx);
+
+    if (bReverse)
+    {
+        std::swap(nFirstIndex, nSecondIndex);
+        std::swap(nFirstPositionPx, nSecondPositionPx);
+    }
+}
+
+template<typename IndexType>
+void BoundsProvider<IndexType>::EnlargeStartBy(long nOffset)
+{
+    const index_type nNewFirstIndex =
+            std::max(static_cast<index_type>(-1),
+                     static_cast<index_type>(nFirstIndex - nOffset));
+    for (index_type nIndex = nFirstIndex; nIndex > nNewFirstIndex; --nIndex)
+    {
+        const long nSizePx = GetSize(nIndex);
+        nFirstPositionPx -= nSizePx;
+    }
+    nFirstIndex = nNewFirstIndex;
+    SAL_INFO("sc.lok.header", "BoundsProvider: added offset: nFirstIndex: " << nFirstIndex
+            << ", nFirstPositionPx: " << nFirstPositionPx);
+}
+
+template<typename IndexType>
+void BoundsProvider<IndexType>::EnlargeEndBy(long nOffset)
+{
+    const index_type nNewSecondIndex = std::min(MAX_INDEX, static_cast<index_type>(nSecondIndex + nOffset));
+    for (index_type nIndex = nSecondIndex + 1; nIndex <= nNewSecondIndex; ++nIndex)
+    {
+        const long nSizePx = GetSize(nIndex);
+        nSecondPositionPx += nSizePx;
+    }
+    nSecondIndex = nNewSecondIndex;
+    SAL_INFO("sc.lok.header", "BoundsProvider: added offset: nSecondIndex: " << nSecondIndex
+            << ", nSecondPositionPx: " << nSecondPositionPx);
+}
+
+template<typename IndexType>
+void BoundsProvider<IndexType>::GeIndexBackwards(
+            index_type nNearestIndex, long nNearestPosition,
+            long nBound, index_type& nFoundIndex, long& nPosition, bool bTowards)
+{
+    nFoundIndex = -1;
+    for (index_type nIndex = nNearestIndex; nIndex >= 0; --nIndex)
+    {
+        if (nBound > nNearestPosition)
+        {
+            nFoundIndex = nIndex; // last index whose nPosition is less than nBound
+            nPosition = nNearestPosition;
+            break;
+        }
+
+        const long nSizePx = GetSize(nIndex);
+        nNearestPosition -= nSizePx;
+    }
+    if (!bTowards && nFoundIndex != -1)
+    {
+        nFoundIndex += 1;
+        nPosition += GetSize(nFoundIndex);
+    }
+}
+
+template<typename IndexType>
+void BoundsProvider<IndexType>::GetIndexTowards(
+            index_type nNearestIndex, long nNearestPosition,
+            long nBound, index_type& nFoundIndex, long& nPosition, bool bTowards)
+{
+    nFoundIndex = -2;
+    for (index_type nIndex = nNearestIndex + 1; nIndex <= MAX_INDEX; ++nIndex)
+    {
+        const long nSizePx = GetSize(nIndex);
+        nNearestPosition += nSizePx;
+
+        if (nNearestPosition > nBound)
+        {
+            nFoundIndex = nIndex; // first index whose nPosition is greater than nBound
+            nPosition = nNearestPosition;
+            break;
+        }
+    }
+    if (nFoundIndex == -2)
+    {
+        nFoundIndex = MAX_INDEX;
+        nPosition = nNearestPosition;
+    }
+    else if (bTowards)
+    {
+        nPosition -= GetSize(nFoundIndex);
+        nFoundIndex -= 1;
+    }
+}
+
 OUString ScTabView::getRowColumnHeaders(const Rectangle& rRectangle)
 {
     ScDocument* pDoc = aViewData.GetDocument();
@@ -2317,55 +2572,51 @@ OUString ScTabView::getRowColumnHeaders(const Rectangle& rRectangle)
     rtl::OUStringBuffer aBuffer(256);
     aBuffer.append("{ \"commandName\": \".uno:ViewRowColumnHeaders\",\n");
 
-    SCROW nStartRow = 0;
-    SCROW nEndRow = 0;
-    SCCOL nStartCol = 0;
-    SCCOL nEndCol = 0;
+    SCTAB nTab = aViewData.GetTabNo();
+    SCROW nStartRow = -1;
+    SCROW nEndRow = -1;
+    long nStartHeightPx = 0;
+    long nEndHeightPx = 0;
+    SCCOL nStartCol = -1;
+    SCCOL nEndCol = -1;
+    long nStartWidthPx = 0;
+    long nEndWidthPx = 0;
+
 
     /// *** start collecting ROWS ***
 
     /// 1) compute start and end rows
 
-    long nTotalPixels = 0;
     if (rRectangle.Top() < rRectangle.Bottom())
     {
-        long nUpperBoundPx = rRectangle.Top() / TWIPS_PER_PIXEL;
-        long nLowerBoundPx = rRectangle.Bottom() / TWIPS_PER_PIXEL;
-        nEndRow = MAXTILEDROW;
-        for (SCROW nRow = 0; nRow <= MAXTILEDROW; ++nRow)
-        {
-            if (nTotalPixels > nLowerBoundPx)
-            {
-                nEndRow = nRow; // first row below the rectangle
-                break;
-            }
+        SAL_INFO("sc.lok.header", "Row Header: compute start/end rows.");
+        long nRectTopPx = rRectangle.Top() / TWIPS_PER_PIXEL;
+        long nRectBottomPx = rRectangle.Bottom() / TWIPS_PER_PIXEL;
 
-            const sal_uInt16 nSize = pDoc->GetRowHeight(nRow, aViewData.GetTabNo());
-            const long nSizePx = ScViewData::ToPixel(nSize, 1.0 / TWIPS_PER_PIXEL);
+        const auto& rTopNearest = aViewData.GetLOKHeightHelper().getNearestByPosition(nRectTopPx);
+        const auto& rBottomNearest = aViewData.GetLOKHeightHelper().getNearestByPosition(nRectBottomPx);
 
-            nTotalPixels += nSizePx;
-
-            if (nTotalPixels < nUpperBoundPx)
-            {
-                nStartRow = nRow; // last row above the rectangle
-                continue;
-            }
-        }
+        BoundsProvider<SCROW> aBoundingRowsProvider(pDoc, nTab);
+        aBoundingRowsProvider.Compute(rTopNearest, rBottomNearest, nRectTopPx, nRectBottomPx);
+        aBoundingRowsProvider.EnlargeBy(2);
+        aBoundingRowsProvider.GetStartIndexAndPosition(nStartRow, nStartHeightPx);
+        aBoundingRowsProvider.GetEndIndexAndPosition(nEndRow, nEndHeightPx);
 
-        nStartRow -= 1;
-        nEndRow += 2;
+        aViewData.GetLOKHeightHelper().removeByIndex(mnLOKStartHeaderRow);
+        aViewData.GetLOKHeightHelper().removeByIndex(mnLOKEndHeaderRow);
+        aViewData.GetLOKHeightHelper().insert(nStartRow, nStartHeightPx);
+        aViewData.GetLOKHeightHelper().insert(nEndRow, nEndHeightPx);
 
-        if (nStartRow < 0) nStartRow = 0;
-        if (nEndRow > MAXTILEDROW) nEndRow = MAXTILEDROW;
+        mnLOKStartHeaderRow = nStartRow;
+        mnLOKEndHeaderRow = nEndRow;
     }
 
-    aBuffer.ensureCapacity( aBuffer.getCapacity() + (50 * (nEndRow - nStartRow + 1)) );
-
-
     long nVisibleRows = nEndRow - nStartRow;
     if (nVisibleRows < 25)
         nVisibleRows = 25;
 
+    SAL_INFO("sc.lok.header", "Row Header: visible rows: " << nVisibleRows);
+
 
     /// 2) if we are approaching current max tiled row, signal a size changed event
     ///    and invalidate the involved area
@@ -2384,6 +2635,7 @@ OUString ScTabView::getRowColumnHeaders(const Rectangle& rRectangle)
         if (pModelObj)
             aNewSize = pModelObj->getDocumentSize();
 
+        SAL_INFO("sc.lok.header", "Row Header: a new height: " << aNewSize.Height());
         if (pDocSh)
         {
             // Provide size in the payload, so clients don't have to
@@ -2410,39 +2662,27 @@ OUString ScTabView::getRowColumnHeaders(const Rectangle& rRectangle)
 
     aBuffer.append("\"rows\": [\n");
 
-    bool bFirstRow = true;
-    if (nStartRow  == 0 && nStartRow != nEndRow)
+    long nTotalPixels = aViewData.GetLOKHeightHelper().getPosition(nStartRow);
+    SAL_INFO("sc.lok.header", "Row Header: [create string data for rows]: start row: "
+            << nStartRow << " start height: " << nTotalPixels);
+
+    if (nStartRow != nEndRow)
     {
-        aBuffer.append("{ \"text\": \"").append("0").append("\", ");
-        aBuffer.append("\"size\": \"").append(OUString::number(0)).append("\" }");
-        bFirstRow = false;
+        OUString aText = OUString::number(nStartRow + 1);
+        aBuffer.append("{ \"text\": \"").append(aText).append("\", ");
+        aBuffer.append("\"size\": \"").append(OUString::number(nTotalPixels * TWIPS_PER_PIXEL)).append("\" }");
     }
 
-    nTotalPixels = 0;
-    for (SCROW nRow = 0; nRow < nEndRow; ++nRow)
+    for (SCROW nRow = nStartRow + 1; nRow < nEndRow; ++nRow)
     {
         // nSize will be 0 for hidden rows.
-        const sal_uInt16 nSize = pDoc->GetRowHeight(nRow, aViewData.GetTabNo());
-        const long nSizePx = ScViewData::ToPixel(nSize, 1.0 / TWIPS_PER_PIXEL);
+        const long nSizePx = lcl_GetRowHeightPx(pDoc, nRow, nTab);
         nTotalPixels += nSizePx;
 
-        if (nRow < nStartRow)
-            continue;
-
         OUString aText = pRowBar[SC_SPLIT_BOTTOM]->GetEntryText(nRow);
-
-        if (!bFirstRow)
-        {
-            aBuffer.append(", ");
-        }
-        else
-        {
-            aText = OUString::number(nStartRow + 1);
-        }
-
+        aBuffer.append(", ");
         aBuffer.append("{ \"text\": \"").append(aText).append("\", ");
         aBuffer.append("\"size\": \"").append(OUString::number(nTotalPixels * TWIPS_PER_PIXEL)).append("\" }");
-        bFirstRow = false;
     }
 
     aBuffer.append("]");
@@ -2455,35 +2695,28 @@ OUString ScTabView::getRowColumnHeaders(const Rectangle& rRectangle)
 
     /// 1) compute start and end columns
 
-    nTotalPixels = 0;
     if (rRectangle.Left() < rRectangle.Right())
     {
-        long nLeftBoundPx = rRectangle.Left() / TWIPS_PER_PIXEL;
-        long nRightBoundPx = rRectangle.Right() / TWIPS_PER_PIXEL;
-        nEndCol = MAXCOL;
-        for (SCCOL nCol = 0; nCol <= MAXCOL; ++nCol)
-        {
-            if (nTotalPixels > nRightBoundPx)
-            {
-                nEndCol = nCol;
-                break;
-            }
+        SAL_INFO("sc.lok.header", "Column Header: compute start/end columns.");
+        long nRectLeftPx = rRectangle.Left() / TWIPS_PER_PIXEL;
+        long nRectRightPx = rRectangle.Right() / TWIPS_PER_PIXEL;
 
-            const sal_uInt16 nSize = pDoc->GetColWidth(nCol, aViewData.GetTabNo());
-            const long nSizePx = ScViewData::ToPixel(nSize, 1.0 / TWIPS_PER_PIXEL);
-            nTotalPixels += nSizePx;
-            if (nTotalPixels < nLeftBoundPx)
-            {
-                nStartCol = nCol;
-                continue;
-            }
-        }
+        const auto& rLeftNearest = aViewData.GetLOKWidthHelper().getNearestByPosition(nRectLeftPx);
+        const auto& rRightNearest = aViewData.GetLOKWidthHelper().getNearestByPosition(nRectRightPx);
+
+        BoundsProvider<SCCOL> aBoundingColsProvider(pDoc, nTab);
+        aBoundingColsProvider.Compute(rLeftNearest, rRightNearest, nRectLeftPx, nRectRightPx);
+        aBoundingColsProvider.EnlargeBy(2);
+        aBoundingColsProvider.GetStartIndexAndPosition(nStartCol, nStartWidthPx);
+        aBoundingColsProvider.GetEndIndexAndPosition(nEndCol, nEndWidthPx);
 
-        nStartCol -= 1;
-        nEndCol += 2;
+        aViewData.GetLOKWidthHelper().removeByIndex(mnLOKStartHeaderCol);
+        aViewData.GetLOKWidthHelper().removeByIndex(mnLOKEndHeaderCol);
+        aViewData.GetLOKWidthHelper().insert(nStartCol, nStartWidthPx);
+        aViewData.GetLOKWidthHelper().insert(nEndCol, nEndWidthPx);
 
-        if (nStartCol < 0) nStartCol = 0;
-        if (nEndCol > MAXCOL) nEndCol = MAXCOL;
+        mnLOKStartHeaderCol = nStartCol;
+        mnLOKEndHeaderCol = nEndCol;
     }
 
     aBuffer.ensureCapacity( aBuffer.getCapacity() + (50 * (nEndCol - nStartCol + 1)) );
@@ -2531,44 +2764,31 @@ OUString ScTabView::getRowColumnHeaders(const Rectangle& rRectangle)
         }
     }
 
-
     /// 3) create string data for columns
 
     aBuffer.append("\"columns\": [\n");
 
-    bool bFirstCol = true;
-    if (nStartCol  == 0 && nStartCol != nEndCol )
+    nTotalPixels = aViewData.GetLOKWidthHelper().getPosition(nStartCol);
+    SAL_INFO("sc.lok.header", "Col Header: [create string data for cols]: start col: "
+            << nStartRow << " start width: " << nTotalPixels);
+
+    if (nStartCol != nEndCol)
     {
-        aBuffer.append("{ \"text\": \"").append("0").append("\", ");
-        aBuffer.append("\"size\": \"").append(OUString::number(0)).append("\" }");
-        bFirstCol = false;
+        OUString aText = OUString::number(nStartCol + 1);
+        aBuffer.append("{ \"text\": \"").append(aText).append("\", ");
+        aBuffer.append("\"size\": \"").append(OUString::number(nTotalPixels * TWIPS_PER_PIXEL)).append("\" }");
     }
 
-    nTotalPixels = 0;
-    for (SCCOL nCol = 0; nCol < nEndCol; ++nCol)
+    for (SCCOL nCol = nStartCol + 1; nCol < nEndCol; ++nCol)
     {
         // nSize will be 0 for hidden columns.
-        const sal_uInt16 nSize = pDoc->GetColWidth(nCol, aViewData.GetTabNo());
-        const long nSizePx = ScViewData::ToPixel(nSize, 1.0 / TWIPS_PER_PIXEL);
+        const long nSizePx = lcl_GetColWidthPx(pDoc, nCol, nTab);
         nTotalPixels += nSizePx;
 
-        if (nCol < nStartCol)
-            continue;
-
         OUString aText = pColBar[SC_SPLIT_LEFT]->GetEntryText(nCol);
-
-        if (!bFirstCol)
-        {
-            aBuffer.append(", ");
-        }
-        else
-        {
-            aText = OUString::number(nStartCol + 1);
-        }
-
+        aBuffer.append(", ");
         aBuffer.append("{ \"text\": \"").append(aText).append("\", ");
         aBuffer.append("\"size\": \"").append(OUString::number(nTotalPixels * TWIPS_PER_PIXEL)).append("\" }");
-        bFirstCol = false;
     }
 
     aBuffer.append("]");
commit 4b39183c5740067cc31c006214cb24b81ee0f98c
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Wed Mar 29 13:42:35 2017 +0200

    LOK - Calc: make computation of cell cursor position faster
    
    Now the computation of the cell cursor position exploits the cached
    row/col positions in HeightHelper/WidthHelper.
    
    That makes navigating through arrow keys independent from the current
    cell cursor position: the cell cursor position is updated at the
    bottom of the document as fast as at the top even for very big
    spreadsheets.
    
    Change-Id: Id369b63e547aedf30c233f75c70d18f32e015edf

diff --git a/sc/source/ui/inc/viewdata.hxx b/sc/source/ui/inc/viewdata.hxx
index af6786b69361..06d829613c0d 100644
--- a/sc/source/ui/inc/viewdata.hxx
+++ b/sc/source/ui/inc/viewdata.hxx
@@ -177,6 +177,9 @@ private:
     SCROW           nCurY;
     SCCOL           nOldCurX;
     SCROW           nOldCurY;
+    SCCOL           nLOKOldCurX;
+    SCROW           nLOKOldCurY;
+
     ScPositionHelper aWidthHelper;
     ScPositionHelper aHeightHelper;
 
@@ -332,6 +335,8 @@ public:
     SCROW           GetCurY() const                         { return pThisTab->nCurY; }
     SCCOL           GetOldCurX() const;
     SCROW           GetOldCurY() const;
+    SCCOL           GetLOKOldCurX() const                   { return pThisTab->nLOKOldCurX; }
+    SCROW           GetLOKOldCurY() const                   { return pThisTab->nLOKOldCurY; }
     long            GetLOKDocWidthPixel() const             { return pThisTab->aWidthHelper.getPosition(pThisTab->nMaxTiledCol); }
     long            GetLOKDocHeightPixel() const            { return pThisTab->aHeightHelper.getPosition(pThisTab->nMaxTiledRow); }
 
@@ -357,6 +362,9 @@ public:
     void            SetCurY( SCROW nNewCurY )                       { pThisTab->nCurY = nNewCurY; }
     void            SetOldCursor( SCCOL nNewX, SCROW nNewY );
     void            ResetOldCursor();
+    void            SetLOKOldCurX( SCCOL nCurX )                    { pThisTab->nLOKOldCurX = nCurX; }
+    void            SetLOKOldCurY( SCROW nCurY )                    { pThisTab->nLOKOldCurY = nCurY; }
+
     void            SetHSplitMode( ScSplitMode eMode )              { pThisTab->eHSplitMode = eMode; }
     void            SetVSplitMode( ScSplitMode eMode )              { pThisTab->eVSplitMode = eMode; }
     void            SetHSplitPos( long nPos )                       { pThisTab->nHSplitPos = nPos; }
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index d2b8f97a1d21..6610d616a28b 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -5741,6 +5741,13 @@ OString ScGridWindow::getCellCursor(const Fraction& rZoomX, const Fraction& rZoo
 
     pViewData->SetZoom(defaultZoomX, defaultZoomY, true);
 
+    pViewData->GetLOKWidthHelper().removeByIndex(pViewData->GetLOKOldCurX() - 1);
+    pViewData->GetLOKWidthHelper().insert(nX - 1, aScrPos.getX());
+    pViewData->SetLOKOldCurX(nX);
+    pViewData->GetLOKHeightHelper().removeByIndex(pViewData->GetLOKOldCurY() - 1);
+    pViewData->GetLOKHeightHelper().insert(nY - 1, aScrPos.getY());
+    pViewData->SetLOKOldCurY(nY);
+
     return aRect.toString();
 }
 
diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx
index dbfd41492601..fb71e4c47c01 100644
--- a/sc/source/ui/view/viewdata.cxx
+++ b/sc/source/ui/view/viewdata.cxx
@@ -268,6 +268,8 @@ ScViewDataTable::ScViewDataTable() :
                 nCurY( 0 ),
                 nOldCurX( 0 ),
                 nOldCurY( 0 ),
+                nLOKOldCurX( 0 ),
+                nLOKOldCurY( 0 ),
                 nMaxTiledCol( 20 ),
                 nMaxTiledRow( 50 ),
                 bShowGrid( true ),
@@ -1881,6 +1883,13 @@ Point ScViewData::GetScrPos( SCCOL nWhereX, SCROW nWhereY, ScSplitPos eWhich,
     SCCOL   nX;
 
     long nScrPosX=0;
+    if (bIsTiledRendering)
+    {
+        const auto& rNearest = pThisTab->aWidthHelper.getNearestByIndex(nWhereX - 1);
+        nPosX = rNearest.first + 1;
+        nScrPosX = rNearest.second;
+    }
+
     if (nWhereX >= nPosX)
         for (nX = nPosX; nX < nWhereX && (bAllowNeg || bIsTiledRendering || nScrPosX <= aScrSize.Width()); nX++)
         {
@@ -1912,6 +1921,13 @@ Point ScViewData::GetScrPos( SCCOL nWhereX, SCROW nWhereY, ScSplitPos eWhich,
     SCROW   nY;
 
     long nScrPosY=0;
+    if (bIsTiledRendering)
+    {
+        const auto& rNearest = pThisTab->aHeightHelper.getNearestByIndex(nWhereY - 1);
+        nPosY = rNearest.first + 1;
+        nScrPosY = rNearest.second;
+    }
+
     if (nWhereY >= nPosY)
         for (nY = nPosY; nY < nWhereY && (bAllowNeg || bIsTiledRendering || nScrPosY <= aScrSize.Height()); nY++)
         {
commit 45694a63614396a98ac56deaf9f548576ae7b95e
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Wed Mar 29 13:17:43 2017 +0200

    LOK - Calc: invalidation of cached row/col positions on several cases
    
    Cached row positions are invalidated when one of the following event
    occurs:
    
    - one or more rows are inserted
    - one or more rows are deleted
    - one or more hidden rows are made visible
    - one or more visible rows are made hidden
    - one row is resized
    - optimal row height is changed
    - the value of the PPTY parameter is updated
    
    The same occurs for cached column positions.
    
    Change-Id: Idf7b8cf1e694142e4fa0e1613d19ee9272b9a1be

diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx
index 473bf6736f03..dbfd41492601 100644
--- a/sc/source/ui/view/viewdata.cxx
+++ b/sc/source/ui/view/viewdata.cxx
@@ -2502,6 +2502,8 @@ void ScViewData::UpdateScreenZoom( const Fraction& rNewX, const Fraction& rNewY
 
 void ScViewData::CalcPPT()
 {
+    double nOldPPTX = nPPTX;
+    double nOldPPTY = nPPTY;
     nPPTX = ScGlobal::nScreenPPTX * (double) GetZoomX();
     if (pDocShell)
         nPPTX = nPPTX / pDocShell->GetOutputFactor();   // Factor is printer to screen
@@ -2538,6 +2540,11 @@ void ScViewData::CalcPPT()
             }
         }
     }
+
+    if (nPPTX != nOldPPTX)
+        GetLOKWidthHelper().invalidateByPosition(0L);
+    if (nPPTY != nOldPPTY)
+        GetLOKHeightHelper().invalidateByPosition(0L);
 }
 
 #define SC_OLD_TABSEP   '/'
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index 0228541fe286..6ad62019050b 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -77,6 +77,7 @@
 #include "tokenarray.hxx"
 #include <rowheightcontext.hxx>
 #include <docfuncutil.hxx>
+#include <comphelper/lok.hxx>
 
 #include <memory>
 
@@ -1457,13 +1458,23 @@ bool ScViewFunc::InsertCells( InsCellCmd eCmd, bool bRecord, bool bPartOfPaste )
         bool bSuccess = pDocSh->GetDocFunc().InsertCells( aRange, &rMark, eCmd, bRecord, false, bPartOfPaste );
         if (bSuccess)
         {
+            bool bInsertCols = ( eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER);
+            bool bInsertRows = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER );
+            if (comphelper::LibreOfficeKit::isActive())
+            {
+                if (bInsertCols)
+                    GetViewData().GetLOKWidthHelper().invalidateByIndex(aRange.aStart.Col());
+
+                if (bInsertRows)
+                    GetViewData().GetLOKHeightHelper().invalidateByIndex(aRange.aStart.Row());
+            }
             pDocSh->UpdateOle(&GetViewData());
             CellContentChanged();
             ResetAutoSpell();
 
-            if ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_INSCOLS_AFTER )
+            if ( bInsertRows || bInsertCols )
             {
-                OUString aOperation = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER ) ?
+                OUString aOperation = bInsertRows ?
                     OUString("insert-rows"):
                     OUString("insert-columns");
                 HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, aRange, aOperation);
@@ -1514,6 +1525,15 @@ void ScViewFunc::DeleteCells( DelCellCmd eCmd )
             pDocSh->GetDocFunc().DeleteCells( aRange, &rMark, eCmd, false );
         }
 
+        if (comphelper::LibreOfficeKit::isActive())
+        {
+            if (eCmd == DEL_DELCOLS)
+                GetViewData().GetLOKWidthHelper().invalidateByIndex(aRange.aStart.Col());
+
+            if (eCmd == DEL_DELROWS)
+                GetViewData().GetLOKHeightHelper().invalidateByIndex(aRange.aStart.Row());
+        }
+
         pDocSh->UpdateOle(&GetViewData());
         CellContentChanged();
         ResetAutoSpell();
@@ -1874,6 +1894,11 @@ void ScViewFunc::SetWidthOrHeight(
     SCCOLROW nStart = rRanges.front().mnStart;
     SCCOLROW nEnd = rRanges.back().mnEnd;
 
+    if (bWidth)
+        GetViewData().GetLOKWidthHelper().invalidateByIndex(nStart);
+    else
+        GetViewData().GetLOKHeightHelper().invalidateByIndex(nStart);
+
     bool bFormula = false;
     if ( eMode == SC_SIZE_OPTIMAL )
     {
commit 5894e6bfe6ee403373b6b8775282a7b48a5e4932
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Wed Mar 29 12:55:12 2017 +0200

    LOK - Calc: document size as sum of row heights/col widths in pixel
    
    Grid lines, cursor overlay, row/col headers are all computed by
    summing up row heights / col widths converted to pixels.
    
    On the contrary the document size was converted to pixel only at the
    end after having summed up heights/widths in twips.
    
    All that lead to have a document height/width greater than the
    position of the last row/col, with the scrolling in online going
    unplesantly far beyond the last row/column.
    
    This patch change the way the document size is computed, so that the
    spreadsheet height/width matches the position of the last row/column.
    
    Moreover it exploits the cache-like structure for row/col positions
    introduced in a previous commit.
    
    Change-Id: I2e7b0e9601653856f88d1e5f9791aaec271592dc

diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index aafdf6b5d6a2..b702c3ca2324 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -126,6 +126,7 @@ certain functionality.
 @li @c sc.core.formulagroup
 @li @c sc.core.grouparealistener - sc::FormulaGroupAreaListener
 @li @c sc.filter - Calc filter
+ at li @c sc.lok.docsize
 @li @c sc.lok.poshelper
 @li @c sc.opencl - OpenCL-related stuff in general
 @li @c sc.opencl.source - Generated OpenCL source code
diff --git a/sc/source/ui/inc/viewdata.hxx b/sc/source/ui/inc/viewdata.hxx
index 33ee723fc533..af6786b69361 100644
--- a/sc/source/ui/inc/viewdata.hxx
+++ b/sc/source/ui/inc/viewdata.hxx
@@ -332,6 +332,9 @@ public:
     SCROW           GetCurY() const                         { return pThisTab->nCurY; }
     SCCOL           GetOldCurX() const;
     SCROW           GetOldCurY() const;
+    long            GetLOKDocWidthPixel() const             { return pThisTab->aWidthHelper.getPosition(pThisTab->nMaxTiledCol); }
+    long            GetLOKDocHeightPixel() const            { return pThisTab->aHeightHelper.getPosition(pThisTab->nMaxTiledRow); }
+
     ScPositionHelper& GetLOKWidthHelper()                   { return pThisTab->aWidthHelper; }
     ScPositionHelper& GetLOKHeightHelper()                  { return pThisTab->aHeightHelper; }
 
@@ -360,8 +363,8 @@ public:
     void            SetVSplitPos( long nPos )                       { pThisTab->nVSplitPos = nPos; }
     void            SetFixPosX( SCCOL nPos )                        { pThisTab->nFixPosX = nPos; }
     void            SetFixPosY( SCROW nPos )                        { pThisTab->nFixPosY = nPos; }
-    void            SetMaxTiledCol( SCCOL nCol )                    { pThisTab->nMaxTiledCol = nCol; }
-    void            SetMaxTiledRow( SCROW nRow )                    { pThisTab->nMaxTiledRow = nRow; }
+    void            SetMaxTiledCol( SCCOL nCol );
+    void            SetMaxTiledRow( SCROW nRow );
 
     void            SetPagebreakMode( bool bSet );
     void            SetPasteMode ( ScPasteFlags nFlags )            { nPasteFlags = nFlags; }
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index 4f3b627a7029..35fa76e8e669 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -544,7 +544,7 @@ Size ScModelObj::getDocumentSize()
 {
     Size aSize(10, 10); // minimum size
 
-    const ScViewData* pViewData = ScDocShell::GetViewData();
+    ScViewData* pViewData = ScDocShell::GetViewData();
     if (!pViewData)
         return aSize;
 
@@ -555,9 +555,21 @@ Size ScModelObj::getDocumentSize()
 
     rDoc.GetTiledRenderingArea(nTab, nEndCol, nEndRow);
 
-    // convert to twips
-    aSize.setWidth(rDoc.GetColWidth(0, nEndCol, nTab));
-    aSize.setHeight(rDoc.GetRowHeight(0, nEndRow, nTab));
+    pViewData->SetMaxTiledCol(nEndCol);
+    pViewData->SetMaxTiledRow(nEndRow);
+
+    if (pViewData->GetLOKDocWidthPixel() > 0 && pViewData->GetLOKDocHeightPixel() > 0)
+    {
+        // convert to twips
+        aSize.setWidth(pViewData->GetLOKDocWidthPixel() * TWIPS_PER_PIXEL);
+        aSize.setHeight(pViewData->GetLOKDocHeightPixel() * TWIPS_PER_PIXEL);
+    }
+    else
+    {
+        // convert to twips
+        aSize.setWidth(rDoc.GetColWidth(0, nEndCol, nTab));
+        aSize.setHeight(rDoc.GetRowHeight(0, nEndRow, nTab));
+    }
 
     return aSize;
 }
diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx
index 4b6c8c0ef482..473bf6736f03 100644
--- a/sc/source/ui/view/viewdata.cxx
+++ b/sc/source/ui/view/viewdata.cxx
@@ -1120,6 +1120,92 @@ void ScViewData::ResetOldCursor()
     pThisTab->mbOldCursorValid = false;
 }
 
+void ScViewData::SetMaxTiledCol( SCCOL nNewMaxCol )
+{
+    if (nNewMaxCol < 0)
+        nNewMaxCol = 0;
+    if (nNewMaxCol > MAXCOL)
+        nNewMaxCol = MAXCOL;
+
+    const SCTAB nTab = GetTabNo();
+    ScDocument* pThisDoc = pDoc;
+    auto GetColWidthPx = [pThisDoc, nTab](SCCOL nCol) {
+        const sal_uInt16 nSize = pThisDoc->GetColWidth(nCol, nTab);
+        const long nSizePx = ScViewData::ToPixel(nSize, 1.0 / TWIPS_PER_PIXEL);
+        return nSizePx;
+    };
+
+    const auto& rNearest = GetLOKWidthHelper().getNearestByIndex(nNewMaxCol);
+    SCCOL nStartCol = rNearest.first;
+    long nTotalPixels = rNearest.second;
+
+    if (nStartCol < nNewMaxCol)
+    {
+        for (SCCOL nCol = nStartCol + 1; nCol <= nNewMaxCol; ++nCol)
+        {
+            nTotalPixels += GetColWidthPx(nCol);
+        }
+    }
+    else
+    {
+        for (SCCOL nCol = nStartCol; nCol > nNewMaxCol; --nCol)
+        {
+            nTotalPixels -= GetColWidthPx(nCol);
+        }
+    }
+
+    SAL_INFO("sc.lok.docsize", "ScViewData::SetMaxTiledCol: nNewMaxCol: "
+            << nNewMaxCol << ", nTotalPixels: " << nTotalPixels);
+
+    GetLOKWidthHelper().removeByIndex(pThisTab->nMaxTiledCol);
+    GetLOKWidthHelper().insert(nNewMaxCol, nTotalPixels);
+
+    pThisTab->nMaxTiledCol = nNewMaxCol;
+}
+
+void ScViewData::SetMaxTiledRow( SCROW nNewMaxRow )
+{
+    if (nNewMaxRow < 0)
+        nNewMaxRow = 0;
+    if (nNewMaxRow > MAXTILEDROW)
+        nNewMaxRow = MAXTILEDROW;
+
+    const SCTAB nTab = GetTabNo();
+    ScDocument* pThisDoc = pDoc;
+    auto GetRowHeightPx = [pThisDoc, nTab](SCROW nRow) {
+        const sal_uInt16 nSize = pThisDoc->GetRowHeight(nRow, nTab);
+        const long nSizePx = ScViewData::ToPixel(nSize, 1.0 / TWIPS_PER_PIXEL);
+        return nSizePx;
+    };
+
+    const auto& rNearest = GetLOKHeightHelper().getNearestByIndex(nNewMaxRow);
+    SCROW nStartRow = rNearest.first;
+    long nTotalPixels = rNearest.second;
+
+    if (nStartRow < nNewMaxRow)
+    {
+        for (SCROW nRow = nStartRow + 1; nRow <= nNewMaxRow; ++nRow)
+        {
+            nTotalPixels += GetRowHeightPx(nRow);
+        }
+    }
+    else
+    {
+        for (SCROW nRow = nStartRow; nRow > nNewMaxRow; --nRow)
+        {
+            nTotalPixels -= GetRowHeightPx(nRow);
+        }
+    }
+
+    SAL_INFO("sc.lok.docsize", "ScViewData::SetMaxTiledRow: nNewMaxRow: "
+            << nNewMaxRow << ", nTotalPixels: " << nTotalPixels);
+
+    GetLOKHeightHelper().removeByIndex(pThisTab->nMaxTiledRow);
+    GetLOKHeightHelper().insert(nNewMaxRow, nTotalPixels);
+
+    pThisTab->nMaxTiledRow = nNewMaxRow;
+}
+
 Rectangle ScViewData::GetEditArea( ScSplitPos eWhich, SCCOL nPosX, SCROW nPosY,
                                     vcl::Window* pWin, const ScPatternAttr* pPattern,
                                     bool bForceToTop )
commit 2488f695197fe987951cd6f4f1552ab7c5f22897
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
Date:   Thu Feb 23 19:20:05 2017 +0100

    LOK - Calc: a cache-like structure for row/col positions in the document
    
    ScPositionHelper provides the ability to insert (and remove) row-
    position pairs where the position is in pixel and related to the
    spreadsheet top.
    
    In this way one can compute a new row position by starting from the
    nearest row presents in this cache-like structure.
    
    It offers also the ability to invalidate the cache by removing all
    cached data below a given row or position.
    
    This data structure can be used for columns, too.
    
    Change-Id: I89c62b81fe9ae685ee84c33a128893c960ebd27e

diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index c5cdc3c188db..aafdf6b5d6a2 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -126,6 +126,7 @@ certain functionality.
 @li @c sc.core.formulagroup
 @li @c sc.core.grouparealistener - sc::FormulaGroupAreaListener
 @li @c sc.filter - Calc filter
+ at li @c sc.lok.poshelper
 @li @c sc.opencl - OpenCL-related stuff in general
 @li @c sc.opencl.source - Generated OpenCL source code
 @li @c sc.orcus
diff --git a/sc/source/ui/inc/viewdata.hxx b/sc/source/ui/inc/viewdata.hxx
index 42b0cbebfe0a..33ee723fc533 100644
--- a/sc/source/ui/inc/viewdata.hxx
+++ b/sc/source/ui/inc/viewdata.hxx
@@ -115,6 +115,38 @@ class ScViewData;
 class ScMarkData;
 class ScGridWindow;
 
+class ScPositionHelper
+{
+public:
+    typedef SCCOLROW index_type;
+    typedef std::pair<index_type, long> value_type;
+    static_assert(std::numeric_limits<index_type>::is_signed, "ScPositionCache: index type is not signed");
+
+private:
+    static const index_type null = std::numeric_limits<index_type>::min();
+
+    class Comp
+    {
+    public:
+        bool operator() (const value_type& rValue1, const value_type& rValue2) const;
+    };
+
+    std::set<value_type, Comp> mData;
+
+public:
+    ScPositionHelper();
+
+    void insert(index_type nIndex, long nPos);
+    void removeByIndex(index_type nIndex);
+    void removeByPosition(long nPos);
+    void invalidateByIndex(index_type nIndex);
+    void invalidateByPosition(long nPos);
+    const value_type& getNearestByIndex(index_type nIndex) const;
+    const value_type& getNearestByPosition(long nPos) const;
+    long getPosition(index_type nIndex) const;
+    index_type getIndex(long nPos) const;
+};
+
 class ScViewDataTable                           // per-sheet data
 {
 friend class ScViewData;
@@ -145,6 +177,9 @@ private:
     SCROW           nCurY;
     SCCOL           nOldCurX;
     SCROW           nOldCurY;
+    ScPositionHelper aWidthHelper;
+    ScPositionHelper aHeightHelper;
+
     SCCOL           nPosX[2];                   ///< X position of the top left cell of the visible area.
     SCROW           nPosY[2];                   ///< Y position of the top left cell of the visible area.
     SCCOL           nMaxTiledCol;
@@ -297,6 +332,9 @@ public:
     SCROW           GetCurY() const                         { return pThisTab->nCurY; }
     SCCOL           GetOldCurX() const;
     SCROW           GetOldCurY() const;
+    ScPositionHelper& GetLOKWidthHelper()                   { return pThisTab->aWidthHelper; }
+    ScPositionHelper& GetLOKHeightHelper()                  { return pThisTab->aHeightHelper; }
+
     ScSplitMode     GetHSplitMode() const                   { return pThisTab->eHSplitMode; }
     ScSplitMode     GetVSplitMode() const                   { return pThisTab->eVSplitMode; }
     long            GetHSplitPos() const                    { return pThisTab->nHSplitPos; }
diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx
index c6111917c6ec..4b6c8c0ef482 100644
--- a/sc/source/ui/view/viewdata.cxx
+++ b/sc/source/ui/view/viewdata.cxx
@@ -91,6 +91,166 @@ void lcl_LOKRemoveWindow(ScTabViewShell* pTabViewShell, ScSplitPos eWhich)
 
 } // anonymous namespace
 
+const ScPositionHelper::index_type ScPositionHelper::null; // definition
+
+bool ScPositionHelper::Comp::operator() (const value_type& rValue1, const value_type& rValue2) const
+{
+    if (rValue1.first == null || rValue2.first == null)
+    {
+        return rValue1.second < rValue2.second;
+    }
+    else
+    {
+        return rValue1.first < rValue2.first;
+    }
+}
+
+ScPositionHelper::ScPositionHelper()
+{
+    mData.insert(std::make_pair(-1, 0));
+}
+
+void ScPositionHelper::insert(index_type nIndex, long nPos)
+{
+    if (nIndex < 0) return;
+    SAL_INFO("sc.lok.poshelper", "ScPositionHelper::insert: nIndex: "
+            << nIndex << ", nPos: " << nPos << ", size: " << mData.size());
+    value_type aValue = std::make_pair(nIndex, nPos);
+    mData.erase(aValue);
+    mData.insert(aValue);
+    SAL_INFO("sc.lok.poshelper",
+            "ScPositionHelper::insert: after insert: size: " << mData.size());
+}
+
+void ScPositionHelper::removeByIndex(index_type nIndex)
+{
+    if (nIndex < 0)
+        return;
+    SAL_INFO("sc.lok.poshelper", "ScPositionHelper::remove: nIndex: " << nIndex
+            << ", size: " << mData.size());
+    auto it = mData.find(std::make_pair(nIndex, 0));
+    if (it == mData.end()) return;
+    mData.erase(it);
+    SAL_INFO("sc.lok.poshelper",
+            "ScPositionHelper::remove: after erase: size: " << mData.size());
+}
+
+void ScPositionHelper::removeByPosition(long nPos)
+{
+    SAL_INFO("sc.lok.poshelper", "ScPositionHelper::remove: nPos: " << nPos
+            << ", size: " << mData.size());
+    auto it = mData.find(std::make_pair(null, nPos));
+    if (it == mData.end() || it->first <= 0)
+        return;
+    mData.erase(it);
+    SAL_INFO("sc.lok.poshelper",
+            "ScPositionHelper::remove: after erase: size: " << mData.size());
+}
+
+void ScPositionHelper::invalidateByIndex(index_type nIndex)
+{
+    SAL_INFO("sc.lok.poshelper", "ScPositionHelper::invalidate: nIndex: " << nIndex);
+    if (nIndex < 0)
+    {
+        mData.clear();
+        mData.insert(std::make_pair(-1, 0));
+    }
+    else
+    {
+        auto it = mData.lower_bound(std::make_pair(nIndex, 0));
+        mData.erase(it, mData.end());
+    }
+}
+
+void ScPositionHelper::invalidateByPosition(long nPos)
+{
+    SAL_INFO("sc.lok.poshelper", "ScPositionHelper::invalidate: nPos: " << nPos);
+    if (nPos <= 0)
+    {
+        mData.clear();
+        mData.insert(std::make_pair(-1, 0));
+    }
+    else
+    {
+        auto it = mData.lower_bound(std::make_pair(null, nPos));
+        mData.erase(it, mData.end());
+    }
+}
+
+const ScPositionHelper::value_type&
+ScPositionHelper::getNearestByIndex(index_type nIndex) const
+{
+    SAL_INFO("sc.lok.poshelper",
+            "ScPositionHelper::getNearest: nIndex: " << nIndex << ", size: " << mData.size());
+    auto posUB = mData.upper_bound(std::make_pair(nIndex, 0));
+    if (posUB == mData.begin())
+    {
+        return *posUB;
+    }
+
+    auto posLB = std::prev(posUB);
+    if (posUB == mData.end())
+    {
+        return *posLB;
+    }
+
+    long nDiffUB = posUB->first - nIndex;
+    long nDiffLB = posLB->first - nIndex;
+    if (nDiffUB < -nDiffLB)
+    {
+        return *posUB;
+    }
+    else
+    {
+        return *posLB;
+    }
+}
+
+const ScPositionHelper::value_type&
+ScPositionHelper::getNearestByPosition(long nPos) const
+{
+    SAL_INFO("sc.lok.poshelper",
+            "ScPositionHelper::getNearest: nPos: " << nPos << ", size: " << mData.size());
+    auto posUB = mData.upper_bound(std::make_pair(null, nPos));
+
+    if (posUB == mData.begin())
+    {
+        return *posUB;
+    }
+
+    auto posLB = std::prev(posUB);
+    if (posUB == mData.end())
+    {
+        return *posLB;
+    }
+
+    long nDiffUB = posUB->second - nPos;
+    long nDiffLB = posLB->second - nPos;
+
+    if (nDiffUB < -nDiffLB)
+    {
+        return *posUB;
+    }
+    else
+    {
+        return *posLB;
+    }
+}
+
+long ScPositionHelper::getPosition(index_type nIndex) const
+{
+    auto it = mData.find(std::make_pair(nIndex, 0));
+    if (it == mData.end()) return -1;
+    return it->second;
+}
+
+ScPositionHelper::index_type ScPositionHelper::getIndex(long nPos) const
+{
+    auto it = mData.find(std::make_pair(null, nPos));
+    if (it == mData.end()) return null;
+    return it->first;
+}
+
 ScViewDataTable::ScViewDataTable() :
                 eZoomType( SvxZoomType::PERCENT ),
                 aZoomX( 1,1 ),


More information about the Libreoffice-commits mailing list