diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2023-11-22 08:41:26 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2023-11-22 16:59:37 +0100 |
commit | d9c726beb64968e84d2150824c81dcf0a8b66ec2 (patch) | |
tree | 9fb1e8983ec450ee793ad6d2c655adf3d0d134a5 | |
parent | 9b2d6b36815cbfee8b44b87b7c0b3cb4bab61850 (diff) |
optimise framelinkarray lookup
We can use hashing to do an O(1) lookup instead of O(n)
linear scanning, this class is sometimes a bottleneck
in laying out large spreadsheets.
Change-Id: I4d27e8f339a8732535d832442a9d4a649da19e88
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159801
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
-rw-r--r-- | include/svx/framelink.hxx | 1 | ||||
-rw-r--r-- | svx/source/dialog/framelink.cxx | 17 | ||||
-rw-r--r-- | svx/source/dialog/framelinkarray.cxx | 255 |
3 files changed, 166 insertions, 107 deletions
diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx index ceb0abe5e390..5c98c3a1a3c6 100644 --- a/include/svx/framelink.hxx +++ b/include/svx/framelink.hxx @@ -163,6 +163,7 @@ public: bool operator==( const Style& rOther) const; bool operator<( const Style& rOther) const; + size_t hashCode() const; }; inline bool operator>( const Style& rL, const Style& rR ) { return rR.operator<(rL); } diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx index fbc5ee1d5533..887fc445dc0c 100644 --- a/svx/source/dialog/framelink.cxx +++ b/svx/source/dialog/framelink.cxx @@ -23,6 +23,7 @@ #include <svx/framelink.hxx> #include <editeng/borderline.hxx> +#include <o3tl/hash_combine.hxx> using namespace ::com::sun::star; @@ -193,6 +194,22 @@ bool Style::operator==( const Style& rOther) const && Type() == rOther.Type()); } +size_t Style::hashCode() const +{ + std::size_t seed = 0; + o3tl::hash_combine(seed, Prim()); + o3tl::hash_combine(seed, Dist()); + o3tl::hash_combine(seed, Secn()); + o3tl::hash_combine(seed, static_cast<sal_Int32>(GetColorPrim())); + o3tl::hash_combine(seed, static_cast<sal_Int32>(GetColorSecn())); + o3tl::hash_combine(seed, static_cast<sal_Int32>(GetColorGap())); + o3tl::hash_combine(seed, GetRefMode()); + o3tl::hash_combine(seed, UseGapColor()); + o3tl::hash_combine(seed, Type()); + return seed; +} + + namespace { /** diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index 65e8c8342dfe..3431c861fcfd 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -24,6 +24,7 @@ #include <set> #include <unordered_set> #include <algorithm> +#include <o3tl/hash_combine.hxx> #include <tools/debug.hxx> #include <tools/gen.hxx> #include <vcl/canvastools.hxx> @@ -71,6 +72,7 @@ public: explicit Cell(const Cell&) = default; bool operator==( const Cell& ) const; + size_t hashCode() const; void SetStyleLeft(const Style& rStyle) { maLeft = rStyle; } void SetStyleRight(const Style& rStyle) { maRight = rStyle; } @@ -226,11 +228,29 @@ bool Cell::operator==(const Cell& rOther) const && mnAddTop == rOther.mnAddTop && mnAddBottom == rOther.mnAddBottom && meRotMode == rOther.meRotMode - && mfOrientation == rOther.mfOrientation && mbOverlapX == rOther.mbOverlapX && mbOverlapY == rOther.mbOverlapY; } +size_t Cell::hashCode() const +{ + std::size_t seed = 0; + o3tl::hash_combine(seed, maLeft.hashCode()); + o3tl::hash_combine(seed, maRight.hashCode()); + o3tl::hash_combine(seed, maTop.hashCode()); + o3tl::hash_combine(seed, maBottom.hashCode()); + o3tl::hash_combine(seed, maTLBR.hashCode()); + o3tl::hash_combine(seed, maBLTR.hashCode()); + o3tl::hash_combine(seed, mnAddLeft); + o3tl::hash_combine(seed, mnAddRight); + o3tl::hash_combine(seed, mnAddTop); + o3tl::hash_combine(seed, mnAddBottom); + o3tl::hash_combine(seed, meRotMode); + o3tl::hash_combine(seed, mbOverlapX); + o3tl::hash_combine(seed, mbOverlapY); + return seed; +} + void Cell::MirrorSelfX() { std::swap( maLeft, maRight ); @@ -255,9 +275,29 @@ static void lclRecalcCoordVec( std::vector<sal_Int32>& rCoords, const std::vecto const Style OBJ_STYLE_NONE; const Cell OBJ_CELL_NONE; +/** use hashing to speed up finding duplicates */ +namespace +{ +struct RegisteredCellHash +{ + size_t operator()(Cell* const pCell) const + { + return pCell->hashCode(); + } +}; + +struct RegisteredCellEquals +{ + bool operator()(Cell* const pCell1, Cell* const pCell2) const + { + return *pCell1 == *pCell2; + } +}; +} + struct ArrayImpl { - std::unordered_set<Cell*> maRegisteredCells; + std::unordered_set<Cell*, RegisteredCellHash, RegisteredCellEquals> maRegisteredCells; CellVec maCells; std::vector<sal_Int32> maWidths; std::vector<sal_Int32> maHeights; @@ -281,7 +321,7 @@ struct ArrayImpl sal_Int32 GetIndex( sal_Int32 nCol, sal_Int32 nRow ) const { return nRow * mnWidth + nCol; } - const Cell* GetCell( sal_Int32 nCol, sal_Int32 nRow ) const; + const Cell& GetCell( sal_Int32 nCol, sal_Int32 nRow ) const; void PutCell( sal_Int32 nCol, sal_Int32 nRow, const Cell& ); sal_Int32 GetMergedFirstCol( sal_Int32 nCol, sal_Int32 nRow ) const; @@ -289,8 +329,8 @@ struct ArrayImpl sal_Int32 GetMergedLastCol( sal_Int32 nCol, sal_Int32 nRow ) const; sal_Int32 GetMergedLastRow( sal_Int32 nCol, sal_Int32 nRow ) const; - const Cell* GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const; - const Cell* GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const; + const Cell& GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const; + const Cell& GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const; bool IsMergedOverlappedLeft( sal_Int32 nCol, sal_Int32 nRow ) const; bool IsMergedOverlappedRight( sal_Int32 nCol, sal_Int32 nRow ) const; @@ -359,18 +399,18 @@ ArrayImpl::~ArrayImpl() Cell* ArrayImpl::createOrFind(const Cell& rCell) { - for (auto* pCell : maRegisteredCells) - if (*pCell == rCell) - return pCell; + auto it = maRegisteredCells.find(const_cast<Cell*>(&rCell)); + if (it != maRegisteredCells.end()) + return *it; Cell* pRetval(new Cell(rCell)); maRegisteredCells.insert(pRetval); return pRetval; } -const Cell* ArrayImpl::GetCell( sal_Int32 nCol, sal_Int32 nRow ) const +const Cell& ArrayImpl::GetCell( sal_Int32 nCol, sal_Int32 nRow ) const { - return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : &OBJ_CELL_NONE; + return IsValidPos( nCol, nRow ) ? *maCells[ GetIndex( nCol, nRow ) ] : OBJ_CELL_NONE; } void ArrayImpl::PutCell( sal_Int32 nCol, sal_Int32 nRow, const Cell & rCell ) @@ -382,61 +422,61 @@ void ArrayImpl::PutCell( sal_Int32 nCol, sal_Int32 nRow, const Cell & rCell ) sal_Int32 ArrayImpl::GetMergedFirstCol( sal_Int32 nCol, sal_Int32 nRow ) const { sal_Int32 nFirstCol = nCol; - while( (nFirstCol > 0) && GetCell( nFirstCol, nRow )->mbOverlapX ) --nFirstCol; + while( (nFirstCol > 0) && GetCell( nFirstCol, nRow ).mbOverlapX ) --nFirstCol; return nFirstCol; } sal_Int32 ArrayImpl::GetMergedFirstRow( sal_Int32 nCol, sal_Int32 nRow ) const { sal_Int32 nFirstRow = nRow; - while( (nFirstRow > 0) && GetCell( nCol, nFirstRow )->mbOverlapY ) --nFirstRow; + while( (nFirstRow > 0) && GetCell( nCol, nFirstRow ).mbOverlapY ) --nFirstRow; return nFirstRow; } sal_Int32 ArrayImpl::GetMergedLastCol( sal_Int32 nCol, sal_Int32 nRow ) const { sal_Int32 nLastCol = nCol + 1; - while( (nLastCol < mnWidth) && GetCell( nLastCol, nRow )->mbOverlapX ) ++nLastCol; + while( (nLastCol < mnWidth) && GetCell( nLastCol, nRow ).mbOverlapX ) ++nLastCol; return nLastCol - 1; } sal_Int32 ArrayImpl::GetMergedLastRow( sal_Int32 nCol, sal_Int32 nRow ) const { sal_Int32 nLastRow = nRow + 1; - while( (nLastRow < mnHeight) && GetCell( nCol, nLastRow )->mbOverlapY ) ++nLastRow; + while( (nLastRow < mnHeight) && GetCell( nCol, nLastRow ).mbOverlapY ) ++nLastRow; return nLastRow - 1; } -const Cell* ArrayImpl::GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const +const Cell& ArrayImpl::GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const { return GetCell( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) ); } -const Cell* ArrayImpl::GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const +const Cell& ArrayImpl::GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const { return GetCell( GetMergedLastCol( nCol, nRow ), GetMergedLastRow( nCol, nRow ) ); } bool ArrayImpl::IsMergedOverlappedLeft( sal_Int32 nCol, sal_Int32 nRow ) const { - const Cell* pCell(GetCell( nCol, nRow )); - return pCell->mbOverlapX || (pCell->mnAddLeft > 0); + const Cell& rCell = GetCell( nCol, nRow ); + return rCell.mbOverlapX || (rCell.mnAddLeft > 0); } bool ArrayImpl::IsMergedOverlappedRight( sal_Int32 nCol, sal_Int32 nRow ) const { - return GetCell( nCol + 1, nRow )->mbOverlapX || (GetCell( nCol, nRow )->mnAddRight > 0); + return GetCell( nCol + 1, nRow ).mbOverlapX || (GetCell( nCol, nRow ).mnAddRight > 0); } bool ArrayImpl::IsMergedOverlappedTop( sal_Int32 nCol, sal_Int32 nRow ) const { - const Cell* pCell(GetCell( nCol, nRow )); - return pCell->mbOverlapY || (pCell->mnAddTop > 0); + const Cell& rCell = GetCell( nCol, nRow ); + return rCell.mbOverlapY || (rCell.mnAddTop > 0); } bool ArrayImpl::IsMergedOverlappedBottom( sal_Int32 nCol, sal_Int32 nRow ) const { - return GetCell( nCol, nRow + 1 )->mbOverlapY || (GetCell( nCol, nRow )->mnAddBottom > 0); + return GetCell( nCol, nRow + 1 ).mbOverlapY || (GetCell( nCol, nRow ).mnAddBottom > 0); } bool ArrayImpl::IsColInClipRange( sal_Int32 nCol ) const @@ -547,6 +587,7 @@ MergedCellIterator& MergedCellIterator::operator++() return *this; } + #define DBG_FRAME_CHECK( cond, funcname, error ) DBG_ASSERT( cond, "svx::frame::Array::" funcname " - " error ) #define DBG_FRAME_CHECK_COL( col, funcname ) DBG_FRAME_CHECK( (col) < GetColCount(), funcname, "invalid column index" ) #define DBG_FRAME_CHECK_ROW( row, funcname ) DBG_FRAME_CHECK( (row) < GetRowCount(), funcname, "invalid row index" ) @@ -554,6 +595,13 @@ MergedCellIterator& MergedCellIterator::operator++() #define DBG_FRAME_CHECK_COL_1( col, funcname ) DBG_FRAME_CHECK( (col) <= GetColCount(), funcname, "invalid column index" ) #define DBG_FRAME_CHECK_ROW_1( row, funcname ) DBG_FRAME_CHECK( (row) <= GetRowCount(), funcname, "invalid row index" ) + +#define CELL( col, row ) mxImpl->GetCell( col, row ) +#define PUTCELL( col, row, cell ) mxImpl->PutCell( col, row, cell ) +#define ORIGCELL( col, row ) mxImpl->GetMergedOriginCell( col, row ) +#define LASTCELL( col, row ) mxImpl->GetMergedLastCell( col, row ) + + Array::Array() { Initialize( 0, 0 ); @@ -596,79 +644,72 @@ sal_Int32 Array::GetCellIndex( sal_Int32 nCol, sal_Int32 nRow, bool bRTL ) const void Array::SetCellStyleLeft( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle ) { DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleLeft" ); - const Cell* pTempCell(mxImpl->GetCell(nCol, nRow)); - if (pTempCell->GetStyleLeft() == rStyle) + Cell aTempCell(CELL(nCol, nRow)); + if (aTempCell.GetStyleLeft() == rStyle) return; - Cell aTempCell(*pTempCell); aTempCell.SetStyleLeft(rStyle); - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); } void Array::SetCellStyleRight( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle ) { DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleRight" ); - const Cell* pTempCell(mxImpl->GetCell(nCol, nRow)); - if (pTempCell->GetStyleRight() == rStyle) + Cell aTempCell(CELL(nCol, nRow)); + if (aTempCell.GetStyleRight() == rStyle) return; - Cell aTempCell(*pTempCell); aTempCell.SetStyleRight(rStyle); - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); } void Array::SetCellStyleTop( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle ) { DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTop" ); - const Cell* pTempCell(mxImpl->GetCell(nCol, nRow)); - if (pTempCell->GetStyleTop() == rStyle) + Cell aTempCell(CELL(nCol, nRow)); + if (aTempCell.GetStyleTop() == rStyle) return; - Cell aTempCell(*pTempCell); aTempCell.SetStyleTop(rStyle); - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); } void Array::SetCellStyleBottom( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle ) { DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBottom" ); - const Cell* pTempCell(mxImpl->GetCell(nCol, nRow)); - if (pTempCell->GetStyleBottom() == rStyle) + Cell aTempCell(CELL(nCol, nRow)); + if (aTempCell.GetStyleBottom() == rStyle) return; - Cell aTempCell(*pTempCell); aTempCell.SetStyleBottom(rStyle); - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); } void Array::SetCellStyleTLBR( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle ) { DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTLBR" ); - const Cell* pTempCell(mxImpl->GetCell(nCol, nRow)); - if (pTempCell->GetStyleTLBR() == rStyle) + Cell aTempCell(CELL(nCol, nRow)); + if (aTempCell.GetStyleTLBR() == rStyle) return; - Cell aTempCell(*pTempCell); aTempCell.SetStyleTLBR(rStyle); - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); } void Array::SetCellStyleBLTR( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle ) { DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBLTR" ); - const Cell* pTempCell(mxImpl->GetCell(nCol, nRow)); - if (pTempCell->GetStyleBLTR() == rStyle) + Cell aTempCell(CELL(nCol, nRow)); + if (aTempCell.GetStyleBLTR() == rStyle) return; - Cell aTempCell(*pTempCell); aTempCell.SetStyleBLTR(rStyle); - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); } void Array::SetCellStyleDiag( sal_Int32 nCol, sal_Int32 nRow, const Style& rTLBR, const Style& rBLTR ) { DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleDiag" ); - const Cell* pTempCell(mxImpl->GetCell(nCol, nRow)); - if (pTempCell->GetStyleTLBR() == rTLBR && pTempCell->GetStyleBLTR() == rBLTR) + Cell aTempCell(CELL(nCol, nRow)); + if (aTempCell.GetStyleTLBR() == rTLBR && aTempCell.GetStyleBLTR() == rBLTR) return; - Cell aTempCell(*pTempCell); aTempCell.SetStyleTLBR(rTLBR); aTempCell.SetStyleBLTR(rBLTR); - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); } void Array::SetColumnStyleLeft( sal_Int32 nCol, const Style& rStyle ) @@ -702,13 +743,12 @@ void Array::SetRowStyleBottom( sal_Int32 nRow, const Style& rStyle ) void Array::SetCellRotation(sal_Int32 nCol, sal_Int32 nRow, SvxRotateMode eRotMode, double fOrientation) { DBG_FRAME_CHECK_COLROW(nCol, nRow, "SetCellRotation"); - const Cell* pTempCell(mxImpl->GetCell(nCol, nRow)); - if (pTempCell->meRotMode == eRotMode && pTempCell->mfOrientation == fOrientation) + Cell aTempCell(CELL(nCol, nRow)); + if (aTempCell.meRotMode == eRotMode && aTempCell.mfOrientation == fOrientation) return; - Cell aTempCell(*pTempCell); aTempCell.meRotMode = eRotMode; aTempCell.mfOrientation = fOrientation; - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); if (!mxImpl->mbMayHaveCellRotation) { @@ -736,15 +776,15 @@ const Style& Array::GetCellStyleLeft( sal_Int32 nCol, sal_Int32 nRow ) const return OBJ_STYLE_NONE; // left clipping border: always own left style if( nCol == mxImpl->mnFirstClipCol ) - return mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleLeft(); + return ORIGCELL( nCol, nRow ).GetStyleLeft(); // right clipping border: always right style of left neighbor cell if( nCol == mxImpl->mnLastClipCol + 1 ) - return mxImpl->GetMergedOriginCell( nCol - 1, nRow )->GetStyleRight(); + return ORIGCELL( nCol - 1, nRow ).GetStyleRight(); // outside clipping columns: invisible if( !mxImpl->IsColInClipRange( nCol ) ) return OBJ_STYLE_NONE; // inside clipping range: maximum of own left style and right style of left neighbor cell - return std::max( mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleLeft(), mxImpl->GetMergedOriginCell( nCol - 1, nRow )->GetStyleRight() ); + return std::max( ORIGCELL( nCol, nRow ).GetStyleLeft(), ORIGCELL( nCol - 1, nRow ).GetStyleRight() ); } const Style& Array::GetCellStyleRight( sal_Int32 nCol, sal_Int32 nRow ) const @@ -754,15 +794,15 @@ const Style& Array::GetCellStyleRight( sal_Int32 nCol, sal_Int32 nRow ) const return OBJ_STYLE_NONE; // left clipping border: always left style of right neighbor cell if( nCol + 1 == mxImpl->mnFirstClipCol ) - return mxImpl->GetMergedOriginCell( nCol + 1, nRow )->GetStyleLeft(); + return ORIGCELL( nCol + 1, nRow ).GetStyleLeft(); // right clipping border: always own right style if( nCol == mxImpl->mnLastClipCol ) - return mxImpl->GetMergedLastCell( nCol, nRow )->GetStyleRight(); + return LASTCELL( nCol, nRow ).GetStyleRight(); // outside clipping columns: invisible if( !mxImpl->IsColInClipRange( nCol ) ) return OBJ_STYLE_NONE; // inside clipping range: maximum of own right style and left style of right neighbor cell - return std::max( mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleRight(), mxImpl->GetMergedOriginCell( nCol + 1, nRow )->GetStyleLeft() ); + return std::max( ORIGCELL( nCol, nRow ).GetStyleRight(), ORIGCELL( nCol + 1, nRow ).GetStyleLeft() ); } const Style& Array::GetCellStyleTop( sal_Int32 nCol, sal_Int32 nRow ) const @@ -772,15 +812,15 @@ const Style& Array::GetCellStyleTop( sal_Int32 nCol, sal_Int32 nRow ) const return OBJ_STYLE_NONE; // top clipping border: always own top style if( nRow == mxImpl->mnFirstClipRow ) - return mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleTop(); + return ORIGCELL( nCol, nRow ).GetStyleTop(); // bottom clipping border: always bottom style of top neighbor cell if( nRow == mxImpl->mnLastClipRow + 1 ) - return mxImpl->GetMergedOriginCell( nCol, nRow - 1 )->GetStyleBottom(); + return ORIGCELL( nCol, nRow - 1 ).GetStyleBottom(); // outside clipping rows: invisible if( !mxImpl->IsRowInClipRange( nRow ) ) return OBJ_STYLE_NONE; // inside clipping range: maximum of own top style and bottom style of top neighbor cell - return std::max( mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleTop(), mxImpl->GetMergedOriginCell( nCol, nRow - 1 )->GetStyleBottom() ); + return std::max( ORIGCELL( nCol, nRow ).GetStyleTop(), ORIGCELL( nCol, nRow - 1 ).GetStyleBottom() ); } const Style& Array::GetCellStyleBottom( sal_Int32 nCol, sal_Int32 nRow ) const @@ -790,25 +830,25 @@ const Style& Array::GetCellStyleBottom( sal_Int32 nCol, sal_Int32 nRow ) const return OBJ_STYLE_NONE; // top clipping border: always top style of bottom neighbor cell if( nRow + 1 == mxImpl->mnFirstClipRow ) - return mxImpl->GetMergedOriginCell( nCol, nRow + 1 )->GetStyleTop(); + return ORIGCELL( nCol, nRow + 1 ).GetStyleTop(); // bottom clipping border: always own bottom style if( nRow == mxImpl->mnLastClipRow ) - return mxImpl->GetMergedLastCell( nCol, nRow )->GetStyleBottom(); + return LASTCELL( nCol, nRow ).GetStyleBottom(); // outside clipping rows: invisible if( !mxImpl->IsRowInClipRange( nRow ) ) return OBJ_STYLE_NONE; // inside clipping range: maximum of own bottom style and top style of bottom neighbor cell - return std::max( mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleBottom(), mxImpl->GetMergedOriginCell( nCol, nRow + 1 )->GetStyleTop() ); + return std::max( ORIGCELL( nCol, nRow ).GetStyleBottom(), ORIGCELL( nCol, nRow + 1 ).GetStyleTop() ); } const Style& Array::GetCellStyleTLBR( sal_Int32 nCol, sal_Int32 nRow ) const { - return mxImpl->GetCell( nCol, nRow )->GetStyleTLBR(); + return CELL( nCol, nRow ).GetStyleTLBR(); } const Style& Array::GetCellStyleBLTR( sal_Int32 nCol, sal_Int32 nRow ) const { - return mxImpl->GetCell( nCol, nRow )->GetStyleBLTR(); + return CELL( nCol, nRow ).GetStyleBLTR(); } const Style& Array::GetCellStyleTL( sal_Int32 nCol, sal_Int32 nRow ) const @@ -820,7 +860,7 @@ const Style& Array::GetCellStyleTL( sal_Int32 nCol, sal_Int32 nRow ) const sal_Int32 nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); sal_Int32 nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); return ((nCol == nFirstCol) && (nRow == nFirstRow)) ? - mxImpl->GetCell( nFirstCol, nFirstRow )->GetStyleTLBR() : OBJ_STYLE_NONE; + CELL( nFirstCol, nFirstRow ).GetStyleTLBR() : OBJ_STYLE_NONE; } const Style& Array::GetCellStyleBR( sal_Int32 nCol, sal_Int32 nRow ) const @@ -832,7 +872,7 @@ const Style& Array::GetCellStyleBR( sal_Int32 nCol, sal_Int32 nRow ) const sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); return ((nCol == nLastCol) && (nRow == nLastRow)) ? - mxImpl->GetCell( mxImpl->GetMergedFirstCol( nCol, nRow ), mxImpl->GetMergedFirstRow( nCol, nRow ) )->GetStyleTLBR() : OBJ_STYLE_NONE; + CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), mxImpl->GetMergedFirstRow( nCol, nRow ) ).GetStyleTLBR() : OBJ_STYLE_NONE; } const Style& Array::GetCellStyleBL( sal_Int32 nCol, sal_Int32 nRow ) const @@ -844,7 +884,7 @@ const Style& Array::GetCellStyleBL( sal_Int32 nCol, sal_Int32 nRow ) const sal_Int32 nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); return ((nCol == nFirstCol) && (nRow == nLastRow)) ? - mxImpl->GetCell( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) )->GetStyleBLTR() : OBJ_STYLE_NONE; + CELL( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) ).GetStyleBLTR() : OBJ_STYLE_NONE; } const Style& Array::GetCellStyleTR( sal_Int32 nCol, sal_Int32 nRow ) const @@ -856,7 +896,7 @@ const Style& Array::GetCellStyleTR( sal_Int32 nCol, sal_Int32 nRow ) const sal_Int32 nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); return ((nCol == nLastCol) && (nRow == nFirstRow)) ? - mxImpl->GetCell( mxImpl->GetMergedFirstCol( nCol, nRow ), nFirstRow )->GetStyleBLTR() : OBJ_STYLE_NONE; + CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), nFirstRow ).GetStyleBLTR() : OBJ_STYLE_NONE; } // cell merging @@ -869,7 +909,7 @@ void Array::SetMergedRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 bool bFound = false; for( sal_Int32 nCurrCol = nFirstCol; !bFound && (nCurrCol <= nLastCol); ++nCurrCol ) for( sal_Int32 nCurrRow = nFirstRow; !bFound && (nCurrRow <= nLastRow); ++nCurrRow ) - bFound = mxImpl->GetCell( nCurrCol, nCurrRow )->IsMerged(); + bFound = CELL( nCurrCol, nCurrRow ).IsMerged(); DBG_FRAME_CHECK( !bFound, "SetMergedRange", "overlapping merged ranges" ); } #endif @@ -883,12 +923,11 @@ void Array::SetAddMergedLeftSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAdd DBG_FRAME_CHECK( mxImpl->GetMergedFirstCol( nCol, nRow ) == 0, "SetAddMergedLeftSize", "additional border inside array" ); for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) { - const Cell* pTempCell(mxImpl->GetCell(aIt.Col(), aIt.Row())); - if (pTempCell->mnAddLeft == nAddSize) + Cell aTempCell(CELL(aIt.Col(), aIt.Row())); + if (aTempCell.mnAddLeft == nAddSize) return; - Cell aTempCell(*pTempCell); aTempCell.mnAddLeft = nAddSize; - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); } } @@ -898,12 +937,11 @@ void Array::SetAddMergedRightSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAd DBG_FRAME_CHECK( mxImpl->GetMergedLastCol( nCol, nRow ) + 1 == mxImpl->mnWidth, "SetAddMergedRightSize", "additional border inside array" ); for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) { - const Cell* pTempCell(mxImpl->GetCell(aIt.Col(), aIt.Row())); - if (pTempCell->mnAddRight == nAddSize) + Cell aTempCell(CELL(aIt.Col(), aIt.Row())); + if (aTempCell.mnAddRight == nAddSize) return; - Cell aTempCell(*pTempCell); aTempCell.mnAddRight = nAddSize; - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); } } @@ -913,12 +951,11 @@ void Array::SetAddMergedTopSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddS DBG_FRAME_CHECK( mxImpl->GetMergedFirstRow( nCol, nRow ) == 0, "SetAddMergedTopSize", "additional border inside array" ); for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) { - const Cell* pTempCell(mxImpl->GetCell(aIt.Col(), aIt.Row())); - if (pTempCell->mnAddTop == nAddSize) + Cell aTempCell(CELL(aIt.Col(), aIt.Row())); + if (aTempCell.mnAddTop == nAddSize) return; - Cell aTempCell(*pTempCell); aTempCell.mnAddTop = nAddSize; - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); } } @@ -928,19 +965,18 @@ void Array::SetAddMergedBottomSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nA DBG_FRAME_CHECK( mxImpl->GetMergedLastRow( nCol, nRow ) + 1 == mxImpl->mnHeight, "SetAddMergedBottomSize", "additional border inside array" ); for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) { - const Cell* pTempCell(mxImpl->GetCell(aIt.Col(), aIt.Row())); - if (pTempCell->mnAddBottom == nAddSize) + Cell aTempCell(CELL(aIt.Col(), aIt.Row())); + if (aTempCell.mnAddBottom == nAddSize) return; - Cell aTempCell(*pTempCell); aTempCell.mnAddBottom = nAddSize; - mxImpl->PutCell( nCol, nRow, aTempCell ); + PUTCELL( nCol, nRow, aTempCell ); } } bool Array::IsMerged( sal_Int32 nCol, sal_Int32 nRow ) const { DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMerged" ); - return mxImpl->GetCell( nCol, nRow )->IsMerged(); + return CELL( nCol, nRow ).IsMerged(); } void Array::GetMergedOrigin( sal_Int32& rnFirstCol, sal_Int32& rnFirstRow, sal_Int32 nCol, sal_Int32 nRow ) const @@ -1056,9 +1092,9 @@ basegfx::B2DRange Array::GetCellRange( sal_Int32 nCol, sal_Int32 nRow ) const tools::Rectangle aRect(aPoint, aSize); // adjust rectangle for partly visible merged cells - const Cell* pCell(mxImpl->GetCell( nCol, nRow )); + const Cell& rCell = CELL( nCol, nRow ); - if( pCell->IsMerged() ) + if( rCell.IsMerged() ) { // not *sure* what exactly this is good for, // it is just a hard set extension at merged cells, @@ -1066,10 +1102,10 @@ basegfx::B2DRange Array::GetCellRange( sal_Int32 nCol, sal_Int32 nRow ) const // GetColPosition/GetColWidth already. This might be // added due to GetColPosition/GetColWidth not working // correctly over PageChanges (if used), but not sure. - aRect.AdjustLeft( -(pCell->mnAddLeft) ); - aRect.AdjustRight(pCell->mnAddRight ); - aRect.AdjustTop( -(pCell->mnAddTop) ); - aRect.AdjustBottom(pCell->mnAddBottom ); + aRect.AdjustLeft( -(rCell.mnAddLeft) ); + aRect.AdjustRight(rCell.mnAddRight ); + aRect.AdjustTop( -(rCell.mnAddTop) ); + aRect.AdjustBottom(rCell.mnAddBottom ); } return vcl::unotools::b2DRectangleFromRectangle(aRect); @@ -1095,7 +1131,7 @@ void Array::MirrorSelfX() { for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) { - Cell aTempCell(*mxImpl->GetCell(mxImpl->GetMirrorCol( nCol ), nRow)); + Cell aTempCell(CELL(mxImpl->GetMirrorCol( nCol ), nRow)); aTempCell.MirrorSelfX(); aNewCells.push_back( mxImpl->createOrFind(aTempCell) ); } @@ -1377,31 +1413,31 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( { // get Cell and CoordinateSystem (*only* for this Cell, do *not* expand for // merged cells (!)), check if used (non-empty vectors) - const Cell* pCell(mxImpl->GetCell(nCol, nRow)); - basegfx::B2DHomMatrix aCoordinateSystem(pCell->CreateCoordinateSystemSingleCell(*this, nCol, nRow)); + const Cell& rCell(CELL(nCol, nRow)); + basegfx::B2DHomMatrix aCoordinateSystem(rCell.CreateCoordinateSystemSingleCell(*this, nCol, nRow)); basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0)); basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1)); // get needed local values basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2)); - const bool bOverlapX(pCell->mbOverlapX); + const bool bOverlapX(rCell.mbOverlapX); const bool bFirstCol(nCol == nFirstCol); // handle rotation: If cell is rotated, handle lower/right edge inside // this local geometry due to the created CoordinateSystem already representing // the needed transformations. - const bool bRotated(pCell->IsRotated()); + const bool bRotated(rCell.IsRotated()); // Additionally avoid double-handling by suppressing handling when self not rotated, // but above/left is rotated and thus already handled. Two directly connected // rotated will paint/create both edges, they might be rotated differently. - const bool bSuppressLeft(!bRotated && nCol > nFirstCol && mxImpl->GetCell(nCol - 1, nRow)->IsRotated()); - const bool bSuppressAbove(!bRotated && nRow > nFirstRow && mxImpl->GetCell(nCol, nRow - 1)->IsRotated()); + const bool bSuppressLeft(!bRotated && nCol > nFirstCol && CELL(nCol - 1, nRow).IsRotated()); + const bool bSuppressAbove(!bRotated && nRow > nFirstRow && CELL(nCol, nRow - 1).IsRotated()); if(!aX.equalZero() && !aY.equalZero()) { // additionally needed local values - const bool bOverlapY(pCell->mbOverlapY); + const bool bOverlapY(rCell.mbOverlapY); const bool bLastCol(nCol == nLastCol); const bool bFirstRow(nRow == nFirstRow); const bool bLastRow(nRow == nLastRow); @@ -1412,7 +1448,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( && !bSuppressAbove) // true when above is not rotated, so edge is already handled (see bRotated) { // get CellStyle - method will take care to get the correct one, e.g. - // for merged cells (it uses mxImpl->GetMergedOriginCell that works with topLeft's of these) + // for merged cells (it uses ORIGCELL that works with topLeft's of these) const Style& rTop(GetCellStyleTop(nCol, nRow)); if(rTop.IsUsed()) @@ -1461,7 +1497,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( // tdf#126269 check for crossed lines, these need special treatment, especially // for merged cells (see comments in task). Separate treatment of merged and // non-merged cells to allow better handling of both types - if(pCell->IsMerged()) + if(rCell.IsMerged()) { // first check if this merged cell was already handled. To do so, // calculate and use the index of the TopLeft cell @@ -1490,7 +1526,8 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( // when merged, get extended coordinate system and derived values // for the full range of this merged cell. Only work with rMergedCell // (which is the top-left single cell of the merged cell) from here on - aCoordinateSystem = mxImpl->GetCell(nColLeft, nRowTop)->CreateCoordinateSystemMergedCell( + const Cell& rMergedCell(CELL(nColLeft, nRowTop)); + aCoordinateSystem = rMergedCell.CreateCoordinateSystemMergedCell( *this, nColLeft, nRowTop, nColRight, nRowBottom); aX = basegfx::utils::getColumn(aCoordinateSystem, 0); aY = basegfx::utils::getColumn(aCoordinateSystem, 1); @@ -1624,6 +1661,10 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveArray() return aPrimitives; } +#undef ORIGCELL +#undef LASTCELL +#undef CELLACC +#undef CELL #undef DBG_FRAME_CHECK_ROW_1 #undef DBG_FRAME_CHECK_COL_1 #undef DBG_FRAME_CHECK_COLROW |