[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