1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26 #include <svx/framelinkarray.hxx>
27 
28 #include <math.h>
29 #include <vector>
30 #include <algorithm>
31 #include <vcl/outdev.hxx>
32 
33 namespace svx {
34 namespace frame {
35 
36 // ============================================================================
37 
38 
Cell()39 Cell::Cell() :
40     mnAddLeft( 0 ),
41     mnAddRight( 0 ),
42     mnAddTop( 0 ),
43     mnAddBottom( 0 ),
44     mbMergeOrig( false ),
45     mbOverlapX( false ),
46     mbOverlapY( false )
47 {
48 }
49 
MirrorSelfX(bool bMirrorStyles,bool bSwapDiag)50 void Cell::MirrorSelfX( bool bMirrorStyles, bool bSwapDiag )
51 {
52     std::swap( maLeft, maRight );
53     std::swap( mnAddLeft, mnAddRight );
54     if( bMirrorStyles )
55     {
56         maLeft.MirrorSelf();
57         maRight.MirrorSelf();
58     }
59     if( bSwapDiag )
60     {
61         std::swap( maTLBR, maBLTR );
62         if( bMirrorStyles )
63         {
64             maTLBR.MirrorSelf();
65             maBLTR.MirrorSelf();
66         }
67     }
68 }
69 
MirrorSelfY(bool bMirrorStyles,bool bSwapDiag)70 void Cell::MirrorSelfY( bool bMirrorStyles, bool bSwapDiag )
71 {
72     std::swap( maTop, maBottom );
73     std::swap( mnAddTop, mnAddBottom );
74     if( bMirrorStyles )
75     {
76         maTop.MirrorSelf();
77         maBottom.MirrorSelf();
78     }
79     if( bSwapDiag )
80         std::swap( maTLBR, maBLTR );
81     /*  Do not mirror diagonal styles, because they are oriented vertical.
82         Therefore swapping the styles is sufficient for correct behaviour. */
83 }
84 
85 // ----------------------------------------------------------------------------
86 
87 
lclRecalcCoordVec(LongVec & rCoords,const LongVec & rSizes)88 void lclRecalcCoordVec( LongVec& rCoords, const LongVec& rSizes )
89 {
90     DBG_ASSERT( rCoords.size() == rSizes.size() + 1, "lclRecalcCoordVec - inconsistent vectors" );
91     LongVec::iterator aCIt = rCoords.begin();
92     LongVec::const_iterator aSIt = rSizes.begin(), aSEnd = rSizes.end();
93     for( ; aSIt != aSEnd; ++aCIt, ++aSIt )
94         *(aCIt + 1) = *aCIt + *aSIt;
95 }
96 
lclSetMergedRange(CellVec & rCells,size_t nWidth,size_t nFirstCol,size_t nFirstRow,size_t nLastCol,size_t nLastRow)97 void lclSetMergedRange( CellVec& rCells, size_t nWidth, size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow )
98 {
99     for( size_t nCol = nFirstCol; nCol <= nLastCol; ++nCol )
100     {
101         for( size_t nRow = nFirstRow; nRow <= nLastRow; ++nRow )
102         {
103             Cell& rCell = rCells[ nRow * nWidth + nCol ];
104             rCell.mbMergeOrig = false;
105             rCell.mbOverlapX = nCol > nFirstCol;
106             rCell.mbOverlapY = nRow > nFirstRow;
107         }
108     }
109     rCells[ nFirstRow * nWidth + nFirstCol ].mbMergeOrig = true;
110 }
111 
112 // ----------------------------------------------------------------------------
113 
114 static const Style OBJ_STYLE_NONE;
115 static const Cell OBJ_CELL_NONE;
116 
117 const bool DIAG_DBL_CLIP_DEFAULT = false;
118 
119 // ============================================================================
120 
ArrayImpl(size_t nWidth,size_t nHeight,bool bDiagDblClip)121 ArrayImpl::ArrayImpl( size_t nWidth, size_t nHeight, bool bDiagDblClip ) :
122     mnWidth( nWidth ),
123     mnHeight( nHeight ),
124     mnFirstClipCol( 0 ),
125     mnFirstClipRow( 0 ),
126     mnLastClipCol( nWidth - 1 ),
127     mnLastClipRow( nHeight - 1 ),
128     mbXCoordsDirty( false ),
129     mbYCoordsDirty( false ),
130     mbDiagDblClip( bDiagDblClip )
131 {
132     // default-construct all vectors
133     maCells.resize( mnWidth * mnHeight );
134     maWidths.resize( mnWidth, 0L );
135     maHeights.resize( mnHeight, 0L );
136     maXCoords.resize( mnWidth + 1, 0L );
137     maYCoords.resize( mnHeight + 1, 0L );
138 }
139 
GetCell(size_t nCol,size_t nRow) const140 const Cell& ArrayImpl::GetCell( size_t nCol, size_t nRow ) const
141 {
142     return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : OBJ_CELL_NONE;
143 }
144 
GetCellAcc(size_t nCol,size_t nRow)145 Cell& ArrayImpl::GetCellAcc( size_t nCol, size_t nRow )
146 {
147     static Cell aDummy;
148     return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : aDummy;
149 }
150 
GetMergedFirstCol(size_t nCol,size_t nRow) const151 size_t ArrayImpl::GetMergedFirstCol( size_t nCol, size_t nRow ) const
152 {
153     size_t nFirstCol = nCol;
154     while( (nFirstCol > 0) && GetCell( nFirstCol, nRow ).mbOverlapX ) --nFirstCol;
155     return nFirstCol;
156 }
157 
GetMergedFirstRow(size_t nCol,size_t nRow) const158 size_t ArrayImpl::GetMergedFirstRow( size_t nCol, size_t nRow ) const
159 {
160     size_t nFirstRow = nRow;
161     while( (nFirstRow > 0) && GetCell( nCol, nFirstRow ).mbOverlapY ) --nFirstRow;
162     return nFirstRow;
163 }
164 
GetMergedLastCol(size_t nCol,size_t nRow) const165 size_t ArrayImpl::GetMergedLastCol( size_t nCol, size_t nRow ) const
166 {
167     size_t nLastCol = nCol + 1;
168     while( (nLastCol < mnWidth) && GetCell( nLastCol, nRow ).mbOverlapX ) ++nLastCol;
169     return nLastCol - 1;
170 }
171 
GetMergedLastRow(size_t nCol,size_t nRow) const172 size_t ArrayImpl::GetMergedLastRow( size_t nCol, size_t nRow ) const
173 {
174     size_t nLastRow = nRow + 1;
175     while( (nLastRow < mnHeight) && GetCell( nCol, nLastRow ).mbOverlapY ) ++nLastRow;
176     return nLastRow - 1;
177 }
178 
GetMergedOriginCell(size_t nCol,size_t nRow) const179 const Cell& ArrayImpl::GetMergedOriginCell( size_t nCol, size_t nRow ) const
180 {
181     return GetCell( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) );
182 }
183 
GetMergedOriginCellAcc(size_t nCol,size_t nRow)184 Cell& ArrayImpl::GetMergedOriginCellAcc( size_t nCol, size_t nRow )
185 {
186     return GetCellAcc( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) );
187 }
188 
IsMergedOverlappedLeft(size_t nCol,size_t nRow) const189 bool ArrayImpl::IsMergedOverlappedLeft( size_t nCol, size_t nRow ) const
190 {
191     const Cell& rCell = GetCell( nCol, nRow );
192     return rCell.mbOverlapX || (rCell.mnAddLeft > 0);
193 }
194 
IsMergedOverlappedRight(size_t nCol,size_t nRow) const195 bool ArrayImpl::IsMergedOverlappedRight( size_t nCol, size_t nRow ) const
196 {
197     return GetCell( nCol + 1, nRow ).mbOverlapX || (GetCell( nCol, nRow ).mnAddRight > 0);
198 }
199 
IsMergedOverlappedTop(size_t nCol,size_t nRow) const200 bool ArrayImpl::IsMergedOverlappedTop( size_t nCol, size_t nRow ) const
201 {
202     const Cell& rCell = GetCell( nCol, nRow );
203     return rCell.mbOverlapY || (rCell.mnAddTop > 0);
204 }
205 
IsMergedOverlappedBottom(size_t nCol,size_t nRow) const206 bool ArrayImpl::IsMergedOverlappedBottom( size_t nCol, size_t nRow ) const
207 {
208     return GetCell( nCol, nRow + 1 ).mbOverlapY || (GetCell( nCol, nRow ).mnAddBottom > 0);
209 }
210 
IsColInClipRange(size_t nCol) const211 bool ArrayImpl::IsColInClipRange( size_t nCol ) const
212 {
213     return (mnFirstClipCol <= nCol) && (nCol <= mnLastClipCol);
214 }
215 
IsRowInClipRange(size_t nRow) const216 bool ArrayImpl::IsRowInClipRange( size_t nRow ) const
217 {
218     return (mnFirstClipRow <= nRow) && (nRow <= mnLastClipRow);
219 }
220 
IsInClipRange(size_t nCol,size_t nRow) const221 bool ArrayImpl::IsInClipRange( size_t nCol, size_t nRow ) const
222 {
223     return IsColInClipRange( nCol ) && IsRowInClipRange( nRow );
224 }
225 
GetColPosition(size_t nCol) const226 long ArrayImpl::GetColPosition( size_t nCol ) const
227 {
228     if( mbXCoordsDirty )
229     {
230         lclRecalcCoordVec( maXCoords, maWidths );
231         mbXCoordsDirty = false;
232     }
233     return maXCoords[ nCol ];
234 }
235 
GetRowPosition(size_t nRow) const236 long ArrayImpl::GetRowPosition( size_t nRow ) const
237 {
238     if( mbYCoordsDirty )
239     {
240         lclRecalcCoordVec( maYCoords, maHeights );
241         mbYCoordsDirty = false;
242     }
243     return maYCoords[ nRow ];
244 }
245 
GetColWidth(size_t nFirstCol,size_t nLastCol) const246 long ArrayImpl::GetColWidth( size_t nFirstCol, size_t nLastCol ) const
247 {
248     return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol );
249 }
250 
GetRowHeight(size_t nFirstRow,size_t nLastRow) const251 long ArrayImpl::GetRowHeight( size_t nFirstRow, size_t nLastRow ) const
252 {
253     return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow );
254 }
255 
GetHorDiagAngle(size_t nCol,size_t nRow,bool bSimple) const256 double ArrayImpl::GetHorDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const
257 {
258     double fAngle = 0.0;
259     if( IsValidPos( nCol, nRow ) )
260     {
261         if( bSimple || !GetCell( nCol, nRow ).IsMerged() )
262         {
263             fAngle = frame::GetHorDiagAngle( maWidths[ nCol ] + 1, maHeights[ nRow ] + 1 );
264         }
265         else
266         {
267             // return correct angle for each cell in the merged range
268             size_t nFirstCol = GetMergedFirstCol( nCol, nRow );
269             size_t nFirstRow = GetMergedFirstRow( nCol, nRow );
270             const Cell& rCell = GetCell( nFirstCol, nFirstRow );
271             long nWidth = GetColWidth( nFirstCol, GetMergedLastCol( nCol, nRow ) ) + rCell.mnAddLeft + rCell.mnAddRight;
272             long nHeight = GetRowHeight( nFirstRow, GetMergedLastRow( nCol, nRow ) ) + rCell.mnAddTop + rCell.mnAddBottom;
273             fAngle = frame::GetHorDiagAngle( nWidth + 1, nHeight + 1 );
274         }
275     }
276     return fAngle;
277 }
278 
GetVerDiagAngle(size_t nCol,size_t nRow,bool bSimple) const279 double ArrayImpl::GetVerDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const
280 {
281     double fAngle = GetHorDiagAngle( nCol, nRow, bSimple );
282     return (fAngle > 0.0) ? (F_PI2 - fAngle) : 0.0;
283 }
284 
285 // ============================================================================
286 
287 class MergedCellIterator
288 {
289 public:
290     explicit            MergedCellIterator( const Array& rArray, size_t nCol, size_t nRow );
291 
Is() const292     inline bool         Is() const { return (mnCol <= mnLastCol) && (mnRow <= mnLastRow); }
Col() const293     inline size_t       Col() const { return mnCol; }
Row() const294     inline size_t       Row() const { return mnRow; }
295 
296     MergedCellIterator& operator++();
297 
298 private:
299     size_t              mnFirstCol;
300     size_t              mnFirstRow;
301     size_t              mnLastCol;
302     size_t              mnLastRow;
303     size_t              mnCol;
304     size_t              mnRow;
305 };
306 
307 // ----------------------------------------------------------------------------
308 
MergedCellIterator(const Array & rArray,size_t nCol,size_t nRow)309 MergedCellIterator::MergedCellIterator( const Array& rArray, size_t nCol, size_t nRow )
310 {
311     DBG_ASSERT( rArray.IsMerged( nCol, nRow ), "svx::frame::MergedCellIterator::MergedCellIterator - not in merged range" );
312     rArray.GetMergedRange( mnFirstCol, mnFirstRow, mnLastCol, mnLastRow, nCol, nRow );
313     mnCol = mnFirstCol;
314     mnRow = mnFirstRow;
315 }
316 
operator ++()317 MergedCellIterator& MergedCellIterator::operator++()
318 {
319     DBG_ASSERT( Is(), "svx::frame::MergedCellIterator::operator++() - already invalid" );
320     if( ++mnCol > mnLastCol )
321     {
322         mnCol = mnFirstCol;
323         ++mnRow;
324     }
325     return *this;
326 }
327 
328 // ============================================================================
329 
330 #define DBG_FRAME_ERROR( funcname, error )              DBG_ERRORFILE( "svx::frame::Array::" funcname " - " error )
331 #define DBG_FRAME_CHECK( cond, funcname, error )        DBG_ASSERT( cond, "svx::frame::Array::" funcname " - " error )
332 #define DBG_FRAME_CHECK_COL( col, funcname )            DBG_FRAME_CHECK( (col) < GetColCount(), funcname, "invalid column index" )
333 #define DBG_FRAME_CHECK_ROW( row, funcname )            DBG_FRAME_CHECK( (row) < GetRowCount(), funcname, "invalid row index" )
334 #define DBG_FRAME_CHECK_COLROW( col, row, funcname )    DBG_FRAME_CHECK( ((col) < GetColCount()) && ((row) < GetRowCount()), funcname, "invalid cell index" )
335 #define DBG_FRAME_CHECK_INDEX( index, funcname )        DBG_FRAME_CHECK( (index) < GetCellCount(), funcname, "invalid cell index" )
336 #define DBG_FRAME_CHECK_COL_1( col, funcname )          DBG_FRAME_CHECK( (col) <= GetColCount(), funcname, "invalid column index" )
337 #define DBG_FRAME_CHECK_ROW_1( row, funcname )          DBG_FRAME_CHECK( (row) <= GetRowCount(), funcname, "invalid row index" )
338 
339 // ----------------------------------------------------------------------------
340 
341 #define CELL( col, row )        mxImpl->GetCell( col, row )
342 #define CELLACC( col, row )     mxImpl->GetCellAcc( col, row )
343 #define ORIGCELL( col, row )    mxImpl->GetMergedOriginCell( col, row )
344 #define ORIGCELLACC( col, row ) mxImpl->GetMergedOriginCellAcc( col, row )
345 
346 // ----------------------------------------------------------------------------
347 
Array()348 Array::Array()
349 {
350     Initialize( 0, 0 );
351 }
352 
Array(size_t nWidth,size_t nHeight)353 Array::Array( size_t nWidth, size_t nHeight )
354 {
355     Initialize( nWidth, nHeight );
356 }
357 
~Array()358 Array::~Array()
359 {
360 }
361 
362 // array size and column/row indexes ------------------------------------------
363 
Initialize(size_t nWidth,size_t nHeight)364 void Array::Initialize( size_t nWidth, size_t nHeight )
365 {
366     bool bDiagDblClip = mxImpl.get() ? mxImpl->mbDiagDblClip : DIAG_DBL_CLIP_DEFAULT;
367     mxImpl.reset( new ArrayImpl( nWidth, nHeight, bDiagDblClip ) );
368 }
369 
Clear()370 void Array::Clear()
371 {
372     Initialize( mxImpl->mnWidth, mxImpl->mnHeight );
373 }
374 
GetColCount() const375 size_t Array::GetColCount() const
376 {
377     return mxImpl->mnWidth;
378 }
379 
GetRowCount() const380 size_t Array::GetRowCount() const
381 {
382     return mxImpl->mnHeight;
383 }
384 
GetCellCount() const385 size_t Array::GetCellCount() const
386 {
387     return mxImpl->maCells.size();
388 }
389 
GetColFromIndex(size_t nCellIndex) const390 size_t Array::GetColFromIndex( size_t nCellIndex ) const
391 {
392     DBG_FRAME_CHECK_INDEX( nCellIndex, "GetColFromIndex" );
393     return mxImpl->mnWidth ? (nCellIndex % mxImpl->mnWidth) : 0;
394 }
395 
GetRowFromIndex(size_t nCellIndex) const396 size_t Array::GetRowFromIndex( size_t nCellIndex ) const
397 {
398     DBG_FRAME_CHECK_INDEX( nCellIndex, "GetRowFromIndex" );
399     return mxImpl->mnWidth ? (nCellIndex / mxImpl->mnWidth) : 0;
400 }
401 
GetCellIndex(size_t nCol,size_t nRow,bool bRTL) const402 size_t Array::GetCellIndex( size_t nCol, size_t nRow, bool bRTL ) const
403 {
404     DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetCellIndex" );
405     if (bRTL)
406         nCol = mxImpl->GetMirrorCol(nCol);
407     return mxImpl->GetIndex( nCol, nRow );
408 }
409 
410 // cell border styles ---------------------------------------------------------
411 
SetCellStyleLeft(size_t nCol,size_t nRow,const Style & rStyle)412 void Array::SetCellStyleLeft( size_t nCol, size_t nRow, const Style& rStyle )
413 {
414     DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleLeft" );
415     CELLACC( nCol, nRow ).maLeft = rStyle;
416 }
417 
SetCellStyleRight(size_t nCol,size_t nRow,const Style & rStyle)418 void Array::SetCellStyleRight( size_t nCol, size_t nRow, const Style& rStyle )
419 {
420     DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleRight" );
421     CELLACC( nCol, nRow ).maRight = rStyle;
422 }
423 
SetCellStyleTop(size_t nCol,size_t nRow,const Style & rStyle)424 void Array::SetCellStyleTop( size_t nCol, size_t nRow, const Style& rStyle )
425 {
426     DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTop" );
427     CELLACC( nCol, nRow ).maTop = rStyle;
428 }
429 
SetCellStyleBottom(size_t nCol,size_t nRow,const Style & rStyle)430 void Array::SetCellStyleBottom( size_t nCol, size_t nRow, const Style& rStyle )
431 {
432     DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBottom" );
433     CELLACC( nCol, nRow ).maBottom = rStyle;
434 }
435 
SetCellStyleTLBR(size_t nCol,size_t nRow,const Style & rStyle)436 void Array::SetCellStyleTLBR( size_t nCol, size_t nRow, const Style& rStyle )
437 {
438     DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTLBR" );
439     CELLACC( nCol, nRow ).maTLBR = rStyle;
440 }
441 
SetCellStyleBLTR(size_t nCol,size_t nRow,const Style & rStyle)442 void Array::SetCellStyleBLTR( size_t nCol, size_t nRow, const Style& rStyle )
443 {
444     DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBLTR" );
445     CELLACC( nCol, nRow ).maBLTR = rStyle;
446 }
447 
SetCellStyleDiag(size_t nCol,size_t nRow,const Style & rTLBR,const Style & rBLTR)448 void Array::SetCellStyleDiag( size_t nCol, size_t nRow, const Style& rTLBR, const Style& rBLTR )
449 {
450     DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleDiag" );
451     Cell& rCell = CELLACC( nCol, nRow );
452     rCell.maTLBR = rTLBR;
453     rCell.maBLTR = rBLTR;
454 }
455 
SetColumnStyleLeft(size_t nCol,const Style & rStyle)456 void Array::SetColumnStyleLeft( size_t nCol, const Style& rStyle )
457 {
458     DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleLeft" );
459     for( size_t nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
460         SetCellStyleLeft( nCol, nRow, rStyle );
461 }
462 
SetColumnStyleRight(size_t nCol,const Style & rStyle)463 void Array::SetColumnStyleRight( size_t nCol, const Style& rStyle )
464 {
465     DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleRight" );
466     for( size_t nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
467         SetCellStyleRight( nCol, nRow, rStyle );
468 }
469 
SetRowStyleTop(size_t nRow,const Style & rStyle)470 void Array::SetRowStyleTop( size_t nRow, const Style& rStyle )
471 {
472     DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleTop" );
473     for( size_t nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
474         SetCellStyleTop( nCol, nRow, rStyle );
475 }
476 
SetRowStyleBottom(size_t nRow,const Style & rStyle)477 void Array::SetRowStyleBottom( size_t nRow, const Style& rStyle )
478 {
479     DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleBottom" );
480     for( size_t nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
481         SetCellStyleBottom( nCol, nRow, rStyle );
482 }
483 
GetCellStyleLeft(size_t nCol,size_t nRow,bool bSimple) const484 const Style& Array::GetCellStyleLeft( size_t nCol, size_t nRow, bool bSimple ) const
485 {
486     // simple: always return own left style
487     if( bSimple )
488         return CELL( nCol, nRow ).maLeft;
489     // outside clipping rows or overlapped in merged cells: invisible
490     if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedLeft( nCol, nRow ) )
491         return OBJ_STYLE_NONE;
492     // left clipping border: always own left style
493     if( nCol == mxImpl->mnFirstClipCol )
494         return ORIGCELL( nCol, nRow ).maLeft;
495     // right clipping border: always right style of left neighbor cell
496     if( nCol == mxImpl->mnLastClipCol + 1 )
497         return ORIGCELL( nCol - 1, nRow ).maRight;
498     // outside clipping columns: invisible
499     if( !mxImpl->IsColInClipRange( nCol ) )
500         return OBJ_STYLE_NONE;
501     // inside clipping range: maximum of own left style and right style of left neighbor cell
502     return std::max( ORIGCELL( nCol, nRow ).maLeft, ORIGCELL( nCol - 1, nRow ).maRight );
503 }
504 
GetCellStyleRight(size_t nCol,size_t nRow,bool bSimple) const505 const Style& Array::GetCellStyleRight( size_t nCol, size_t nRow, bool bSimple ) const
506 {
507     // simple: always return own right style
508     if( bSimple )
509         return CELL( nCol, nRow ).maRight;
510     // outside clipping rows or overlapped in merged cells: invisible
511     if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedRight( nCol, nRow ) )
512         return OBJ_STYLE_NONE;
513     // left clipping border: always left style of right neighbor cell
514     if( nCol + 1 == mxImpl->mnFirstClipCol )
515         return ORIGCELL( nCol + 1, nRow ).maLeft;
516     // right clipping border: always own right style
517     if( nCol == mxImpl->mnLastClipCol )
518         return ORIGCELL( nCol, nRow ).maRight;
519     // outside clipping columns: invisible
520     if( !mxImpl->IsColInClipRange( nCol ) )
521         return OBJ_STYLE_NONE;
522     // inside clipping range: maximum of own right style and left style of right neighbor cell
523     return std::max( ORIGCELL( nCol, nRow ).maRight, ORIGCELL( nCol + 1, nRow ).maLeft );
524 }
525 
GetCellStyleTop(size_t nCol,size_t nRow,bool bSimple) const526 const Style& Array::GetCellStyleTop( size_t nCol, size_t nRow, bool bSimple ) const
527 {
528     // simple: always return own top style
529     if( bSimple )
530         return CELL( nCol, nRow ).maTop;
531     // outside clipping columns or overlapped in merged cells: invisible
532     if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedTop( nCol, nRow ) )
533         return OBJ_STYLE_NONE;
534     // top clipping border: always own top style
535     if( nRow == mxImpl->mnFirstClipRow )
536         return ORIGCELL( nCol, nRow ).maTop;
537     // bottom clipping border: always bottom style of top neighbor cell
538     if( nRow == mxImpl->mnLastClipRow + 1 )
539         return ORIGCELL( nCol, nRow - 1 ).maBottom;
540     // outside clipping rows: invisible
541     if( !mxImpl->IsRowInClipRange( nRow ) )
542         return OBJ_STYLE_NONE;
543     // inside clipping range: maximum of own top style and bottom style of top neighbor cell
544     return std::max( ORIGCELL( nCol, nRow ).maTop, ORIGCELL( nCol, nRow - 1 ).maBottom );
545 }
546 
GetCellStyleBottom(size_t nCol,size_t nRow,bool bSimple) const547 const Style& Array::GetCellStyleBottom( size_t nCol, size_t nRow, bool bSimple ) const
548 {
549     // simple: always return own bottom style
550     if( bSimple )
551         return CELL( nCol, nRow ).maBottom;
552     // outside clipping columns or overlapped in merged cells: invisible
553     if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedBottom( nCol, nRow ) )
554         return OBJ_STYLE_NONE;
555     // top clipping border: always top style of bottom neighbor cell
556     if( nRow + 1 == mxImpl->mnFirstClipRow )
557         return ORIGCELL( nCol, nRow + 1 ).maTop;
558     // bottom clipping border: always own bottom style
559     if( nRow == mxImpl->mnLastClipRow )
560         return ORIGCELL( nCol, nRow ).maBottom;
561     // outside clipping rows: invisible
562     if( !mxImpl->IsRowInClipRange( nRow ) )
563         return OBJ_STYLE_NONE;
564     // inside clipping range: maximum of own bottom style and top style of bottom neighbor cell
565     return std::max( ORIGCELL( nCol, nRow ).maBottom, ORIGCELL( nCol, nRow + 1 ).maTop );
566 }
567 
GetCellStyleTLBR(size_t nCol,size_t nRow,bool bSimple) const568 const Style& Array::GetCellStyleTLBR( size_t nCol, size_t nRow, bool bSimple ) const
569 {
570     return bSimple ? CELL( nCol, nRow ).maTLBR :
571         (mxImpl->IsInClipRange( nCol, nRow ) ? ORIGCELL( nCol, nRow ).maTLBR : OBJ_STYLE_NONE);
572 }
573 
GetCellStyleBLTR(size_t nCol,size_t nRow,bool bSimple) const574 const Style& Array::GetCellStyleBLTR( size_t nCol, size_t nRow, bool bSimple ) const
575 {
576     return bSimple ? CELL( nCol, nRow ).maBLTR :
577         (mxImpl->IsInClipRange( nCol, nRow ) ? ORIGCELL( nCol, nRow ).maBLTR : OBJ_STYLE_NONE);
578 }
579 
GetCellStyleTL(size_t nCol,size_t nRow) const580 const Style& Array::GetCellStyleTL( size_t nCol, size_t nRow ) const
581 {
582     // not in clipping range: always invisible
583     if( !mxImpl->IsInClipRange( nCol, nRow ) )
584         return OBJ_STYLE_NONE;
585     // return style only for top-left cell
586     size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
587     size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
588     return ((nCol == nFirstCol) && (nRow == nFirstRow)) ?
589         CELL( nFirstCol, nFirstRow ).maTLBR : OBJ_STYLE_NONE;
590 }
591 
GetCellStyleBR(size_t nCol,size_t nRow) const592 const Style& Array::GetCellStyleBR( size_t nCol, size_t nRow ) const
593 {
594     // not in clipping range: always invisible
595     if( !mxImpl->IsInClipRange( nCol, nRow ) )
596         return OBJ_STYLE_NONE;
597     // return style only for bottom-right cell
598     size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
599     size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
600     return ((nCol == nLastCol) && (nRow == nLastRow)) ?
601         CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), mxImpl->GetMergedFirstRow( nCol, nRow ) ).maTLBR : OBJ_STYLE_NONE;
602 }
603 
GetCellStyleBL(size_t nCol,size_t nRow) const604 const Style& Array::GetCellStyleBL( size_t nCol, size_t nRow ) const
605 {
606     // not in clipping range: always invisible
607     if( !mxImpl->IsInClipRange( nCol, nRow ) )
608         return OBJ_STYLE_NONE;
609     // return style only for bottom-left cell
610     size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
611     size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
612     return ((nCol == nFirstCol) && (nRow == nLastRow)) ?
613         CELL( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) ).maBLTR : OBJ_STYLE_NONE;
614 }
615 
GetCellStyleTR(size_t nCol,size_t nRow) const616 const Style& Array::GetCellStyleTR( size_t nCol, size_t nRow ) const
617 {
618     // not in clipping range: always invisible
619     if( !mxImpl->IsInClipRange( nCol, nRow ) )
620         return OBJ_STYLE_NONE;
621     // return style only for top-right cell
622     size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
623     size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
624     return ((nCol == nLastCol) && (nRow == nFirstRow)) ?
625         CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), nFirstRow ).maBLTR : OBJ_STYLE_NONE;
626 }
627 
628 // cell merging ---------------------------------------------------------------
629 
SetMergedRange(size_t nFirstCol,size_t nFirstRow,size_t nLastCol,size_t nLastRow)630 void Array::SetMergedRange( size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow )
631 {
632     DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetMergedRange" );
633     DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetMergedRange" );
634 #if OSL_DEBUG_LEVEL >= 2
635     {
636         bool bFound = false;
637         for( size_t nCurrCol = nFirstCol; !bFound && (nCurrCol <= nLastCol); ++nCurrCol )
638             for( size_t nCurrRow = nFirstRow; !bFound && (nCurrRow <= nLastRow); ++nCurrRow )
639                 bFound = CELL( nCurrCol, nCurrRow ).IsMerged();
640         DBG_FRAME_CHECK( !bFound, "SetMergedRange", "overlapping merged ranges" );
641     }
642 #endif
643     if( mxImpl->IsValidPos( nFirstCol, nFirstRow ) && mxImpl->IsValidPos( nLastCol, nLastRow ) )
644         lclSetMergedRange( mxImpl->maCells, mxImpl->mnWidth, nFirstCol, nFirstRow, nLastCol, nLastRow );
645 }
646 
RemoveMergedRange(size_t nCol,size_t nRow)647 void Array::RemoveMergedRange( size_t nCol, size_t nRow )
648 {
649     DBG_FRAME_CHECK_COLROW( nCol, nRow, "RemoveMergedRange" );
650     for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
651     {
652         Cell& rCell = CELLACC( aIt.Col(), aIt.Row() );
653         rCell.mbMergeOrig = rCell.mbOverlapX = rCell.mbOverlapY = false;
654         rCell.mnAddLeft = rCell.mnAddRight = rCell.mnAddTop = rCell.mnAddBottom = 0;
655     }
656 }
657 
SetAddMergedLeftSize(size_t nCol,size_t nRow,long nAddSize)658 void Array::SetAddMergedLeftSize( size_t nCol, size_t nRow, long nAddSize )
659 {
660     DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedLeftSize" );
661     DBG_FRAME_CHECK( mxImpl->GetMergedFirstCol( nCol, nRow ) == 0, "SetAddMergedLeftSize", "additional border inside array" );
662     for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
663         CELLACC( aIt.Col(), aIt.Row() ).mnAddLeft = nAddSize;
664 }
665 
SetAddMergedRightSize(size_t nCol,size_t nRow,long nAddSize)666 void Array::SetAddMergedRightSize( size_t nCol, size_t nRow, long nAddSize )
667 {
668     DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedRightSize" );
669     DBG_FRAME_CHECK( mxImpl->GetMergedLastCol( nCol, nRow ) + 1 == mxImpl->mnWidth, "SetAddMergedRightSize", "additional border inside array" );
670     for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
671         CELLACC( aIt.Col(), aIt.Row() ).mnAddRight = nAddSize;
672 }
673 
SetAddMergedTopSize(size_t nCol,size_t nRow,long nAddSize)674 void Array::SetAddMergedTopSize( size_t nCol, size_t nRow, long nAddSize )
675 {
676     DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedTopSize" );
677     DBG_FRAME_CHECK( mxImpl->GetMergedFirstRow( nCol, nRow ) == 0, "SetAddMergedTopSize", "additional border inside array" );
678     for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
679         CELLACC( aIt.Col(), aIt.Row() ).mnAddTop = nAddSize;
680 }
681 
SetAddMergedBottomSize(size_t nCol,size_t nRow,long nAddSize)682 void Array::SetAddMergedBottomSize( size_t nCol, size_t nRow, long nAddSize )
683 {
684     DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedBottomSize" );
685     DBG_FRAME_CHECK( mxImpl->GetMergedLastRow( nCol, nRow ) + 1 == mxImpl->mnHeight, "SetAddMergedBottomSize", "additional border inside array" );
686     for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
687         CELLACC( aIt.Col(), aIt.Row() ).mnAddBottom = nAddSize;
688 }
689 
IsMerged(size_t nCol,size_t nRow) const690 bool Array::IsMerged( size_t nCol, size_t nRow ) const
691 {
692     DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMerged" );
693     return CELL( nCol, nRow ).IsMerged();
694 }
695 
IsMergedOrigin(size_t nCol,size_t nRow) const696 bool Array::IsMergedOrigin( size_t nCol, size_t nRow ) const
697 {
698     DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOrigin" );
699     return CELL( nCol, nRow ).mbMergeOrig;
700 }
701 
IsMergedOverlapped(size_t nCol,size_t nRow) const702 bool Array::IsMergedOverlapped( size_t nCol, size_t nRow ) const
703 {
704     DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlapped" );
705     return CELL( nCol, nRow ).IsOverlapped();
706 }
707 
IsMergedOverlappedLeft(size_t nCol,size_t nRow) const708 bool Array::IsMergedOverlappedLeft( size_t nCol, size_t nRow ) const
709 {
710     DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedLeft" );
711     return mxImpl->IsMergedOverlappedLeft( nCol, nRow );
712 }
713 
IsMergedOverlappedRight(size_t nCol,size_t nRow) const714 bool Array::IsMergedOverlappedRight( size_t nCol, size_t nRow ) const
715 {
716     DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedRight" );
717     return mxImpl->IsMergedOverlappedRight( nCol, nRow );
718 }
719 
IsMergedOverlappedTop(size_t nCol,size_t nRow) const720 bool Array::IsMergedOverlappedTop( size_t nCol, size_t nRow ) const
721 {
722     DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedTop" );
723     return mxImpl->IsMergedOverlappedTop( nCol, nRow );
724 }
725 
IsMergedOverlappedBottom(size_t nCol,size_t nRow) const726 bool Array::IsMergedOverlappedBottom( size_t nCol, size_t nRow ) const
727 {
728     DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedBottom" );
729     return mxImpl->IsMergedOverlappedBottom( nCol, nRow );
730 }
731 
GetMergedOrigin(size_t & rnFirstCol,size_t & rnFirstRow,size_t nCol,size_t nRow) const732 void Array::GetMergedOrigin( size_t& rnFirstCol, size_t& rnFirstRow, size_t nCol, size_t nRow ) const
733 {
734     DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetMergedOrigin" );
735     rnFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
736     rnFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
737 }
738 
GetMergedSize(size_t & rnWidth,size_t & rnHeight,size_t nCol,size_t nRow) const739 void Array::GetMergedSize( size_t& rnWidth, size_t& rnHeight, size_t nCol, size_t nRow ) const
740 {
741     size_t nFirstCol, nFirstRow, nLastCol, nLastRow;
742     GetMergedRange( nFirstCol, nFirstRow, nLastCol, nLastRow, nCol, nRow );
743     rnWidth = nLastCol - nFirstCol + 1;
744     rnHeight = nLastRow - nFirstRow + 1;
745 }
746 
GetMergedRange(size_t & rnFirstCol,size_t & rnFirstRow,size_t & rnLastCol,size_t & rnLastRow,size_t nCol,size_t nRow) const747 void Array::GetMergedRange( size_t& rnFirstCol, size_t& rnFirstRow,
748         size_t& rnLastCol, size_t& rnLastRow, size_t nCol, size_t nRow ) const
749 {
750     GetMergedOrigin( rnFirstCol, rnFirstRow, nCol, nRow );
751     rnLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
752     rnLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
753 }
754 
755 // clipping -------------------------------------------------------------------
756 
SetClipRange(size_t nFirstCol,size_t nFirstRow,size_t nLastCol,size_t nLastRow)757 void Array::SetClipRange( size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow )
758 {
759     DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetClipRange" );
760     DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetClipRange" );
761     mxImpl->mnFirstClipCol = nFirstCol;
762     mxImpl->mnFirstClipRow = nFirstRow;
763     mxImpl->mnLastClipCol = nLastCol;
764     mxImpl->mnLastClipRow = nLastRow;
765 }
766 
RemoveClipRange()767 void Array::RemoveClipRange()
768 {
769     if( !mxImpl->maCells.empty() )
770         SetClipRange( 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1 );
771 }
772 
IsInClipRange(size_t nCol,size_t nRow) const773 bool Array::IsInClipRange( size_t nCol, size_t nRow ) const
774 {
775     DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsInClipRange" );
776     return mxImpl->IsInClipRange( nCol, nRow );
777 }
778 
GetClipRangeRectangle() const779 Rectangle Array::GetClipRangeRectangle() const
780 {
781     return Rectangle(
782         mxImpl->GetColPosition( mxImpl->mnFirstClipCol ),
783         mxImpl->GetRowPosition( mxImpl->mnFirstClipRow ),
784         mxImpl->GetColPosition( mxImpl->mnLastClipCol + 1 ),
785         mxImpl->GetRowPosition( mxImpl->mnLastClipRow + 1 ) );
786 }
787 
788 // cell coordinates -----------------------------------------------------------
789 
SetXOffset(long nXOffset)790 void Array::SetXOffset( long nXOffset )
791 {
792     mxImpl->maXCoords[ 0 ] = nXOffset;
793     mxImpl->mbXCoordsDirty = true;
794 }
795 
SetYOffset(long nYOffset)796 void Array::SetYOffset( long nYOffset )
797 {
798     mxImpl->maYCoords[ 0 ] = nYOffset;
799     mxImpl->mbYCoordsDirty = true;
800 }
801 
SetColWidth(size_t nCol,long nWidth)802 void Array::SetColWidth( size_t nCol, long nWidth )
803 {
804     DBG_FRAME_CHECK_COL( nCol, "SetColWidth" );
805     mxImpl->maWidths[ nCol ] = nWidth;
806     mxImpl->mbXCoordsDirty = true;
807 }
808 
SetRowHeight(size_t nRow,long nHeight)809 void Array::SetRowHeight( size_t nRow, long nHeight )
810 {
811     DBG_FRAME_CHECK_ROW( nRow, "SetRowHeight" );
812     mxImpl->maHeights[ nRow ] = nHeight;
813     mxImpl->mbYCoordsDirty = true;
814 }
815 
SetAllColWidths(long nWidth)816 void Array::SetAllColWidths( long nWidth )
817 {
818     std::fill( mxImpl->maWidths.begin(), mxImpl->maWidths.end(), nWidth );
819     mxImpl->mbXCoordsDirty = true;
820 }
821 
SetAllRowHeights(long nHeight)822 void Array::SetAllRowHeights( long nHeight )
823 {
824     std::fill( mxImpl->maHeights.begin(), mxImpl->maHeights.end(), nHeight );
825     mxImpl->mbYCoordsDirty = true;
826 }
827 
GetColPosition(size_t nCol) const828 long Array::GetColPosition( size_t nCol ) const
829 {
830     DBG_FRAME_CHECK_COL_1( nCol, "GetColPosition" );
831     return mxImpl->GetColPosition( nCol );
832 }
833 
GetRowPosition(size_t nRow) const834 long Array::GetRowPosition( size_t nRow ) const
835 {
836     DBG_FRAME_CHECK_ROW_1( nRow, "GetRowPosition" );
837     return mxImpl->GetRowPosition( nRow );
838 }
839 
GetColWidth(size_t nCol) const840 long Array::GetColWidth( size_t nCol ) const
841 {
842     DBG_FRAME_CHECK_COL( nCol, "GetColWidth" );
843     return mxImpl->maWidths[ nCol ];
844 }
845 
GetColWidth(size_t nFirstCol,size_t nLastCol) const846 long Array::GetColWidth( size_t nFirstCol, size_t nLastCol ) const
847 {
848     DBG_FRAME_CHECK_COL( nFirstCol, "GetColWidth" );
849     DBG_FRAME_CHECK_COL( nLastCol, "GetColWidth" );
850     return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol );
851 }
852 
GetRowHeight(size_t nRow) const853 long Array::GetRowHeight( size_t nRow ) const
854 {
855     DBG_FRAME_CHECK_ROW( nRow, "GetRowHeight" );
856     return mxImpl->maHeights[ nRow ];
857 }
858 
GetRowHeight(size_t nFirstRow,size_t nLastRow) const859 long Array::GetRowHeight( size_t nFirstRow, size_t nLastRow ) const
860 {
861     DBG_FRAME_CHECK_ROW( nFirstRow, "GetRowHeight" );
862     DBG_FRAME_CHECK_ROW( nLastRow, "GetRowHeight" );
863     return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow );
864 }
865 
GetWidth() const866 long Array::GetWidth() const
867 {
868     return GetColPosition( mxImpl->mnWidth ) - GetColPosition( 0 );
869 }
870 
GetHeight() const871 long Array::GetHeight() const
872 {
873     return GetRowPosition( mxImpl->mnHeight ) - GetRowPosition( 0 );
874 }
875 
GetCellPosition(size_t nCol,size_t nRow,bool bSimple) const876 Point Array::GetCellPosition( size_t nCol, size_t nRow, bool bSimple ) const
877 {
878     size_t nFirstCol = bSimple ? nCol : mxImpl->GetMergedFirstCol( nCol, nRow );
879     size_t nFirstRow = bSimple ? nRow : mxImpl->GetMergedFirstRow( nCol, nRow );
880     return Point( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) );
881 }
882 
GetCellSize(size_t nCol,size_t nRow,bool bSimple) const883 Size Array::GetCellSize( size_t nCol, size_t nRow, bool bSimple ) const
884 {
885     size_t nFirstCol = bSimple ? nCol : mxImpl->GetMergedFirstCol( nCol, nRow );
886     size_t nFirstRow = bSimple ? nRow : mxImpl->GetMergedFirstRow( nCol, nRow );
887     size_t nLastCol = bSimple ? nCol : mxImpl->GetMergedLastCol( nCol, nRow );
888     size_t nLastRow = bSimple ? nRow : mxImpl->GetMergedLastRow( nCol, nRow );
889     return Size( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 );
890 }
891 
GetCellRect(size_t nCol,size_t nRow,bool bSimple) const892 Rectangle Array::GetCellRect( size_t nCol, size_t nRow, bool bSimple ) const
893 {
894     Rectangle aRect( GetCellPosition( nCol, nRow, bSimple ), GetCellSize( nCol, nRow, bSimple ) );
895 
896     // adjust rectangle for partly visible merged cells
897     const Cell& rCell = CELL( nCol, nRow );
898     if( !bSimple && rCell.IsMerged() )
899     {
900         aRect.Left() -= rCell.mnAddLeft;
901         aRect.Right() += rCell.mnAddRight;
902         aRect.Top() -= rCell.mnAddTop;
903         aRect.Bottom() += rCell.mnAddBottom;
904     }
905     return aRect;
906 }
907 
908 // diagonal frame borders -----------------------------------------------------
909 
GetHorDiagAngle(size_t nCol,size_t nRow,bool bSimple) const910 double Array::GetHorDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const
911 {
912     DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetHorDiagAngle" );
913     return mxImpl->GetHorDiagAngle( nCol, nRow, bSimple );
914 }
915 
GetVerDiagAngle(size_t nCol,size_t nRow,bool bSimple) const916 double Array::GetVerDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const
917 {
918     DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetVerDiagAngle" );
919     return mxImpl->GetVerDiagAngle( nCol, nRow, bSimple );
920 }
921 
SetUseDiagDoubleClipping(bool bSet)922 void Array::SetUseDiagDoubleClipping( bool bSet )
923 {
924     mxImpl->mbDiagDblClip = bSet;
925 }
926 
GetUseDiagDoubleClipping() const927 bool Array::GetUseDiagDoubleClipping() const
928 {
929     return mxImpl->mbDiagDblClip;
930 }
931 
932 // mirroring ------------------------------------------------------------------
933 
MirrorSelfX(bool bMirrorStyles,bool bSwapDiag)934 void Array::MirrorSelfX( bool bMirrorStyles, bool bSwapDiag )
935 {
936     CellVec aNewCells;
937     aNewCells.reserve( GetCellCount() );
938 
939     size_t nCol, nRow;
940     for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
941     {
942         for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
943         {
944             aNewCells.push_back( CELL( mxImpl->GetMirrorCol( nCol ), nRow ) );
945             aNewCells.back().MirrorSelfX( bMirrorStyles, bSwapDiag );
946         }
947     }
948     for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
949     {
950         for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
951         {
952             if( CELL( nCol, nRow ).mbMergeOrig )
953             {
954                 size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
955                 size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
956                 lclSetMergedRange( aNewCells, mxImpl->mnWidth,
957                     mxImpl->GetMirrorCol( nLastCol ), nRow,
958                     mxImpl->GetMirrorCol( nCol ), nLastRow );
959             }
960         }
961     }
962     mxImpl->maCells.swap( aNewCells );
963 
964     std::reverse( mxImpl->maWidths.begin(), mxImpl->maWidths.end() );
965     mxImpl->mbXCoordsDirty = true;
966 }
967 
MirrorSelfY(bool bMirrorStyles,bool bSwapDiag)968 void Array::MirrorSelfY( bool bMirrorStyles, bool bSwapDiag )
969 {
970     CellVec aNewCells;
971     aNewCells.reserve( GetCellCount() );
972 
973     size_t nCol, nRow;
974     for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
975     {
976         for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
977         {
978             aNewCells.push_back( CELL( nCol, mxImpl->GetMirrorRow( nRow ) ) );
979             aNewCells.back().MirrorSelfY( bMirrorStyles, bSwapDiag );
980         }
981     }
982     for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
983     {
984         for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
985         {
986             if( CELL( nCol, nRow ).mbMergeOrig )
987             {
988                 size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
989                 size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
990                 lclSetMergedRange( aNewCells, mxImpl->mnWidth,
991                     nCol, mxImpl->GetMirrorRow( nLastRow ),
992                     nLastCol, mxImpl->GetMirrorRow( nRow ) );
993             }
994         }
995     }
996     mxImpl->maCells.swap( aNewCells );
997 
998     std::reverse( mxImpl->maHeights.begin(), mxImpl->maHeights.end() );
999     mxImpl->mbYCoordsDirty = true;
1000 }
1001 
1002 // drawing --------------------------------------------------------------------
1003 
DrawCell(OutputDevice & rDev,size_t nCol,size_t nRow,const Color * pForceColor) const1004 void Array::DrawCell( OutputDevice& rDev, size_t nCol, size_t nRow, const Color* pForceColor ) const
1005 {
1006     DrawRange( rDev, nCol, nRow, nCol, nRow, pForceColor );
1007 }
1008 
DrawRange(OutputDevice & rDev,size_t nFirstCol,size_t nFirstRow,size_t nLastCol,size_t nLastRow,const Color * pForceColor) const1009 void Array::DrawRange( OutputDevice& rDev,
1010         size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow,
1011         const Color* pForceColor ) const
1012 {
1013     DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "DrawRange" );
1014     DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "DrawRange" );
1015 
1016     size_t nCol, nRow;
1017 
1018     // *** diagonal frame borders ***
1019 
1020     // set clipping region to clip partly visible merged cells
1021     rDev.Push( PUSH_CLIPREGION );
1022     rDev.IntersectClipRegion( GetClipRangeRectangle() );
1023     for( nRow = nFirstRow; nRow <= nLastRow; ++nRow )
1024     {
1025         for( nCol = nFirstCol; nCol <= nLastCol; ++nCol )
1026         {
1027             const Cell& rCell = CELL( nCol, nRow );
1028             bool bOverlapX = rCell.mbOverlapX;
1029             bool bOverlapY = rCell.mbOverlapY;
1030             bool bFirstCol = nCol == nFirstCol;
1031             bool bFirstRow = nRow == nFirstRow;
1032             if( (!bOverlapX && !bOverlapY) || (bFirstCol && bFirstRow) ||
1033                 (!bOverlapY && bFirstCol) || (!bOverlapX && bFirstRow) )
1034             {
1035                 Rectangle aRect( GetCellRect( nCol, nRow ) );
1036                 if( (aRect.GetWidth() > 1) && (aRect.GetHeight() > 1) )
1037                 {
1038                     size_t _nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
1039                     size_t _nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
1040                     size_t _nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
1041                     size_t _nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
1042 
1043                     DrawDiagFrameBorders( rDev, aRect,
1044                         GetCellStyleTLBR( _nFirstCol, _nFirstRow, true ), GetCellStyleBLTR( _nFirstCol, _nFirstRow, true ),
1045                         GetCellStyleLeft( _nFirstCol, _nFirstRow ), GetCellStyleTop( _nFirstCol, _nFirstRow ),
1046                         GetCellStyleRight( _nLastCol, _nLastRow ), GetCellStyleBottom( _nLastCol, _nLastRow ),
1047                         GetCellStyleLeft( _nFirstCol, _nLastRow ), GetCellStyleBottom( _nFirstCol, _nLastRow ),
1048                         GetCellStyleRight( _nLastCol, _nFirstRow ), GetCellStyleTop( _nLastCol, _nFirstRow ),
1049                         pForceColor, mxImpl->mbDiagDblClip );
1050                 }
1051             }
1052         }
1053     }
1054     rDev.Pop(); // clip region
1055 
1056     // *** horizontal frame borders ***
1057 
1058     for( nRow = nFirstRow; nRow <= nLastRow + 1; ++nRow )
1059     {
1060         double fAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow );
1061         double fTAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow - 1 );
1062 
1063         // *Start*** variables store the data of the left end of the cached frame border
1064         Point aStartPos( mxImpl->GetColPosition( nFirstCol ), mxImpl->GetRowPosition( nRow ) );
1065         const Style* pStart = &GetCellStyleTop( nFirstCol, nRow );
1066         DiagStyle aStartLFromTR( GetCellStyleBL( nFirstCol, nRow - 1 ), fTAngle );
1067         const Style* pStartLFromT = &GetCellStyleLeft( nFirstCol, nRow - 1 );
1068         const Style* pStartLFromL = &GetCellStyleTop( nFirstCol - 1, nRow );
1069         const Style* pStartLFromB = &GetCellStyleLeft( nFirstCol, nRow );
1070         DiagStyle aStartLFromBR( GetCellStyleTL( nFirstCol, nRow ), fAngle );
1071 
1072         // *End*** variables store the data of the right end of the cached frame border
1073         DiagStyle aEndRFromTL( GetCellStyleBR( nFirstCol, nRow - 1 ), fTAngle );
1074         const Style* pEndRFromT = &GetCellStyleRight( nFirstCol, nRow - 1 );
1075         const Style* pEndRFromR = &GetCellStyleTop( nFirstCol + 1, nRow );
1076         const Style* pEndRFromB = &GetCellStyleRight( nFirstCol, nRow );
1077         DiagStyle aEndRFromBL( GetCellStyleTR( nFirstCol, nRow ), fAngle );
1078 
1079         for( nCol = nFirstCol + 1; nCol <= nLastCol; ++nCol )
1080         {
1081             fAngle = mxImpl->GetHorDiagAngle( nCol, nRow );
1082             fTAngle = mxImpl->GetHorDiagAngle( nCol, nRow - 1 );
1083 
1084             const Style& rCurr = *pEndRFromR;
1085 
1086             DiagStyle aLFromTR( GetCellStyleBL( nCol, nRow - 1 ), fTAngle );
1087             const Style& rLFromT = *pEndRFromT;
1088             const Style& rLFromL = *pStart;
1089             const Style& rLFromB = *pEndRFromB;
1090             DiagStyle aLFromBR( GetCellStyleTL( nCol, nRow ), fAngle );
1091 
1092             DiagStyle aRFromTL( GetCellStyleBR( nCol, nRow - 1 ), fTAngle );
1093             const Style& rRFromT = GetCellStyleRight( nCol, nRow - 1 );
1094             const Style& rRFromR = GetCellStyleTop( nCol + 1, nRow );
1095             const Style& rRFromB = GetCellStyleRight( nCol, nRow );
1096             DiagStyle aRFromBL( GetCellStyleTR( nCol, nRow ), fAngle );
1097 
1098             // check if current frame border can be connected to cached frame border
1099             if( !CheckFrameBorderConnectable( *pStart, rCurr,
1100                     aEndRFromTL, rLFromT, aLFromTR, aEndRFromBL, rLFromB, aLFromBR ) )
1101             {
1102                 // draw previous frame border
1103                 Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() );
1104                 if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) )
1105                     DrawHorFrameBorder( rDev, aStartPos, aEndPos, *pStart,
1106                         aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR,
1107                         aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL, pForceColor );
1108 
1109                 // re-init "*Start***" variables
1110                 aStartPos = aEndPos;
1111                 pStart = &rCurr;
1112                 aStartLFromTR = aLFromTR;
1113                 pStartLFromT = &rLFromT;
1114                 pStartLFromL = &rLFromL;
1115                 pStartLFromB = &rLFromB;
1116                 aStartLFromBR = aLFromBR;
1117             }
1118 
1119             // store current styles in "*End***" variables
1120             aEndRFromTL = aRFromTL;
1121             pEndRFromT = &rRFromT;
1122             pEndRFromR = &rRFromR;
1123             pEndRFromB = &rRFromB;
1124             aEndRFromBL = aRFromBL;
1125         }
1126 
1127         // draw last frame border
1128         Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() );
1129         if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) )
1130             DrawHorFrameBorder( rDev, aStartPos, aEndPos, *pStart,
1131                 aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR,
1132                 aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL, pForceColor );
1133     }
1134 
1135     // *** vertical frame borders ***
1136 
1137     for( nCol = nFirstCol; nCol <= nLastCol + 1; ++nCol )
1138     {
1139         double fAngle = mxImpl->GetVerDiagAngle( nCol, nFirstRow );
1140         double fLAngle = mxImpl->GetVerDiagAngle( nCol - 1, nFirstRow );
1141 
1142         // *Start*** variables store the data of the top end of the cached frame border
1143         Point aStartPos( mxImpl->GetColPosition( nCol ), mxImpl->GetRowPosition( nFirstRow ) );
1144         const Style* pStart = &GetCellStyleLeft( nCol, nFirstRow );
1145         DiagStyle aStartTFromBL( GetCellStyleTR( nCol - 1, nFirstRow ), fLAngle );
1146         const Style* pStartTFromL = &GetCellStyleTop( nCol - 1, nFirstRow );
1147         const Style* pStartTFromT = &GetCellStyleLeft( nCol, nFirstRow - 1 );
1148         const Style* pStartTFromR = &GetCellStyleTop( nCol, nFirstRow );
1149         DiagStyle aStartTFromBR( GetCellStyleTL( nCol, nFirstRow ), fAngle );
1150 
1151         // *End*** variables store the data of the bottom end of the cached frame border
1152         DiagStyle aEndBFromTL( GetCellStyleBR( nCol - 1, nFirstRow ), fLAngle );
1153         const Style* pEndBFromL = &GetCellStyleBottom( nCol - 1, nFirstRow );
1154         const Style* pEndBFromB = &GetCellStyleLeft( nCol, nFirstRow + 1 );
1155         const Style* pEndBFromR = &GetCellStyleBottom( nCol, nFirstRow );
1156         DiagStyle aEndBFromTR( GetCellStyleBL( nCol, nFirstRow ), fAngle );
1157 
1158         for( nRow = nFirstRow + 1; nRow <= nLastRow; ++nRow )
1159         {
1160             fAngle = mxImpl->GetVerDiagAngle( nCol, nRow );
1161             fLAngle = mxImpl->GetVerDiagAngle( nCol - 1, nRow );
1162 
1163             const Style& rCurr = *pEndBFromB;
1164 
1165             DiagStyle aTFromBL( GetCellStyleTR( nCol - 1, nRow ), fLAngle );
1166             const Style& rTFromL = *pEndBFromL;
1167             const Style& rTFromT = *pStart;
1168             const Style& rTFromR = *pEndBFromR;
1169             DiagStyle aTFromBR( GetCellStyleTL( nCol, nRow ), fAngle );
1170 
1171             DiagStyle aBFromTL( GetCellStyleBR( nCol - 1, nRow ), fLAngle );
1172             const Style& rBFromL = GetCellStyleBottom( nCol - 1, nRow );
1173             const Style& rBFromB = GetCellStyleLeft( nCol, nRow + 1 );
1174             const Style& rBFromR = GetCellStyleBottom( nCol, nRow );
1175             DiagStyle aBFromTR( GetCellStyleBL( nCol, nRow ), fAngle );
1176 
1177             // check if current frame border can be connected to cached frame border
1178             if( !CheckFrameBorderConnectable( *pStart, rCurr,
1179                     aEndBFromTL, rTFromL, aTFromBL, aEndBFromTR, rTFromR, aTFromBR ) )
1180             {
1181                 // draw previous frame border
1182                 Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) );
1183                 if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) )
1184                     DrawVerFrameBorder( rDev, aStartPos, aEndPos, *pStart,
1185                         aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR,
1186                         aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR, pForceColor );
1187 
1188                 // re-init "*Start***" variables
1189                 aStartPos = aEndPos;
1190                 pStart = &rCurr;
1191                 aStartTFromBL = aTFromBL;
1192                 pStartTFromL = &rTFromL;
1193                 pStartTFromT = &rTFromT;
1194                 pStartTFromR = &rTFromR;
1195                 aStartTFromBR = aTFromBR;
1196             }
1197 
1198             // store current styles in "*End***" variables
1199             aEndBFromTL = aBFromTL;
1200             pEndBFromL = &rBFromL;
1201             pEndBFromB = &rBFromB;
1202             pEndBFromR = &rBFromR;
1203             aEndBFromTR = aBFromTR;
1204         }
1205 
1206         // draw last frame border
1207         Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) );
1208         if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) )
1209             DrawVerFrameBorder( rDev, aStartPos, aEndPos, *pStart,
1210                 aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR,
1211                 aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR, pForceColor );
1212     }
1213 }
1214 
DrawArray(OutputDevice & rDev,const Color * pForceColor) const1215 void Array::DrawArray( OutputDevice& rDev, const Color* pForceColor ) const
1216 {
1217     if( mxImpl->mnWidth && mxImpl->mnHeight )
1218         DrawRange( rDev, 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1, pForceColor );
1219 }
1220 
1221 // ----------------------------------------------------------------------------
1222 
1223 #undef ORIGCELLACC
1224 #undef ORIGCELL
1225 #undef CELLACC
1226 #undef CELL
1227 
1228 // ----------------------------------------------------------------------------
1229 
1230 #undef DBG_FRAME_CHECK_ROW_1
1231 #undef DBG_FRAME_CHECK_COL_1
1232 #undef DBG_FRAME_CHECK_INDEX
1233 #undef DBG_FRAME_CHECK_COLROW
1234 #undef DBG_FRAME_CHECK_ROW
1235 #undef DBG_FRAME_CHECK_COL
1236 #undef DBG_FRAME_CHECK
1237 #undef DBG_FRAME_ERROR
1238 
1239 // ============================================================================
1240 
1241 } // namespace frame
1242 } // namespace svx
1243 
1244