[ooo-build-commit] Branch 'ooo-build-3-1-1' - patches/dev300

Kohei Yoshida kohei at kemper.freedesktop.org
Mon Nov 23 12:27:26 PST 2009


 patches/dev300/apply                                   |    4 
 patches/dev300/calc-perf-speedup-pagebreak-update.diff | 1322 +++++++++++++++++
 2 files changed, 1326 insertions(+)

New commits:
commit 085e933003c9f9f77336c46c214ba62d5adf5da4
Author: Kohei Yoshida <kyoshida at novell.com>
Date:   Mon Nov 23 15:21:34 2009 -0500

    Speed up page break update to improve printing performance.
    
    This patch is not enabled in the default build.
    
    * patches/dev300/apply:
    * patches/dev300/calc-perf-speedup-pagebreak-update.diff: refactored
      row height storage to use flat_segment_tree, and make use of it
      during page break update.  A document that used to take 7 minutes to
      print (99 page document) now only takes ~30 seconds. (n#554955)

diff --git a/patches/dev300/apply b/patches/dev300/apply
index 0b0ec0b..43ec6ef 100644
--- a/patches/dev300/apply
+++ b/patches/dev300/apply
@@ -3293,6 +3293,10 @@ calc-perf-copy-table-flags.diff, n#514156, kohei
 # less than 1000.
 calc-perf-rowheight-no-progress-bar.diff, n#514156, kohei
 
+# Refactor row height storage to speed up page break updates.
+calc-perf-speedup-pagebreak-update.diff, n#554955, kohei
+
+
 [ OOXMLExport ]
 oox-calc-export-row-limit.diff, n#504623, janneke.
 
diff --git a/patches/dev300/calc-perf-speedup-pagebreak-update.diff b/patches/dev300/calc-perf-speedup-pagebreak-update.diff
new file mode 100644
index 0000000..6cb1cae
--- /dev/null
+++ b/patches/dev300/calc-perf-speedup-pagebreak-update.diff
@@ -0,0 +1,1322 @@
+diff --git sc/inc/document.hxx sc/inc/document.hxx
+index 8d28d82..26d19a9 100644
+--- sc/inc/document.hxx
++++ sc/inc/document.hxx
+@@ -1237,7 +1237,6 @@ public:
+     SC_DLLPUBLIC USHORT			GetRowHeight( SCROW nRow, SCTAB nTab ) const;
+     SC_DLLPUBLIC ULONG			GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const;
+     ULONG			GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, double fScale ) const;
+-    SC_DLLPUBLIC const ScSummableCompressedArray< SCROW, USHORT> & GetRowHeightArray( SCTAB nTab ) const;
+     SC_DLLPUBLIC ULONG			GetColOffset( SCCOL nCol, SCTAB nTab ) const;
+     SC_DLLPUBLIC ULONG			GetRowOffset( SCROW nRow, SCTAB nTab ) const;
+ 
+@@ -1257,9 +1256,6 @@ public:
+                         SCTAB nTab, double fScale ) const;
+     SC_DLLPUBLIC inline USHORT	FastGetRowHeight( SCROW nRow, SCTAB nTab ) const;
+     inline SCROW	FastGetRowForHeight( SCTAB nTab, ULONG nHeight ) const;
+-                    /** No check for flags whether row is hidden, height value
+-                        is returned unconditionally. */
+-    inline USHORT   FastGetOriginalRowHeight( SCROW nRow, SCTAB nTab ) const;
+ 
+     SCROW			GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const;
+ 
+@@ -1848,11 +1844,6 @@ inline SCROW ScDocument::FastGetRowForHeight( SCTAB nTab, ULONG nHeight ) const
+ {
+     return pTab[nTab]->GetRowForHeight(nHeight);
+ }
+-
+-inline USHORT ScDocument::FastGetOriginalRowHeight( SCROW nRow, SCTAB nTab ) const
+-{
+-    return pTab[nTab]->pRowHeight->GetValue(nRow);
+-}
+  
+ #endif
+ 
+diff --git sc/inc/mdds/flatsegmenttree.hxx sc/inc/mdds/flatsegmenttree.hxx
+index 40a912a..23dfc04 100644
+--- sc/inc/mdds/flatsegmenttree.hxx
++++ sc/inc/mdds/flatsegmenttree.hxx
+@@ -160,7 +160,7 @@ private:
+             return *this;
+         }
+ 
+-        void operator++()
++        const ::std::pair<key_type, value_type>* operator++()
+         {
+             assert(m_pos);
+             if (m_forward)
+@@ -177,15 +177,19 @@ private:
+                 else
+                     m_pos = get_node(m_pos->left);
+             }
++
++            return operator->();
+         }
+ 
+-        void operator--()
++        const ::std::pair<key_type, value_type>* operator--()
+         {
+             assert(m_pos);
+             if (m_end_pos)
+                 m_end_pos = false;
+             else
+                 m_pos = m_forward ? get_node(m_pos->left) : get_node(m_pos->right);
++
++            return operator->();
+         }
+ 
+         bool operator==(const const_iterator_base& r) const
+@@ -231,7 +235,7 @@ public:
+             const_iterator_base(NULL, false, true) {}
+ 
+     private:
+-        explicit const_iterator(typename const_iterator_base::fst_type* _db, bool _end) : 
++        explicit const_iterator(const typename const_iterator_base::fst_type* _db, bool _end) : 
+             const_iterator_base(_db, _end, true) {}
+     };
+ 
+@@ -242,26 +246,26 @@ public:
+         const_reverse_iterator() :
+             const_iterator_base(NULL, false, false) {}
+     private:
+-        explicit const_reverse_iterator(typename const_iterator_base::fst_type* _db, bool _end) : 
++        explicit const_reverse_iterator(const typename const_iterator_base::fst_type* _db, bool _end) : 
+             const_iterator_base(_db, _end, false) {}
+     };
+ 
+-    const_iterator begin()
++    const_iterator begin() const
+     {
+         return const_iterator(this, false);
+     }
+ 
+-    const_iterator end()
++    const_iterator end() const
+     {
+         return const_iterator(this, true);
+     }
+ 
+-    const_reverse_iterator rbegin()
++    const_reverse_iterator rbegin() const
+     {
+         return const_reverse_iterator(this, false);
+     }
+ 
+-    const_reverse_iterator rend()
++    const_reverse_iterator rend() const
+     {
+         return const_reverse_iterator(this, true);
+     }
+diff --git sc/inc/segmenttree.hxx sc/inc/segmenttree.hxx
+index 64ba898..9b9d753 100644
+--- sc/inc/segmenttree.hxx
++++ sc/inc/segmenttree.hxx
+@@ -53,6 +53,7 @@ public:
+         explicit ForwardIterator(ScFlatBoolRowSegments& rSegs);
+ 
+         bool getValue(SCROW nPos, bool& rVal);
++        SCROW getLastPos() const;
+ 
+     private:
+         ScFlatBoolRowSegments&  mrSegs;
+@@ -101,5 +102,50 @@ private:
+     ::std::auto_ptr<ScFlatBoolSegmentsImpl> mpImpl;
+ };
+ 
++// ============================================================================
++
++class ScFlatUInt16SegmentsImpl;
++
++class ScFlatUInt16RowSegments
++{
++public:
++    struct RangeData
++    {
++        SCROW       mnRow1;
++        SCROW       mnRow2;
++        sal_uInt16  mnValue;
++    };
++
++    class ForwardIterator
++    {
++    public:
++        explicit ForwardIterator(ScFlatUInt16RowSegments& rSegs);
++
++        bool getValue(SCROW nPos, sal_uInt16& rVal);
++        SCROW getLastPos() const;
++
++    private:
++        ScFlatUInt16RowSegments&  mrSegs;
++
++        SCROW       mnCurPos;
++        SCROW       mnLastPos;
++        sal_uInt16  mnCurValue;
++    };
++
++    ScFlatUInt16RowSegments(sal_uInt16 nDefault);
++    ~ScFlatUInt16RowSegments();
++
++    void setValue(SCROW nRow1, SCROW nRow2, sal_uInt16 nValue);
++    sal_uInt16 getValue(SCROW nRow);
++    sal_uInt32 getSumValue(SCROW nRow1, SCROW nRow2);
++    bool getRangeData(SCROW nRow, RangeData& rData);
++    void removeSegment(SCROW nRow1, SCROW nRow2);
++    void insertSegment(SCROW nRow, SCROW nSize, bool bSkipStartBoundary);
++
++    SCROW findLastNotOf(sal_uInt16 nValue) const;
++
++private:
++    ::std::auto_ptr<ScFlatUInt16SegmentsImpl> mpImpl;
++};
+ 
+ #endif
+diff --git sc/inc/table.hxx sc/inc/table.hxx
+index 192ca18..db301be 100644
+--- sc/inc/table.hxx
++++ sc/inc/table.hxx
+@@ -83,6 +83,7 @@ struct RowInfo;
+ struct ScFunctionData;
+ struct ScLineFlags;
+ class CollatorWrapper;
++class ScFlatUInt16RowSegments;
+ class ScFlatBoolRowSegments;
+ class ScFlatBoolColSegments;
+ struct ScSetStringParam;
+@@ -120,7 +121,7 @@ private:
+     ::std::auto_ptr<ScTableProtection> pTabProtection;
+ 
+     USHORT*			pColWidth;
+-    ScSummableCompressedArray< SCROW, USHORT>*  pRowHeight;
++    ::boost::shared_ptr<ScFlatUInt16RowSegments> mpRowHeights;
+ 
+     BYTE*			pColFlags;
+     ScBitMaskCompressedArray< SCROW, BYTE>*     pRowFlags;
+@@ -592,7 +593,7 @@ public:
+     void		SetManualHeight( SCROW nStartRow, SCROW nEndRow, BOOL bManual );
+ 
+ 	USHORT		GetColWidth( SCCOL nCol );
+-    SC_DLLPUBLIC USHORT GetRowHeight( SCROW nRow );
++    SC_DLLPUBLIC USHORT GetRowHeight( SCROW nRow, SCROW* pStartRow = NULL, SCROW* pEndRow = NULL );
+ 	ULONG		GetRowHeight( SCROW nStartRow, SCROW nEndRow );
+ 	ULONG		GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fScale );
+ 	ULONG		GetColOffset( SCCOL nCol );
+@@ -639,8 +640,6 @@ public:
+ 
+     const ScBitMaskCompressedArray< SCROW, BYTE> * GetRowFlagsArray() const
+                     { return pRowFlags; }
+-    const ScSummableCompressedArray< SCROW, USHORT> * GetRowHeightArray() const
+-                    { return pRowHeight; }
+ 
+     BOOL		UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, BOOL bShow );
+     BOOL		UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, BOOL bShow );
+@@ -655,6 +654,19 @@ public:
+     bool        HasColPageBreak(SCCOL nCol) const;
+     bool        HasRowManualBreak(SCROW nRow) const;
+     bool        HasColManualBreak(SCCOL nCol) const;
++
++    /** 
++     * Get the row position of the next manual break that occurs at or below 
++     * specified row.  When no more manual breaks are present at or below 
++     * the specified row, -1 is returned. 
++     *  
++     * @param nRow row at which the search begins. 
++     *  
++     * @return SCROW next row position with manual page break, or -1 if no 
++     *         more manual breaks are present.
++     */
++    SCROW       GetNextManualBreak(SCROW nRow) const;
++
+     void        RemoveRowPageBreaks(SCROW nStartRow, SCROW nEndRow);
+     void        RemoveRowBreak(SCROW nRow, bool bPage, bool bManual);
+     void        RemoveColBreak(SCCOL nCol, bool bPage, bool bManual);
+@@ -672,6 +684,7 @@ public:
+     void        SetColHidden(SCCOL nStartCol, SCCOL nEndCol, bool bHidden);
+     void        CopyColHidden(ScTable& rTable, SCCOL nStartCol, SCCOL nEndCol);
+     void        CopyRowHidden(ScTable& rTable, SCROW nStartRow, SCROW nEndRow);
++    void        CopyRowHeight(ScTable& rSrcTable, SCROW nStartRow, SCROW nEndRow, SCROW nSrcOffset);
+     SCROW       FirstVisibleRow(SCROW nStartRow, SCROW nEndRow);
+     SCROW       LastVisibleRow(SCROW nStartRow, SCROW nEndRow);
+     SCROW       CountVisibleRows(SCROW nStartRow, SCROW nEndRow);
+diff --git sc/source/core/data/document.cxx sc/source/core/data/document.cxx
+index 43da81b..579c99a 100644
+--- sc/source/core/data/document.cxx
++++ sc/source/core/data/document.cxx
+@@ -3050,28 +3050,6 @@ ULONG ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
+ }
+ 
+ 
+-const ScSummableCompressedArray< SCROW, USHORT> & ScDocument::GetRowHeightArray(
+-        SCTAB nTab ) const
+-{
+-    const ScSummableCompressedArray< SCROW, USHORT> * pHeight;
+-    if ( ValidTab(nTab) && pTab[nTab] )
+-        pHeight = pTab[nTab]->GetRowHeightArray();
+-    else
+-    {
+-        DBG_ERROR("wrong sheet number");
+-        pHeight = 0;
+-    }
+-    if (!pHeight)
+-    {
+-        DBG_ERROR("no row heights at sheet");
+-        static ScSummableCompressedArray< SCROW, USHORT> aDummy( MAXROW,
+-                ScGlobal::nStdRowHeight);
+-        pHeight = &aDummy;
+-    }
+-    return *pHeight;
+-}
+-
+-
+ SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
+ {
+     if ( ValidTab(nTab) && pTab[nTab] )
+@@ -3545,7 +3523,7 @@ SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
+ 
+ SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart, bool bCareManualSize) const
+ {
+-    if ( ValidTab(nTab) && pTab[nTab] && pTab[nTab]->GetRowFlagsArray() && pTab[nTab]->GetRowHeightArray() )
++    if ( ValidTab(nTab) && pTab[nTab] && pTab[nTab]->GetRowFlagsArray() && pTab[nTab]->mpRowHeights )
+     {
+         BYTE nStartFlags = pTab[nTab]->GetRowFlags(nStart);
+         USHORT nStartHeight = pTab[nTab]->GetOriginalHeight(nStart);
+@@ -3555,7 +3533,7 @@ SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart, bool bCa
+             SCROW nFlagsEndRow;
+             SCROW nHeightEndRow;
+             BYTE nFlags = pTab[nTab]->GetRowFlagsArray()->GetValue( nRow, nIndex, nFlagsEndRow );
+-            USHORT nHeight = pTab[nTab]->GetRowHeightArray()->GetValue( nRow, nIndex, nHeightEndRow );
++            USHORT nHeight = pTab[nTab]->GetRowHeight(nRow, NULL, &nHeightEndRow);
+             if (((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
+                 ((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
+                 (bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
+diff --git sc/source/core/data/drwlayer.cxx sc/source/core/data/drwlayer.cxx
+index b83c94b..ea8373e 100644
+--- sc/source/core/data/drwlayer.cxx
++++ sc/source/core/data/drwlayer.cxx
+@@ -549,13 +549,11 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, const ScDrawObjData& rData,
+ 
+     if( rData.mbNote )
+     {
+-        /*  #i63671# while inserting/deleting cells/rows/columns: note has
+-            not been moved yet in document, get it from old position. */
+         DBG_ASSERT( rOldStart.IsValid(), "ScDrawLayer::RecalcPos - invalid position for cell note" );
+         /*  When inside an undo action, there may be pending note captions
+             where cell note is already deleted. The caption will be deleted
+             later with drawing undo. */
+-        if( ScPostIt* pNote = pDoc->GetNote( rOldStart ) )
++        if( ScPostIt* pNote = pDoc->GetNote( rData.maStart ) )
+             pNote->UpdateCaptionPos( rData.maStart );
+         return;
+     }
+diff --git sc/source/core/data/segmenttree.cxx sc/source/core/data/segmenttree.cxx
+index 0ee889b..98c5032 100644
+--- sc/source/core/data/segmenttree.cxx
++++ sc/source/core/data/segmenttree.cxx
+@@ -34,100 +34,182 @@
+ #include "segmenttree.hxx"
+ #include "mdds/flatsegmenttree.hxx"
+ 
+-#define USE_TREE_SEARCH 1
++#include <limits>
+ 
+-class ScFlatBoolSegmentsImpl
++using ::std::numeric_limits;
++
++// ============================================================================
++
++template<typename _ValueType, typename _ExtValueType = _ValueType>
++class ScFlatSegmentsImpl
+ {
+ public:
++    typedef _ValueType ValueType;
++    typedef _ExtValueType ExtValueType;
++
+     struct RangeData
+     {
+         SCCOLROW    mnPos1;
+         SCCOLROW    mnPos2;
+-        bool        mbValue;
++        ValueType   mnValue;
+     };
+-    ScFlatBoolSegmentsImpl(SCCOLROW nMax);
+-    ~ScFlatBoolSegmentsImpl();
+ 
+-    void setTrue(SCCOLROW nPos1, SCCOLROW nPos2);
+-    void setFalse(SCCOLROW nPos1, SCCOLROW nPos2);
+-    bool getValue(SCCOLROW nPos);
++    inline ScFlatSegmentsImpl(SCCOLROW nMax, ValueType nDefault);
++    ~ScFlatSegmentsImpl();
++
++    void setValue(SCCOLROW nPos1, SCCOLROW nPos2, ValueType nValue);
++    ValueType getValue(SCCOLROW nPos);
++    ExtValueType getSumValue(SCCOLROW nPos1, SCCOLROW nPos2);
+     bool getRangeData(SCCOLROW nPos, RangeData& rData);
+     void removeSegment(SCCOLROW nPos1, SCCOLROW nPos2);
+     void insertSegment(SCCOLROW nPos, SCCOLROW nSize, bool bSkipStartBoundary);
+ 
+-private:
+-    ScFlatBoolSegmentsImpl();
+-    ScFlatBoolSegmentsImpl(const ScFlatBoolSegmentsImpl&);
++    SCROW findLastNotOf(ValueType nValue) const;
+ 
+-    ::mdds::flat_segment_tree<SCCOLROW, bool> maSegments;
++private:
++    typedef ::mdds::flat_segment_tree<SCCOLROW, ValueType> fst_type;
++    fst_type maSegments;
+ };
+ 
+-ScFlatBoolSegmentsImpl::ScFlatBoolSegmentsImpl(SCCOLROW nMax) :
+-    maSegments(0, nMax+1, false)
++template<typename _ValueType, typename _ExtValueType>
++ScFlatSegmentsImpl<_ValueType, _ExtValueType>::ScFlatSegmentsImpl(SCCOLROW nMax, ValueType nDefault) :
++    maSegments(0, nMax+1, nDefault)
+ {
+ }
+ 
+-ScFlatBoolSegmentsImpl::~ScFlatBoolSegmentsImpl()
++template<typename _ValueType, typename _ExtValueType>
++ScFlatSegmentsImpl<_ValueType, _ExtValueType>::~ScFlatSegmentsImpl()
+ {
+ }
+ 
+-void ScFlatBoolSegmentsImpl::setTrue(SCCOLROW nPos1, SCCOLROW nPos2)
++template<typename _ValueType, typename _ExtValueType>
++void ScFlatSegmentsImpl<_ValueType, _ExtValueType>::setValue(SCCOLROW nPos1, SCCOLROW nPos2, ValueType nValue)
+ {
+-    maSegments.insert_segment(nPos1, nPos2+1, true);
++    maSegments.insert_segment(nPos1, nPos2+1, nValue);
+ }
+ 
+-void ScFlatBoolSegmentsImpl::setFalse(SCCOLROW nPos1, SCCOLROW nPos2)
++template<typename _ValueType, typename _ExtValueType>
++typename ScFlatSegmentsImpl<_ValueType, _ExtValueType>::ValueType ScFlatSegmentsImpl<_ValueType, _ExtValueType>::getValue(SCCOLROW nPos)
+ {
+-    maSegments.insert_segment(nPos1, nPos2+1, false);
++    ValueType nValue = 0;
++    if (!maSegments.is_tree_valid())
++        maSegments.build_tree();
++
++    maSegments.search_tree(nPos, nValue);
++    return nValue;
+ }
+ 
+-bool ScFlatBoolSegmentsImpl::getValue(SCCOLROW nPos)
++template<typename _ValueType, typename _ExtValueType>
++typename ScFlatSegmentsImpl<_ValueType, _ExtValueType>::ExtValueType 
++ScFlatSegmentsImpl<_ValueType, _ExtValueType>::getSumValue(SCCOLROW nPos1, SCCOLROW nPos2)
+ {
+-    bool bValue = false;
+-#if USE_TREE_SEARCH
+-    if (!maSegments.is_tree_valid())
+-        maSegments.build_tree();
++    RangeData aData;
++    if (!getRangeData(nPos1, aData))
++        return 0;
+ 
+-    maSegments.search_tree(nPos, bValue);
+-#else
+-    maSegments.search(nPos, bValue);
+-#endif
+-    return bValue;
++    sal_uInt32 nValue = 0;
++
++    SCROW nCurPos = nPos1;
++    SCROW nEndPos = aData.mnPos2;
++    while (nEndPos <= nPos2)
++    {
++        nValue += aData.mnValue * (nEndPos - nCurPos + 1);
++        nCurPos = nEndPos + 1;
++        if (!getRangeData(nCurPos, aData))
++            break;
++
++        nEndPos = aData.mnPos2;
++    }
++    if (nCurPos <= nPos2)
++    {
++        nEndPos = ::std::min(nEndPos, nPos2);
++        nValue += aData.mnValue * (nEndPos - nCurPos + 1);
++    }
++    return nValue;
+ }
+ 
+-bool ScFlatBoolSegmentsImpl::getRangeData(SCCOLROW nPos, RangeData& rData)
++template<typename _ValueType, typename _ExtValueType>
++bool ScFlatSegmentsImpl<_ValueType, _ExtValueType>::getRangeData(SCCOLROW nPos, RangeData& rData)
+ {
+-#if USE_TREE_SEARCH
+     if (!maSegments.is_tree_valid())
+         maSegments.build_tree();
+-#endif
+ 
+-    bool bValue;
++    ValueType nValue;
+     SCCOLROW nPos1, nPos2;
+-#if USE_TREE_SEARCH
+-    if (!maSegments.search_tree(nPos, bValue, &nPos1, &nPos2))
++    if (!maSegments.search_tree(nPos, nValue, &nPos1, &nPos2))
+         return false;
+-#else
+-    if (!maSegments.search(nPos, bValue, &nPos1, &nPos2))
+-        return false;
+-#endif
+ 
+     rData.mnPos1 = nPos1;
+     rData.mnPos2 = nPos2-1; // end point is not inclusive.
+-    rData.mbValue = bValue;
++    rData.mnValue = nValue;
+     return true;
+ }
+ 
+-void ScFlatBoolSegmentsImpl::removeSegment(SCCOLROW nPos1, SCCOLROW nPos2)
++template<typename _ValueType, typename _ExtValueType>
++void ScFlatSegmentsImpl<_ValueType, _ExtValueType>::removeSegment(SCCOLROW nPos1, SCCOLROW nPos2)
+ {
+     maSegments.shift_segment_left(nPos1, nPos2);
+ }
+ 
+-void ScFlatBoolSegmentsImpl::insertSegment(SCCOLROW nPos, SCCOLROW nSize, bool bSkipStartBoundary)
++template<typename _ValueType, typename _ExtValueType>
++void ScFlatSegmentsImpl<_ValueType, _ExtValueType>::insertSegment(SCCOLROW nPos, SCCOLROW nSize, bool bSkipStartBoundary)
+ {
+     maSegments.shift_segment_right(nPos, nSize, bSkipStartBoundary);
+ }
+ 
++template<typename _ValueType, typename _ExtValueType>
++SCCOLROW ScFlatSegmentsImpl<_ValueType, _ExtValueType>::findLastNotOf(ValueType nValue) const
++{
++    SCCOLROW nPos = numeric_limits<SCCOLROW>::max(); // position not found.
++    typename fst_type::const_reverse_iterator itr = maSegments.rbegin(), itrEnd = maSegments.rend();
++    // Note that when searching in reverse direction, we need to skip the first 
++    // node, since the right-most leaf node does not store a valid value.
++    for (++itr; itr != itrEnd; ++itr)
++    {
++        if (itr->second != nValue)
++        {
++            nPos = (--itr)->second - 1;
++            break;
++        }
++    }
++    return nPos;
++}
++
++// ============================================================================
++
++class ScFlatUInt16SegmentsImpl : public ScFlatSegmentsImpl<sal_uInt16, sal_uInt32>
++{
++public:
++    explicit ScFlatUInt16SegmentsImpl(SCCOLROW nMax, sal_uInt16 nDefault) :
++        ScFlatSegmentsImpl<sal_uInt16, sal_uInt32>(nMax, nDefault)
++    {
++    }
++};
++
++// ----------------------------------------------------------------------------
++
++class ScFlatBoolSegmentsImpl : public ScFlatSegmentsImpl<bool>
++{
++public:
++    explicit ScFlatBoolSegmentsImpl(SCCOLROW nMax) :
++        ScFlatSegmentsImpl<bool>(nMax, false)
++    {
++    }
++
++    void setTrue(SCCOLROW nPos1, SCCOLROW nPos2);
++    void setFalse(SCCOLROW nPos1, SCCOLROW nPos2);
++};
++
++void ScFlatBoolSegmentsImpl::setTrue(SCCOLROW nPos1, SCCOLROW nPos2)
++{
++    setValue(nPos1, nPos2, true);
++}
++
++void ScFlatBoolSegmentsImpl::setFalse(SCCOLROW nPos1, SCCOLROW nPos2)
++{
++    setValue(nPos1, nPos2, false);
++}
++
+ // ============================================================================
+ 
+ ScFlatBoolRowSegments::ForwardIterator::ForwardIterator(ScFlatBoolRowSegments& rSegs) :
+@@ -156,6 +238,11 @@ bool ScFlatBoolRowSegments::ForwardIterator::getValue(SCROW nPos, bool& rVal)
+     return true;
+ }
+ 
++SCROW ScFlatBoolRowSegments::ForwardIterator::getLastPos() const
++{
++    return mnLastPos;
++}
++
+ // ----------------------------------------------------------------------------
+ 
+ ScFlatBoolRowSegments::ScFlatBoolRowSegments() :
+@@ -188,7 +275,7 @@ bool ScFlatBoolRowSegments::getRangeData(SCROW nRow, RangeData& rData)
+     if (!mpImpl->getRangeData(static_cast<SCCOLROW>(nRow), aData))
+         return false;
+ 
+-    rData.mbValue = aData.mbValue;
++    rData.mbValue = aData.mnValue;
+     rData.mnRow1  = static_cast<SCROW>(aData.mnPos1);
+     rData.mnRow2  = static_cast<SCROW>(aData.mnPos2);
+     return true;
+@@ -236,7 +323,7 @@ bool ScFlatBoolColSegments::getRangeData(SCCOL nCol, RangeData& rData)
+     if (!mpImpl->getRangeData(static_cast<SCCOLROW>(nCol), aData))
+         return false;
+ 
+-    rData.mbValue = aData.mbValue;
++    rData.mbValue = aData.mnValue;
+     rData.mnCol1  = static_cast<SCCOL>(aData.mnPos1);
+     rData.mnCol2  = static_cast<SCCOL>(aData.mnPos2);
+     return true;
+@@ -251,3 +338,92 @@ void ScFlatBoolColSegments::insertSegment(SCCOL nCol, SCCOL nSize, bool bSkipSta
+ {
+     mpImpl->insertSegment(static_cast<SCCOLROW>(nCol), static_cast<SCCOLROW>(nSize), bSkipStartBoundary);
+ }
++
++// ============================================================================
++
++
++// ============================================================================
++
++ScFlatUInt16RowSegments::ForwardIterator::ForwardIterator(ScFlatUInt16RowSegments& rSegs) :
++    mrSegs(rSegs), mnCurPos(0), mnLastPos(-1), mnCurValue(0)
++{
++}
++
++bool ScFlatUInt16RowSegments::ForwardIterator::getValue(SCROW nPos, sal_uInt16& rVal)
++{
++    if (nPos >= mnCurPos)
++        // It can only go in a forward direction.
++        mnCurPos = nPos;
++
++    if (mnCurPos > mnLastPos)
++    {
++        // position not in the current segment.  Update the current value.
++        ScFlatUInt16RowSegments::RangeData aData;
++        if (!mrSegs.getRangeData(mnCurPos, aData))
++            return false;
++    
++        mnCurValue = aData.mnValue;
++        mnLastPos = aData.mnRow2;
++    }
++
++    rVal = mnCurValue;
++    return true;
++}
++
++SCROW ScFlatUInt16RowSegments::ForwardIterator::getLastPos() const
++{
++    return mnLastPos;
++}
++
++// ----------------------------------------------------------------------------
++
++ScFlatUInt16RowSegments::ScFlatUInt16RowSegments(sal_uInt16 nDefault) :
++    mpImpl(new ScFlatUInt16SegmentsImpl(static_cast<SCCOLROW>(MAXROW), nDefault))
++{
++}
++
++ScFlatUInt16RowSegments::~ScFlatUInt16RowSegments()
++{
++}
++
++void ScFlatUInt16RowSegments::setValue(SCROW nRow1, SCROW nRow2, sal_uInt16 nValue)
++{
++    mpImpl->setValue(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2), nValue);
++}
++
++sal_uInt16 ScFlatUInt16RowSegments::getValue(SCROW nRow)
++{
++    return mpImpl->getValue(static_cast<SCCOLROW>(nRow));
++}
++
++sal_uInt32 ScFlatUInt16RowSegments::getSumValue(SCROW nRow1, SCROW nRow2)
++{
++    return mpImpl->getSumValue(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
++}
++
++bool ScFlatUInt16RowSegments::getRangeData(SCROW nRow, RangeData& rData)
++{
++    ScFlatUInt16SegmentsImpl::RangeData aData;
++    if (!mpImpl->getRangeData(static_cast<SCCOLROW>(nRow), aData))
++        return false;
++
++    rData.mnRow1  = aData.mnPos1;
++    rData.mnRow2  = aData.mnPos2;
++    rData.mnValue = aData.mnValue;
++    return true;
++}
++
++void ScFlatUInt16RowSegments::removeSegment(SCROW nRow1, SCROW nRow2)
++{
++    mpImpl->removeSegment(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
++}
++
++void ScFlatUInt16RowSegments::insertSegment(SCROW nRow, SCROW nSize, bool bSkipStartBoundary)
++{
++    mpImpl->insertSegment(static_cast<SCCOLROW>(nRow), static_cast<SCCOLROW>(nSize), bSkipStartBoundary);
++}
++
++SCROW ScFlatUInt16RowSegments::findLastNotOf(sal_uInt16 nValue) const
++{
++    return static_cast<SCROW>(mpImpl->findLastNotOf(nValue));
++}
+diff --git sc/source/core/data/table1.cxx sc/source/core/data/table1.cxx
+index d46dba2..5319b1a 100644
+--- sc/source/core/data/table1.cxx
++++ sc/source/core/data/table1.cxx
+@@ -137,7 +137,7 @@ ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const String& rNewName,
+     nRepeatStartY( SCROW_REPEAT_NONE ),
+     pTabProtection( NULL ),
+     pColWidth( NULL ),
+-    pRowHeight( NULL ),
++    mpRowHeights( static_cast<ScFlatUInt16RowSegments*>(NULL) ),
+     pColFlags( NULL ),
+     pRowFlags( NULL ),
+     mpHiddenCols(new ScFlatBoolColSegments),
+@@ -178,7 +178,7 @@ ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const String& rNewName,
+ 
+     if (bRowInfo)
+     {
+-        pRowHeight = new ScSummableCompressedArray< SCROW, USHORT>( MAXROW, ScGlobal::nStdRowHeight);
++        mpRowHeights.reset(new ScFlatUInt16RowSegments(ScGlobal::nStdRowHeight));
+         pRowFlags  = new ScBitMaskCompressedArray< SCROW, BYTE>( MAXROW, 0);
+     }
+ 
+@@ -220,7 +220,6 @@ ScTable::~ScTable()
+ 
+     delete[] pColWidth;
+     delete[] pColFlags;
+-    delete pRowHeight;
+     delete pRowFlags;
+     delete pOutlineTable;
+     delete pSearchParam;
+diff --git sc/source/core/data/table2.cxx sc/source/core/data/table2.cxx
+index ce2705d..01b268e 100644
+--- sc/source/core/data/table2.cxx
++++ sc/source/core/data/table2.cxx
+@@ -64,6 +64,49 @@
+ 
+ #include <math.h>
+ 
++
++#include <stdio.h>
++#include <string>
++#include <sys/time.h>
++
++namespace {
++
++class StackPrinter
++{
++public:
++    explicit StackPrinter(const char* msg) :
++        msMsg(msg)
++    {
++        fprintf(stdout, "%s: --begin\n", msMsg.c_str());
++        mfStartTime = getTime();
++    }
++
++    ~StackPrinter()
++    {
++        double fEndTime = getTime();
++        fprintf(stdout, "%s: --end (duration: %g sec)\n", msMsg.c_str(), (fEndTime-mfStartTime));
++    }
++
++    void printTime(int line) const
++    {
++        double fEndTime = getTime();
++        fprintf(stdout, "%s: --(%d) (duration: %g sec)\n", msMsg.c_str(), line, (fEndTime-mfStartTime));
++    }
++
++private:
++    double getTime() const
++    {
++        timeval tv;
++        gettimeofday(&tv, NULL);
++        return tv.tv_sec + tv.tv_usec / 1000000.0;
++    }
++
++    ::std::string msMsg;
++    double mfStartTime;
++};
++
++}
++
+ // STATIC DATA -----------------------------------------------------------
+ 
+ 
+@@ -120,15 +163,16 @@ void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE
+     nRecalcLvl++;
+     if (nStartCol==0 && nEndCol==MAXCOL)
+     {
+-        if (pRowHeight && pRowFlags)
++        if (mpRowHeights && pRowFlags)
+         {
+-            pRowHeight->Insert( nStartRow, nSize);
++            mpRowHeights->insertSegment(nStartRow, nSize, false);
+             BYTE nNewFlags = pRowFlags->Insert( nStartRow, nSize);
+             // only copy manual size flag, clear all others
+             if (nNewFlags && (nNewFlags != CR_MANUALSIZE))
+                 pRowFlags->SetValue( nStartRow, nStartRow + nSize - 1,
+                         nNewFlags & CR_MANUALSIZE);
+         }
++
+         if (pOutlineTable)
+             pOutlineTable->InsertRow( nStartRow, nSize );
+ 
+@@ -151,11 +195,12 @@ void ScTable::DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE
+     nRecalcLvl++;
+     if (nStartCol==0 && nEndCol==MAXCOL)
+     {
+-        if (pRowHeight && pRowFlags)
+-        {
+-            pRowHeight->Remove( nStartRow, nSize);
++        if (pRowFlags)
+             pRowFlags->Remove( nStartRow, nSize);
+-        }
++
++        if (mpRowHeights)
++            mpRowHeights->removeSegment(nStartRow, nStartRow+nSize);
++
+         if (pOutlineTable)
+             if (pOutlineTable->DeleteRow( nStartRow, nSize ))
+                 if (pUndoOutline)
+@@ -372,10 +417,10 @@ void ScTable::CopyToClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+         pTable->CopyColHidden(*this, 0, nCol2);
+         pTable->CopyColFiltered(*this, 0, nCol2);
+ 
+-        if (pRowFlags && pTable->pRowFlags && pRowHeight && pTable->pRowHeight)
++        if (pRowFlags && pTable->pRowFlags && mpRowHeights && pTable->mpRowHeights)
+         {
+             pTable->pRowFlags->CopyFromAnded( *pRowFlags, 0, nRow2, CR_MANUALSIZE);
+-            pTable->pRowHeight->CopyFrom( *pRowHeight, 0, nRow2);
++            pTable->CopyRowHeight(*this, 0, nRow2, 0);
+         }
+ 
+         pTable->CopyRowHidden(*this, 0, nRow2);
+@@ -420,10 +465,10 @@ void ScTable::CopyFromClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+                 for (i=nCol1; i<=nCol2; i++)
+                     pColWidth[i] = pTable->pColWidth[i-nDx];
+ 
+-            if (nCol1==0 && nCol2==MAXCOL && pRowHeight && pTable->pRowHeight &&
++            if (nCol1==0 && nCol2==MAXCOL && mpRowHeights && pTable->mpRowHeights &&
+                                              pRowFlags && pTable->pRowFlags)
+             {
+-                pRowHeight->CopyFrom( *pTable->pRowHeight, nRow1, nRow2, -nDy);
++                CopyRowHeight(*pTable, nRow1, nRow2, -nDy);
+                 // Must copy CR_MANUALSIZE bit too, otherwise pRowHeight doesn't make sense
+                 for (SCROW j=nRow1; j<=nRow2; j++)
+                 {
+@@ -674,13 +719,13 @@ void ScTable::CopyToTable(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+                         bFlagChange = true;
+                 }
+ 
+-            if (nCol1==0 && nCol2==MAXCOL && pRowHeight && pDestTab->pRowHeight)
++            if (nCol1==0 && nCol2==MAXCOL && mpRowHeights && pDestTab->mpRowHeights)
+             {
+-                bool bChange = pDestTab->pRowHeight->SumValues(nRow1, nRow2) != pRowHeight->SumValues(nRow1, nRow2);
++                bool bChange = pDestTab->GetRowHeight(nRow1, nRow2) != GetRowHeight(nRow1, nRow2);
+                 if (bChange)
+                     bFlagChange = true;
+ 
+-                pDestTab->pRowHeight->CopyFrom( *pRowHeight, nRow1, nRow2);
++                pDestTab->CopyRowHeight(*this, nRow1, nRow2, 0);
+                 pDestTab->pRowFlags->CopyFrom(*pRowFlags, nRow1, nRow2);
+ 
+                 // Hidden flags.
+@@ -741,7 +786,7 @@ void ScTable::UndoToTable(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+     if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+     {
+         BOOL bWidth  = (nRow1==0 && nRow2==MAXROW && pColWidth && pDestTab->pColWidth);
+-        BOOL bHeight = (nCol1==0 && nCol2==MAXCOL && pRowHeight && pDestTab->pRowHeight);
++        BOOL bHeight = (nCol1==0 && nCol2==MAXCOL && mpRowHeights && pDestTab->mpRowHeights);
+ 
+         if (bWidth||bHeight)
+             nRecalcLvl++;
+@@ -761,7 +806,8 @@ void ScTable::UndoToTable(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+                 for (SCCOL i=nCol1; i<=nCol2; i++)
+                     pDestTab->pColWidth[i] = pColWidth[i];
+             if (bHeight)
+-                pDestTab->pRowHeight->CopyFrom( *pRowHeight, nRow1, nRow2);
++                pDestTab->CopyRowHeight(*this, nRow1, nRow2, 0);
++
+             if( !--nRecalcLvl )
+                 SetDrawPageSize();
+         }
+@@ -1352,7 +1398,7 @@ SCSIZE ScTable::FillMaxRot( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCO
+                         // reicht die gedrehte Zelle bis in den sichtbaren Bereich?
+ 
+                         SCCOL nTouchedCol = nCol;
+-                        long nWidth = (long) ( pRowHeight->GetValue(nRow) * nFactor );
++                        long nWidth = static_cast<long>(mpRowHeights->getValue(nRow) * nFactor);
+                         DBG_ASSERT(nWidth <= 0, "Richtung falsch");
+                         while ( nWidth < 0 && nTouchedCol > 0 )
+                         {
+@@ -1380,7 +1426,7 @@ SCSIZE ScTable::FillMaxRot( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCO
+ 
+ void ScTable::FindMaxRotCol( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCOL nX2 )
+ {
+-    if ( !pColWidth || !pRowHeight || !pColFlags || !pRowFlags )
++    if ( !pColWidth || !mpRowHeights || !pColFlags || !pRowFlags )
+     {
+         DBG_ERROR( "Spalten-/Zeileninfo fehlt" );
+         return;
+@@ -2021,7 +2067,7 @@ void ScTable::SetColWidth( SCCOL nCol, USHORT nNewWidth )
+ 
+ void ScTable::SetRowHeight( SCROW nRow, USHORT nNewHeight )
+ {
+-    if (VALIDROW(nRow) && pRowHeight)
++    if (VALIDROW(nRow) && mpRowHeights)
+     {
+         if (!nNewHeight)
+         {
+@@ -2029,14 +2075,14 @@ void ScTable::SetRowHeight( SCROW nRow, USHORT nNewHeight )
+             nNewHeight = ScGlobal::nStdRowHeight;
+         }
+ 
+-        USHORT nOldHeight = pRowHeight->GetValue(nRow);
++        sal_uInt16 nOldHeight = mpRowHeights->getValue(nRow);
+         if ( nNewHeight != nOldHeight )
+         {
+             nRecalcLvl++;
+             ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+             if (pDrawLayer)
+                 pDrawLayer->HeightChanged( nTab, nRow, ((long) nNewHeight) - (long) nOldHeight );
+-            pRowHeight->SetValue( nRow, nNewHeight);
++            mpRowHeights->setValue(nRow, nRow, nNewHeight);
+             if( !--nRecalcLvl )
+                 SetDrawPageSize();
+ 
+@@ -2049,12 +2095,45 @@ void ScTable::SetRowHeight( SCROW nRow, USHORT nNewHeight )
+     }
+ }
+ 
++namespace {
++
++/** 
++ * Check if the new pixel size is different from the old size between 
++ * specified ranges. 
++ */
++bool lcl_pixelSizeChanged(
++    ScFlatUInt16RowSegments& rRowHeights, SCROW nStartRow, SCROW nEndRow, 
++    sal_uInt16 nNewHeight, double nPPTY)
++{
++    long nNewPix = static_cast<long>(nNewHeight * nPPTY);
++
++    ScFlatUInt16RowSegments::ForwardIterator aFwdIter(rRowHeights);
++    for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
++    {
++        sal_uInt16 nHeight;
++        if (!aFwdIter.getValue(nRow, nHeight))
++            break;
++
++        if (nHeight != nNewHeight)
++        {    
++            bool bChanged = (nNewPix != static_cast<long>(nHeight * nPPTY));
++            if (bChanged)
++                return true;
++        }
++
++        // Skip ahead to the last position of the current range.
++        nRow = aFwdIter.getLastPos();
++    }
++    return false;
++}
++
++}
+ 
+ BOOL ScTable::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, USHORT nNewHeight,
+                                     double /* nPPTX */, double nPPTY )
+ {
+     BOOL bChanged = FALSE;
+-    if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && pRowHeight)
++    if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && mpRowHeights)
+     {
+         nRecalcLvl++;
+         if (!nNewHeight)
+@@ -2063,8 +2142,6 @@ BOOL ScTable::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, USHORT nNewHeig
+             nNewHeight = ScGlobal::nStdRowHeight;
+         }
+ 
+-        long nNewPix = (long) ( nNewHeight * nPPTY );
+-
+         BOOL bSingle = FALSE;
+         ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+         if (pDrawLayer)
+@@ -2073,23 +2150,34 @@ BOOL ScTable::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, USHORT nNewHeig
+ 
+         if (bSingle)
+         {
+-            size_t nIndex;
+-            SCROW nRegionEndRow;
+-            USHORT nOldHeight = pRowHeight->GetValue( nStartRow, nIndex, nRegionEndRow);
+-            if (nNewHeight == nOldHeight && nEndRow <= nRegionEndRow)
++            ScFlatUInt16RowSegments::RangeData aData;
++            mpRowHeights->getRangeData(nStartRow, aData);
++            if (nNewHeight == aData.mnValue && nEndRow <= aData.mnRow2)
+                 bSingle = FALSE;    // no difference in this range
+         }
+         if (bSingle)
+         {
+             if (nEndRow-nStartRow < 20)
+             {
+-                for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
++                if (!bChanged)
++                    bChanged = lcl_pixelSizeChanged(*mpRowHeights, nStartRow, nEndRow, nNewHeight, nPPTY);
++
++                /*  #i94028# #i94991# If drawing objects are involved, each row
++                    has to be changed for its own, because each call to
++                    ScDrawLayer::HeightChanged expects correct row heights
++                    above passed row in the document. Cannot use array iterator
++                    because array changes in every cycle. */
++                if( pDrawLayer )
+                 {
+-                    if (!bChanged)
+-                        if (pRowHeight->GetValue( nRow ))
+-                            bChanged = (nNewPix != (long) (pRowHeight->GetValue( nRow ) * nPPTY));
+-                    SetRowHeight( nRow, nNewHeight );
++                    for( SCROW nRow = nStartRow; nRow <= nEndRow ; ++nRow )
++                    {
++                        pDrawLayer->HeightChanged( nTab, nRow,
++                            ((long) nNewHeight) - ((long) mpRowHeights->getValue(nRow)));
++                        mpRowHeights->setValue(nRow, nRow, nNewHeight);
++                    }
+                 }
++                else
++                    mpRowHeights->setValue(nStartRow, nEndRow, nNewHeight);
+             }
+             else
+             {
+@@ -2104,22 +2192,19 @@ BOOL ScTable::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, USHORT nNewHeig
+         {
+             if (pDrawLayer)
+             {
+-                unsigned long nOldHeights = pRowHeight->SumValues( nStartRow, nEndRow);
++                unsigned long nOldHeights = GetRowHeight(nStartRow, nEndRow);
+                 // FIXME: should we test for overflows?
+                 long nHeightDif = (long) (unsigned long) nNewHeight *
+                     (nEndRow - nStartRow + 1) - nOldHeights;
+                 pDrawLayer->HeightChanged( nTab, nEndRow, nHeightDif );
+             }
+-            // Whether new pixel size will differ from old pixel size in any row.
+-            ScCompressedArrayIterator< SCROW, USHORT> aIter( *pRowHeight,
+-                    nStartRow, nEndRow);
+-            do
+-            {
+-                if (*aIter != nNewHeight)
+-                    bChanged = (nNewPix != (long) (*aIter * nPPTY));
+-            } while (!bChanged && aIter.NextRange());
+-            pRowHeight->SetValue( nStartRow, nEndRow, nNewHeight);
++
++            if (!bChanged)
++                bChanged = lcl_pixelSizeChanged(*mpRowHeights, nStartRow, nEndRow, nNewHeight, nPPTY);
++
++            mpRowHeights->setValue(nStartRow, nEndRow, nNewHeight);
+         }
++
+         if( !--nRecalcLvl )
+             SetDrawPageSize();
+ 
+@@ -2225,16 +2310,27 @@ USHORT ScTable::GetCommonWidth( SCCOL nEndCol )
+ }
+ 
+ 
+-USHORT ScTable::GetRowHeight( SCROW nRow )
++USHORT ScTable::GetRowHeight( SCROW nRow, SCROW* pStartRow, SCROW* pEndRow )
+ {
+     DBG_ASSERT(VALIDROW(nRow),"Falsche Zeilennummer");
+ 
+-	if (VALIDROW(nRow) && pRowHeight)
++	if (VALIDROW(nRow) && mpRowHeights)
+     {
+         if (RowHidden(nRow))
+             return 0;
+         else
+-            return pRowHeight->GetValue(nRow);
++        {
++            ScFlatUInt16RowSegments::RangeData aData;
++            if (!mpRowHeights->getRangeData(nRow, aData))
++                // TODO: What should we return in case the search fails?
++                return 0;
++
++            if (pStartRow)
++                *pStartRow = aData.mnRow1;
++            if (pEndRow)
++                *pEndRow = aData.mnRow2;
++            return aData.mnValue;
++        }
+     }
+     else
+         return (USHORT) ScGlobal::nStdRowHeight;
+@@ -2245,7 +2341,7 @@ ULONG ScTable::GetRowHeight( SCROW nStartRow, SCROW nEndRow )
+ {
+     DBG_ASSERT(VALIDROW(nStartRow) && VALIDROW(nEndRow),"Falsche Zeilennummer");
+ 
+-	if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && pRowHeight)
++	if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && mpRowHeights)
+     {
+         ULONG nHeight = 0;
+         SCROW nRow = nStartRow;
+@@ -2256,7 +2352,7 @@ ULONG ScTable::GetRowHeight( SCROW nStartRow, SCROW nEndRow )
+             {
+                 if (nLastRow > nEndRow)
+                     nLastRow = nEndRow;
+-                nHeight += pRowFlags->SumCoupledArrayForCondition(nRow, nLastRow, 0, 0, *pRowHeight);
++                nHeight += mpRowHeights->getSumValue(nRow, nLastRow);
+             }
+             nRow = nLastRow + 1;
+         }
+@@ -2271,7 +2367,7 @@ ULONG ScTable::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fScale
+ {
+     DBG_ASSERT(VALIDROW(nStartRow) && VALIDROW(nEndRow),"Falsche Zeilennummer");
+ 
+-	if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && pRowHeight)
++	if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && mpRowHeights)
+     {
+         ULONG nHeight = 0;
+         SCROW nRow = nStartRow;
+@@ -2282,8 +2378,8 @@ ULONG ScTable::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fScale
+             {
+                 if (nLastRow > nEndRow)
+                     nLastRow = nEndRow;
+-                nHeight += pRowFlags->SumScaledCoupledArrayForCondition(
+-                    nRow, nLastRow, 0, 0, *pRowHeight, fScale);
++                sal_uInt32 nThisHeight = mpRowHeights->getSumValue(nRow, nLastRow);
++                nHeight += nThisHeight * fScale;
+             }
+             nRow = nLastRow + 1;
+         }
+@@ -2298,8 +2394,8 @@ USHORT ScTable::GetOriginalHeight( SCROW nRow ) const		// non-0 even if hidden
+ {
+     DBG_ASSERT(VALIDROW(nRow),"wrong row number");
+ 
+-    if (VALIDROW(nRow) && pRowHeight)
+-        return pRowHeight->GetValue(nRow);
++    if (VALIDROW(nRow) && mpRowHeights)
++        return mpRowHeights->getValue(nRow);
+     else
+         return (USHORT) ScGlobal::nStdRowHeight;
+ }
+@@ -2369,9 +2465,11 @@ void ScTable::ShowRow(SCROW nRow, BOOL bShow)
+             if (pDrawLayer)
+             {
+                 if (bShow)
+-                    pDrawLayer->HeightChanged( nTab, nRow, (long) pRowHeight->GetValue(nRow) );
++                    pDrawLayer->HeightChanged(
++                        nTab, nRow, static_cast<long>(mpRowHeights->getValue(nRow)));
+                 else
+-                    pDrawLayer->HeightChanged( nTab, nRow, -(long) pRowHeight->GetValue(nRow) );
++                    pDrawLayer->HeightChanged(
++                        nTab, nRow, -static_cast<long>(mpRowHeights->getValue(nRow)));
+             }
+ 
+             SetRowHidden(nRow, nRow, !bShow);
+@@ -2407,9 +2505,11 @@ void ScTable::DBShowRow(SCROW nRow, BOOL bShow)
+             if (pDrawLayer)
+             {
+                 if (bShow)
+-                    pDrawLayer->HeightChanged( nTab, nRow, (long) pRowHeight->GetValue(nRow) );
++                    pDrawLayer->HeightChanged(
++                        nTab, nRow, static_cast<long>(mpRowHeights->getValue(nRow)));
+                 else
+-                    pDrawLayer->HeightChanged( nTab, nRow, -(long) pRowHeight->GetValue(nRow) );
++                    pDrawLayer->HeightChanged(
++                        nTab, nRow, -static_cast<long>(mpRowHeights->getValue(nRow)));
+             }
+         }
+ 
+@@ -2457,7 +2557,7 @@ void ScTable::DBShowRows(SCROW nRow1, SCROW nRow2, BOOL bShow)
+             ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+             if (pDrawLayer)
+             {
+-                long nHeight = (long) pRowHeight->SumValues( nStartRow, nEndRow);
++                long nHeight = static_cast<long>(mpRowHeights->getSumValue(nStartRow, nEndRow));
+                 if (bShow)
+                     pDrawLayer->HeightChanged( nTab, nStartRow, nHeight );
+                 else
+@@ -2506,7 +2606,7 @@ void ScTable::ShowRows(SCROW nRow1, SCROW nRow2, BOOL bShow)
+             ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+             if (pDrawLayer)
+             {
+-                long nHeight = (long) pRowHeight->SumValues( nStartRow, nEndRow);
++                long nHeight = static_cast<long>(mpRowHeights->getSumValue(nStartRow, nEndRow));
+                 if (bShow)
+                     pDrawLayer->HeightChanged( nTab, nStartRow, nHeight );
+                 else
+@@ -2618,7 +2718,10 @@ SCROW ScTable::GetLastChangedRow() const
+     if (!ValidRow(nLastFlags))
+         nLastFlags = 0;
+ 
+-    SCROW nLastHeight = pRowHeight->GetLastUnequalAccess( 0, ScGlobal::nStdRowHeight);
++    // Find the last row position where the height is NOT the standard row
++    // height.
++    // KOHEI: Test this to make sure it does what it's supposed to.
++    SCROW nLastHeight = mpRowHeights->findLastNotOf(ScGlobal::nStdRowHeight);
+     if (!ValidRow(nLastHeight))
+         nLastHeight = 0;
+ 
+@@ -2911,7 +3014,7 @@ void ScTable::SetDrawPageSize()
+ ULONG ScTable::GetRowOffset( SCROW nRow )
+ {
+     ULONG n = 0;
+-    if ( pRowFlags && pRowHeight )
++    if ( mpHiddenRows && mpRowHeights )
+     {
+         if (nRow == 0)
+             return 0;
+@@ -2947,7 +3050,7 @@ SCROW ScTable::GetRowForHeight(ULONG nHeight)
+             continue;
+         }
+ 
+-        sal_uInt32 nNew = pRowHeight->GetValue(nRow);
++        sal_uInt32 nNew = mpRowHeights->getValue(nRow);
+         nSum += nNew;
+         if (nSum > nHeight)
+         {
+diff --git sc/source/core/data/table5.cxx sc/source/core/data/table5.cxx
+index 4d28ff2..1892a39 100644
+--- sc/source/core/data/table5.cxx
++++ sc/source/core/data/table5.cxx
+@@ -203,15 +203,31 @@ void ScTable::UpdatePageBreaks( const ScRange* pUserArea )
+     BOOL bRepeatRow = ( nRepeatStartY != SCROW_REPEAT_NONE );
+     BOOL bRowFound = FALSE;
+     long nSizeY = 0;
+-    ScFlatBoolRowSegments::ForwardIterator aIter(*mpHiddenRows);
++    ScFlatBoolRowSegments::ForwardIterator aIterHidden(*mpHiddenRows);
++    ScFlatUInt16RowSegments::ForwardIterator aIterHeights(*mpRowHeights);
++    SCROW nNextManualBreak = GetNextManualBreak(nStartRow); // -1 => no more manual breaks
+     for (SCROW nY = nStartRow; nY <= nEndRow; ++nY)
+     {
+         BOOL bStartOfPage = FALSE;
+         bool bThisRowHidden = false;
+-        aIter.getValue(nY, bThisRowHidden);
+-        long nThisY = bThisRowHidden ? 0 : pRowHeight->GetValue(nY);
++        aIterHidden.getValue(nY, bThisRowHidden);
++        long nThisY = 0;
++        if (!bThisRowHidden)
++        {
++            sal_uInt16 nTmp;    
++            aIterHeights.getValue(nY, nTmp);
++            nThisY = static_cast<long>(nTmp);
++        }
++
++        bool bManualBreak = false;
++        if (nNextManualBreak >= 0)
++        {
++            bManualBreak = (nY == nNextManualBreak);
++            if (nY >= nNextManualBreak)
++                // Query the next menual break position.
++                nNextManualBreak = GetNextManualBreak(nY+1);
++        }
+ 
+-        bool bManualBreak = HasRowManualBreak(nY);
+ 		if ( (nSizeY+nThisY > nPageSizeY) || (bManualBreak && !bSkipBreaks) )
+         {
+             SetRowBreak(nY, true, false);
+@@ -237,6 +253,38 @@ void ScTable::UpdatePageBreaks( const ScRange* pUserArea )
+             bRowFound = TRUE;
+         }
+ 
++        if (bThisRowHidden)
++        {
++            // Hidden row range.  Skip them unless there is a manual break.
++            SCROW nLastCommon = aIterHidden.getLastPos();
++            if (nNextManualBreak >= 0)
++                nLastCommon = ::std::min(nLastCommon, nNextManualBreak-1);
++            nY = nLastCommon;
++        }
++        else
++        {
++            // Visible row range.
++
++            SCROW nLastHidden = aIterHidden.getLastPos();
++            SCROW nLastHeight = aIterHeights.getLastPos();
++            SCROW nLastCommon = ::std::min(nLastHidden, nLastHeight);
++            if (nNextManualBreak >= 0)
++                nLastCommon = ::std::min(nLastCommon, nNextManualBreak-1);
++    
++            if (nLastCommon > nY)
++            {
++                long nMaxMultiple = static_cast<long>(nLastCommon - nY);
++                long nMultiple = (nPageSizeY - nSizeY) / nThisY;
++                if (nMultiple > nMaxMultiple)
++                    nMultiple = nMaxMultiple;
++                if (nMultiple > 1)
++                {
++                    nSizeY += nThisY * (nMultiple - 1);
++                    nY += nMultiple - 1;
++                }
++            }
++        }
++
+         nSizeY += nThisY;
+     }
+ 
+@@ -325,6 +373,12 @@ bool ScTable::HasColManualBreak(SCCOL nCol) const
+     return (maColManualBreaks.count(nCol) > 0);
+ }
+ 
++SCROW ScTable::GetNextManualBreak(SCROW nRow) const
++{
++    set<SCROW>::const_iterator itr = maRowManualBreaks.lower_bound(nRow);
++    return itr == maRowManualBreaks.end() ? -1 : *itr;
++}
++
+ void ScTable::RemoveRowPageBreaks(SCROW nStartRow, SCROW nEndRow)
+ {
+     using namespace std;
+@@ -562,6 +616,25 @@ void ScTable::CopyRowHidden(ScTable& rTable, SCROW nStartRow, SCROW nEndRow)
+     }
+ }
+ 
++void ScTable::CopyRowHeight(ScTable& rSrcTable, SCROW nStartRow, SCROW nEndRow, SCROW nSrcOffset)
++{
++    SCROW nRow = nStartRow;
++    ScFlatUInt16RowSegments::RangeData aSrcData;
++    while (nRow <= nEndRow)
++    {
++        if (!rSrcTable.mpRowHeights->getRangeData(nRow + nSrcOffset, aSrcData))
++            // Something is wrong !
++            return;
++
++        SCROW nLastRow = aSrcData.mnRow2 - nSrcOffset;
++        if (nLastRow > nEndRow)
++            nLastRow = nEndRow;
++
++        mpRowHeights->setValue(nRow, nLastRow, aSrcData.mnValue);
++        nRow = nLastRow + 1;
++    }
++}
++
+ SCROW ScTable::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow)
+ {
+     SCROW nRow = nStartRow;
+@@ -644,7 +717,7 @@ sal_uInt32 ScTable::GetTotalRowHeight(SCROW nStartRow, SCROW nEndRow)
+ 
+         if (!aData.mbValue)
+             // visible row range.
+-            nHeight += pRowHeight->SumValues(nRow, aData.mnRow2);
++            nHeight += mpRowHeights->getSumValue(nRow, aData.mnRow2);
+ 
+         nRow = aData.mnRow2 + 1;
+     }
+diff --git sc/source/ui/view/prevloc.cxx sc/source/ui/view/prevloc.cxx
+index fb65955..65c7f73 100644
+--- sc/source/ui/view/prevloc.cxx
++++ sc/source/ui/view/prevloc.cxx
+@@ -692,7 +692,7 @@ void ScPreviewLocationData::GetTableInfo( const Rectangle& rVisiblePixel, ScPrev
+                 if (pDoc->RowHidden(nRow, nTab))
+                     continue;
+ 
+-                USHORT nDocH = pDoc->FastGetOriginalRowHeight( nRow, nTab );
++                USHORT nDocH = pDoc->GetOriginalHeight( nRow, nTab );
+                 long nNextY = nPosY + (long) (nDocH * nScaleY);
+ 
+                 long nPixelStart = pWindow->LogicToPixel( Size( 0, nPosY ), aCellMapMode ).Height();
+@@ -713,7 +713,7 @@ void ScPreviewLocationData::GetTableInfo( const Rectangle& rVisiblePixel, ScPrev
+                 if (pDoc->RowHidden(nRow, nTab))
+                     continue;
+ 
+-                USHORT nDocH = pDoc->FastGetOriginalRowHeight( nRow, nTab );
++                USHORT nDocH = pDoc->GetOriginalHeight( nRow, nTab );
+                 long nNextY = nPosY + (long) (nDocH * nScaleY);
+ 
+                 long nPixelStart = pWindow->LogicToPixel( Size( 0, nPosY ), aCellMapMode ).Height();


More information about the ooo-build-commit mailing list