LibreOffice Module svx (master) 1
framelinkarray.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
21
22#include <math.h>
23#include <vector>
24#include <set>
25#include <unordered_set>
26#include <algorithm>
27#include <tools/debug.hxx>
28#include <tools/gen.hxx>
29#include <vcl/canvastools.hxx>
33// #include <basegfx/numeric/ftools.hxx>
34
35//#define OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
36#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
39#endif
40
41namespace svx::frame {
42
43namespace {
44
45class Cell
46{
47private:
54
55 basegfx::B2DHomMatrix HelperCreateB2DHomMatrixFromB2DRange(
56 const basegfx::B2DRange& rRange ) const;
57
58public:
59 sal_Int32 mnAddLeft;
60 sal_Int32 mnAddRight;
61 sal_Int32 mnAddTop;
62 sal_Int32 mnAddBottom;
63
66
70
71public:
72 explicit Cell();
73
74 void SetStyleLeft(const Style& rStyle) { maLeft = rStyle; }
75 void SetStyleRight(const Style& rStyle) { maRight = rStyle; }
76 void SetStyleTop(const Style& rStyle) { maTop = rStyle; }
77 void SetStyleBottom(const Style& rStyle) { maBottom = rStyle; }
78 void SetStyleTLBR(const Style& rStyle) { maTLBR = rStyle; }
79 void SetStyleBLTR(const Style& rStyle) { maBLTR = rStyle; }
80
81 const Style& GetStyleLeft() const { return maLeft; }
82 const Style& GetStyleRight() const { return maRight; }
83 const Style& GetStyleTop() const { return maTop; }
84 const Style& GetStyleBottom() const { return maBottom; }
85 const Style& GetStyleTLBR() const { return maTLBR; }
86 const Style& GetStyleBLTR() const { return maBLTR; }
87
88 bool IsMerged() const { return mbMergeOrig || mbOverlapX || mbOverlapY; }
89 bool IsRotated() const { return mfOrientation != 0.0; }
90
91 void MirrorSelfX();
92
93 basegfx::B2DHomMatrix CreateCoordinateSystemSingleCell(
94 const Array& rArray, sal_Int32 nCol, sal_Int32 nRow ) const;
95 basegfx::B2DHomMatrix CreateCoordinateSystemMergedCell(
96 const Array& rArray, sal_Int32 nColLeft, sal_Int32 nRowTop, sal_Int32 nColRight, sal_Int32 nRowBottom ) const;
97};
98
99}
100
101typedef std::vector< Cell > CellVec;
102
103basegfx::B2DHomMatrix Cell::HelperCreateB2DHomMatrixFromB2DRange(
104 const basegfx::B2DRange& rRange ) const
105{
106 if( rRange.isEmpty() )
107 return basegfx::B2DHomMatrix();
108
109 basegfx::B2DPoint aOrigin(rRange.getMinimum());
110 basegfx::B2DVector aX(rRange.getWidth(), 0.0);
111 basegfx::B2DVector aY(0.0, rRange.getHeight());
112
114 {
115 // tdf#143377 We need to limit applying Skew to geometry since the closer
116 // we get to 0.0 or PI the more sin(mfOrientation) will get to zero and the
117 // huger the Skew effect will be. For that, use an epsilon-radius of 1/2
118 // degree around the dangerous points 0.0 and PI.
119
120 // Snap to modulo to [0.0 .. 2PI[ to make compare easier
121 const double fSnapped(::basegfx::snapToZeroRange(mfOrientation, M_PI * 2.0));
122
123 // As a compromise, allow up to 1/2 degree
124 static const double fMinAng(M_PI/360.0);
125
126 // Check if Skew makes sense or would be too huge
127 const bool bForbidSkew(
128 fSnapped < fMinAng || // range [0.0 .. fMinAng]
129 fSnapped > (M_PI * 2.0) - fMinAng || // range [PI-fMinAng .. 2PI[
130 fabs(fSnapped - M_PI) < fMinAng); // range [PI-fMinAng .. PI+fMinAng]
131
132 if(!bForbidSkew)
133 {
134 // when rotated, adapt values. Get Skew (cos/sin == 1/tan)
135 const double fSkew(aY.getY() * (cos(mfOrientation) / sin(mfOrientation)));
136
137 switch (meRotMode)
138 {
140 // shear Y-Axis
141 aY.setX(-fSkew);
142 break;
144 // shear origin half, Y full
145 aOrigin.setX(aOrigin.getX() + (fSkew * 0.5));
146 aY.setX(-fSkew);
147 break;
149 // shear origin full, Y full
150 aOrigin.setX(aOrigin.getX() + fSkew);
151 aY.setX(-fSkew);
152 break;
153 default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, already excluded above
154 break;
155 }
156 }
157 }
158
159 // use column vectors as coordinate axes, homogen column for translation
160 return basegfx::utils::createCoordinateSystemTransform( aOrigin, aX, aY );
161}
162
163basegfx::B2DHomMatrix Cell::CreateCoordinateSystemSingleCell(
164 const Array& rArray, sal_Int32 nCol, sal_Int32 nRow) const
165{
166 const Point aPoint( rArray.GetColPosition( nCol ), rArray.GetRowPosition( nRow ) );
167 const Size aSize( rArray.GetColWidth( nCol, nCol ) + 1, rArray.GetRowHeight( nRow, nRow ) + 1 );
169
170 return HelperCreateB2DHomMatrixFromB2DRange( aRange );
171}
172
173basegfx::B2DHomMatrix Cell::CreateCoordinateSystemMergedCell(
174 const Array& rArray, sal_Int32 nColLeft, sal_Int32 nRowTop, sal_Int32 nColRight, sal_Int32 nRowBottom) const
175{
176 basegfx::B2DRange aRange( rArray.GetB2DRange(
177 nColLeft, nRowTop, nColRight, nRowBottom ) );
178
179 // adjust rectangle for partly visible merged cells
180 if( IsMerged() )
181 {
182 // not *sure* what exactly this is good for,
183 // it is just a hard set extension at merged cells,
184 // probably *should* be included in the above extended
185 // GetColPosition/GetColWidth already. This might be
186 // added due to GetColPosition/GetColWidth not working
187 // correctly over PageChanges (if used), but not sure.
188 aRange.expand(
190 aRange.getMinX() - mnAddLeft,
191 aRange.getMinY() - mnAddTop,
192 aRange.getMaxX() + mnAddRight,
193 aRange.getMaxY() + mnAddBottom ) );
194 }
195
196 return HelperCreateB2DHomMatrixFromB2DRange( aRange );
197}
198
199Cell::Cell() :
200 mnAddLeft( 0 ),
201 mnAddRight( 0 ),
202 mnAddTop( 0 ),
203 mnAddBottom( 0 ),
205 mfOrientation( 0.0 ),
206 mbMergeOrig( false ),
207 mbOverlapX( false ),
208 mbOverlapY( false )
209{
210}
211
212void Cell::MirrorSelfX()
213{
214 std::swap( maLeft, maRight );
215 std::swap( mnAddLeft, mnAddRight );
216 maLeft.MirrorSelf();
217 maRight.MirrorSelf();
219}
220
221
222static void lclRecalcCoordVec( std::vector<sal_Int32>& rCoords, const std::vector<sal_Int32>& rSizes )
223{
224 DBG_ASSERT( rCoords.size() == rSizes.size() + 1, "lclRecalcCoordVec - inconsistent vectors" );
225 auto aCIt = rCoords.begin();
226 for( const auto& rSize : rSizes )
227 {
228 *(aCIt + 1) = *aCIt + rSize;
229 ++aCIt;
230 }
231}
232
233static void lclSetMergedRange( CellVec& rCells, sal_Int32 nWidth, sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
234{
235 for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
236 {
237 for( sal_Int32 nRow = nFirstRow; nRow <= nLastRow; ++nRow )
238 {
239 Cell& rCell = rCells[ nRow * nWidth + nCol ];
240 rCell.mbMergeOrig = false;
241 rCell.mbOverlapX = nCol > nFirstCol;
242 rCell.mbOverlapY = nRow > nFirstRow;
243 }
244 }
245 rCells[ nFirstRow * nWidth + nFirstCol ].mbMergeOrig = true;
246}
247
248
251
253{
255 std::vector<sal_Int32> maWidths;
256 std::vector<sal_Int32> maHeights;
257 mutable std::vector<sal_Int32> maXCoords;
258 mutable std::vector<sal_Int32> maYCoords;
259 sal_Int32 mnWidth;
260 sal_Int32 mnHeight;
261 sal_Int32 mnFirstClipCol;
262 sal_Int32 mnFirstClipRow;
263 sal_Int32 mnLastClipCol;
264 sal_Int32 mnLastClipRow;
265 mutable bool mbXCoordsDirty;
266 mutable bool mbYCoordsDirty;
268
269 explicit ArrayImpl( sal_Int32 nWidth, sal_Int32 nHeight );
270
271 bool IsValidPos( sal_Int32 nCol, sal_Int32 nRow ) const
272 { return (nCol < mnWidth) && (nRow < mnHeight); }
273 sal_Int32 GetIndex( sal_Int32 nCol, sal_Int32 nRow ) const
274 { return nRow * mnWidth + nCol; }
275
276 const Cell& GetCell( sal_Int32 nCol, sal_Int32 nRow ) const;
277 Cell& GetCellAcc( sal_Int32 nCol, sal_Int32 nRow );
278
279 sal_Int32 GetMergedFirstCol( sal_Int32 nCol, sal_Int32 nRow ) const;
280 sal_Int32 GetMergedFirstRow( sal_Int32 nCol, sal_Int32 nRow ) const;
281 sal_Int32 GetMergedLastCol( sal_Int32 nCol, sal_Int32 nRow ) const;
282 sal_Int32 GetMergedLastRow( sal_Int32 nCol, sal_Int32 nRow ) const;
283
284 const Cell& GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const;
285 const Cell& GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const;
286
287 bool IsMergedOverlappedLeft( sal_Int32 nCol, sal_Int32 nRow ) const;
288 bool IsMergedOverlappedRight( sal_Int32 nCol, sal_Int32 nRow ) const;
289 bool IsMergedOverlappedTop( sal_Int32 nCol, sal_Int32 nRow ) const;
290 bool IsMergedOverlappedBottom( sal_Int32 nCol, sal_Int32 nRow ) const;
291
292 bool IsInClipRange( sal_Int32 nCol, sal_Int32 nRow ) const;
293 bool IsColInClipRange( sal_Int32 nCol ) const;
294 bool IsRowInClipRange( sal_Int32 nRow ) const;
295
296 bool OverlapsClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow ) const;
297
298 sal_Int32 GetMirrorCol( sal_Int32 nCol ) const { return mnWidth - nCol - 1; }
299
300 sal_Int32 GetColPosition( sal_Int32 nCol ) const;
301 sal_Int32 GetRowPosition( sal_Int32 nRow ) const;
302
303 bool HasCellRotation() const;
304};
305
306ArrayImpl::ArrayImpl( sal_Int32 nWidth, sal_Int32 nHeight ) :
307 mnWidth( nWidth ),
308 mnHeight( nHeight ),
309 mnFirstClipCol( 0 ),
310 mnFirstClipRow( 0 ),
311 mnLastClipCol( nWidth - 1 ),
312 mnLastClipRow( nHeight - 1 ),
313 mbXCoordsDirty( false ),
314 mbYCoordsDirty( false ),
315 mbMayHaveCellRotation( false )
316{
317 // default-construct all vectors
318 maCells.resize( mnWidth * mnHeight );
319 maWidths.resize( mnWidth, 0 );
320 maHeights.resize( mnHeight, 0 );
321 maXCoords.resize( mnWidth + 1, 0 );
322 maYCoords.resize( mnHeight + 1, 0 );
323}
324
325const Cell& ArrayImpl::GetCell( sal_Int32 nCol, sal_Int32 nRow ) const
326{
327 return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : OBJ_CELL_NONE;
328}
329
330Cell& ArrayImpl::GetCellAcc( sal_Int32 nCol, sal_Int32 nRow )
331{
332 static Cell aDummy;
333 return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : aDummy;
334}
335
336sal_Int32 ArrayImpl::GetMergedFirstCol( sal_Int32 nCol, sal_Int32 nRow ) const
337{
338 sal_Int32 nFirstCol = nCol;
339 while( (nFirstCol > 0) && GetCell( nFirstCol, nRow ).mbOverlapX ) --nFirstCol;
340 return nFirstCol;
341}
342
343sal_Int32 ArrayImpl::GetMergedFirstRow( sal_Int32 nCol, sal_Int32 nRow ) const
344{
345 sal_Int32 nFirstRow = nRow;
346 while( (nFirstRow > 0) && GetCell( nCol, nFirstRow ).mbOverlapY ) --nFirstRow;
347 return nFirstRow;
348}
349
350sal_Int32 ArrayImpl::GetMergedLastCol( sal_Int32 nCol, sal_Int32 nRow ) const
351{
352 sal_Int32 nLastCol = nCol + 1;
353 while( (nLastCol < mnWidth) && GetCell( nLastCol, nRow ).mbOverlapX ) ++nLastCol;
354 return nLastCol - 1;
355}
356
357sal_Int32 ArrayImpl::GetMergedLastRow( sal_Int32 nCol, sal_Int32 nRow ) const
358{
359 sal_Int32 nLastRow = nRow + 1;
360 while( (nLastRow < mnHeight) && GetCell( nCol, nLastRow ).mbOverlapY ) ++nLastRow;
361 return nLastRow - 1;
362}
363
364const Cell& ArrayImpl::GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const
365{
366 return GetCell( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) );
367}
368
369const Cell& ArrayImpl::GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const
370{
371 return GetCell( GetMergedLastCol( nCol, nRow ), GetMergedLastRow( nCol, nRow ) );
372}
373
374bool ArrayImpl::IsMergedOverlappedLeft( sal_Int32 nCol, sal_Int32 nRow ) const
375{
376 const Cell& rCell = GetCell( nCol, nRow );
377 return rCell.mbOverlapX || (rCell.mnAddLeft > 0);
378}
379
380bool ArrayImpl::IsMergedOverlappedRight( sal_Int32 nCol, sal_Int32 nRow ) const
381{
382 return GetCell( nCol + 1, nRow ).mbOverlapX || (GetCell( nCol, nRow ).mnAddRight > 0);
383}
384
385bool ArrayImpl::IsMergedOverlappedTop( sal_Int32 nCol, sal_Int32 nRow ) const
386{
387 const Cell& rCell = GetCell( nCol, nRow );
388 return rCell.mbOverlapY || (rCell.mnAddTop > 0);
389}
390
391bool ArrayImpl::IsMergedOverlappedBottom( sal_Int32 nCol, sal_Int32 nRow ) const
392{
393 return GetCell( nCol, nRow + 1 ).mbOverlapY || (GetCell( nCol, nRow ).mnAddBottom > 0);
394}
395
396bool ArrayImpl::IsColInClipRange( sal_Int32 nCol ) const
397{
398 return (mnFirstClipCol <= nCol) && (nCol <= mnLastClipCol);
399}
400
401bool ArrayImpl::IsRowInClipRange( sal_Int32 nRow ) const
402{
403 return (mnFirstClipRow <= nRow) && (nRow <= mnLastClipRow);
404}
405
406bool ArrayImpl::OverlapsClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow ) const
407{
408 if(nLastCol < mnFirstClipCol)
409 return false;
410
411 if(nFirstCol > mnLastClipCol)
412 return false;
413
414 if(nLastRow < mnFirstClipRow)
415 return false;
416
417 if(nFirstRow > mnLastClipRow)
418 return false;
419
420 return true;
421}
422
423bool ArrayImpl::IsInClipRange( sal_Int32 nCol, sal_Int32 nRow ) const
424{
425 return IsColInClipRange( nCol ) && IsRowInClipRange( nRow );
426}
427
428sal_Int32 ArrayImpl::GetColPosition( sal_Int32 nCol ) const
429{
430 if( mbXCoordsDirty )
431 {
433 mbXCoordsDirty = false;
434 }
435 return maXCoords[ nCol ];
436}
437
438sal_Int32 ArrayImpl::GetRowPosition( sal_Int32 nRow ) const
439{
440 if( mbYCoordsDirty )
441 {
443 mbYCoordsDirty = false;
444 }
445 return maYCoords[ nRow ];
446}
447
449{
450 // check cell array
451 for (const auto& aCell : maCells)
452 {
453 if (aCell.IsRotated())
454 {
455 return true;
456 }
457 }
458
459 return false;
460}
461
462namespace {
463
464class MergedCellIterator
465{
466public:
467 explicit MergedCellIterator( const Array& rArray, sal_Int32 nCol, sal_Int32 nRow );
468
469 bool Is() const { return (mnCol <= mnLastCol) && (mnRow <= mnLastRow); }
470 sal_Int32 Col() const { return mnCol; }
471 sal_Int32 Row() const { return mnRow; }
472
473 MergedCellIterator& operator++();
474
475private:
476 sal_Int32 mnFirstCol;
477 sal_Int32 mnFirstRow;
478 sal_Int32 mnLastCol;
479 sal_Int32 mnLastRow;
480 sal_Int32 mnCol;
481 sal_Int32 mnRow;
482};
483
484}
485
486MergedCellIterator::MergedCellIterator( const Array& rArray, sal_Int32 nCol, sal_Int32 nRow )
487{
488 DBG_ASSERT( rArray.IsMerged( nCol, nRow ), "svx::frame::MergedCellIterator::MergedCellIterator - not in merged range" );
489 rArray.GetMergedRange( mnFirstCol, mnFirstRow, mnLastCol, mnLastRow, nCol, nRow );
492}
493
494MergedCellIterator& MergedCellIterator::operator++()
495{
496 DBG_ASSERT( Is(), "svx::frame::MergedCellIterator::operator++() - already invalid" );
497 if( ++mnCol > mnLastCol )
498 {
500 ++mnRow;
501 }
502 return *this;
503}
504
505
506#define DBG_FRAME_CHECK( cond, funcname, error ) DBG_ASSERT( cond, "svx::frame::Array::" funcname " - " error )
507#define DBG_FRAME_CHECK_COL( col, funcname ) DBG_FRAME_CHECK( (col) < GetColCount(), funcname, "invalid column index" )
508#define DBG_FRAME_CHECK_ROW( row, funcname ) DBG_FRAME_CHECK( (row) < GetRowCount(), funcname, "invalid row index" )
509#define DBG_FRAME_CHECK_COLROW( col, row, funcname ) DBG_FRAME_CHECK( ((col) < GetColCount()) && ((row) < GetRowCount()), funcname, "invalid cell index" )
510#define DBG_FRAME_CHECK_COL_1( col, funcname ) DBG_FRAME_CHECK( (col) <= GetColCount(), funcname, "invalid column index" )
511#define DBG_FRAME_CHECK_ROW_1( row, funcname ) DBG_FRAME_CHECK( (row) <= GetRowCount(), funcname, "invalid row index" )
512
513
514#define CELL( col, row ) mxImpl->GetCell( col, row )
515#define CELLACC( col, row ) mxImpl->GetCellAcc( col, row )
516#define ORIGCELL( col, row ) mxImpl->GetMergedOriginCell( col, row )
517#define LASTCELL( col, row ) mxImpl->GetMergedLastCell( col, row )
518
519
521{
522 Initialize( 0, 0 );
523}
524
526{
527}
528
529// array size and column/row indexes
530void Array::Initialize( sal_Int32 nWidth, sal_Int32 nHeight )
531{
532 mxImpl.reset( new ArrayImpl( nWidth, nHeight ) );
533}
534
535sal_Int32 Array::GetColCount() const
536{
537 return mxImpl->mnWidth;
538}
539
540sal_Int32 Array::GetRowCount() const
541{
542 return mxImpl->mnHeight;
543}
544
545sal_Int32 Array::GetCellCount() const
546{
547 return mxImpl->maCells.size();
548}
549
550sal_Int32 Array::GetCellIndex( sal_Int32 nCol, sal_Int32 nRow, bool bRTL ) const
551{
552 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetCellIndex" );
553 if (bRTL)
554 nCol = mxImpl->GetMirrorCol(nCol);
555 return mxImpl->GetIndex( nCol, nRow );
556}
557
558// cell border styles
559void Array::SetCellStyleLeft( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
560{
561 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleLeft" );
562 CELLACC( nCol, nRow ).SetStyleLeft(rStyle);
563}
564
565void Array::SetCellStyleRight( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
566{
567 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleRight" );
568 CELLACC( nCol, nRow ).SetStyleRight(rStyle);
569}
570
571void Array::SetCellStyleTop( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
572{
573 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTop" );
574 CELLACC( nCol, nRow ).SetStyleTop(rStyle);
575}
576
577void Array::SetCellStyleBottom( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
578{
579 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBottom" );
580 CELLACC( nCol, nRow ).SetStyleBottom(rStyle);
581}
582
583void Array::SetCellStyleTLBR( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
584{
585 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTLBR" );
586 CELLACC( nCol, nRow ).SetStyleTLBR(rStyle);
587}
588
589void Array::SetCellStyleBLTR( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
590{
591 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBLTR" );
592 CELLACC( nCol, nRow ).SetStyleBLTR(rStyle);
593}
594
595void Array::SetCellStyleDiag( sal_Int32 nCol, sal_Int32 nRow, const Style& rTLBR, const Style& rBLTR )
596{
597 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleDiag" );
598 Cell& rCell = CELLACC( nCol, nRow );
599 rCell.SetStyleTLBR(rTLBR);
600 rCell.SetStyleBLTR(rBLTR);
601}
602
603void Array::SetColumnStyleLeft( sal_Int32 nCol, const Style& rStyle )
604{
605 DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleLeft" );
606 for( sal_Int32 nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
607 SetCellStyleLeft( nCol, nRow, rStyle );
608}
609
610void Array::SetColumnStyleRight( sal_Int32 nCol, const Style& rStyle )
611{
612 DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleRight" );
613 for( sal_Int32 nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
614 SetCellStyleRight( nCol, nRow, rStyle );
615}
616
617void Array::SetRowStyleTop( sal_Int32 nRow, const Style& rStyle )
618{
619 DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleTop" );
620 for( sal_Int32 nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
621 SetCellStyleTop( nCol, nRow, rStyle );
622}
623
624void Array::SetRowStyleBottom( sal_Int32 nRow, const Style& rStyle )
625{
626 DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleBottom" );
627 for( sal_Int32 nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
628 SetCellStyleBottom( nCol, nRow, rStyle );
629}
630
631void Array::SetCellRotation(sal_Int32 nCol, sal_Int32 nRow, SvxRotateMode eRotMode, double fOrientation)
632{
633 DBG_FRAME_CHECK_COLROW(nCol, nRow, "SetCellRotation");
634 Cell& rTarget = CELLACC(nCol, nRow);
635 rTarget.meRotMode = eRotMode;
636 rTarget.mfOrientation = fOrientation;
637
638 if (!mxImpl->mbMayHaveCellRotation)
639 {
640 // activate once when a cell gets actually rotated to allow fast
641 // answering HasCellRotation() calls
642 mxImpl->mbMayHaveCellRotation = rTarget.IsRotated();
643 }
644}
645
647{
648 if (!mxImpl->mbMayHaveCellRotation)
649 {
650 // never set, no need to check
651 return false;
652 }
653
654 return mxImpl->HasCellRotation();
655}
656
657const Style& Array::GetCellStyleLeft( sal_Int32 nCol, sal_Int32 nRow ) const
658{
659 // outside clipping rows or overlapped in merged cells: invisible
660 if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedLeft( nCol, nRow ) )
661 return OBJ_STYLE_NONE;
662 // left clipping border: always own left style
663 if( nCol == mxImpl->mnFirstClipCol )
664 return ORIGCELL( nCol, nRow ).GetStyleLeft();
665 // right clipping border: always right style of left neighbor cell
666 if( nCol == mxImpl->mnLastClipCol + 1 )
667 return ORIGCELL( nCol - 1, nRow ).GetStyleRight();
668 // outside clipping columns: invisible
669 if( !mxImpl->IsColInClipRange( nCol ) )
670 return OBJ_STYLE_NONE;
671 // inside clipping range: maximum of own left style and right style of left neighbor cell
672 return std::max( ORIGCELL( nCol, nRow ).GetStyleLeft(), ORIGCELL( nCol - 1, nRow ).GetStyleRight() );
673}
674
675const Style& Array::GetCellStyleRight( sal_Int32 nCol, sal_Int32 nRow ) const
676{
677 // outside clipping rows or overlapped in merged cells: invisible
678 if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedRight( nCol, nRow ) )
679 return OBJ_STYLE_NONE;
680 // left clipping border: always left style of right neighbor cell
681 if( nCol + 1 == mxImpl->mnFirstClipCol )
682 return ORIGCELL( nCol + 1, nRow ).GetStyleLeft();
683 // right clipping border: always own right style
684 if( nCol == mxImpl->mnLastClipCol )
685 return LASTCELL( nCol, nRow ).GetStyleRight();
686 // outside clipping columns: invisible
687 if( !mxImpl->IsColInClipRange( nCol ) )
688 return OBJ_STYLE_NONE;
689 // inside clipping range: maximum of own right style and left style of right neighbor cell
690 return std::max( ORIGCELL( nCol, nRow ).GetStyleRight(), ORIGCELL( nCol + 1, nRow ).GetStyleLeft() );
691}
692
693const Style& Array::GetCellStyleTop( sal_Int32 nCol, sal_Int32 nRow ) const
694{
695 // outside clipping columns or overlapped in merged cells: invisible
696 if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedTop( nCol, nRow ) )
697 return OBJ_STYLE_NONE;
698 // top clipping border: always own top style
699 if( nRow == mxImpl->mnFirstClipRow )
700 return ORIGCELL( nCol, nRow ).GetStyleTop();
701 // bottom clipping border: always bottom style of top neighbor cell
702 if( nRow == mxImpl->mnLastClipRow + 1 )
703 return ORIGCELL( nCol, nRow - 1 ).GetStyleBottom();
704 // outside clipping rows: invisible
705 if( !mxImpl->IsRowInClipRange( nRow ) )
706 return OBJ_STYLE_NONE;
707 // inside clipping range: maximum of own top style and bottom style of top neighbor cell
708 return std::max( ORIGCELL( nCol, nRow ).GetStyleTop(), ORIGCELL( nCol, nRow - 1 ).GetStyleBottom() );
709}
710
711const Style& Array::GetCellStyleBottom( sal_Int32 nCol, sal_Int32 nRow ) const
712{
713 // outside clipping columns or overlapped in merged cells: invisible
714 if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedBottom( nCol, nRow ) )
715 return OBJ_STYLE_NONE;
716 // top clipping border: always top style of bottom neighbor cell
717 if( nRow + 1 == mxImpl->mnFirstClipRow )
718 return ORIGCELL( nCol, nRow + 1 ).GetStyleTop();
719 // bottom clipping border: always own bottom style
720 if( nRow == mxImpl->mnLastClipRow )
721 return LASTCELL( nCol, nRow ).GetStyleBottom();
722 // outside clipping rows: invisible
723 if( !mxImpl->IsRowInClipRange( nRow ) )
724 return OBJ_STYLE_NONE;
725 // inside clipping range: maximum of own bottom style and top style of bottom neighbor cell
726 return std::max( ORIGCELL( nCol, nRow ).GetStyleBottom(), ORIGCELL( nCol, nRow + 1 ).GetStyleTop() );
727}
728
729const Style& Array::GetCellStyleTLBR( sal_Int32 nCol, sal_Int32 nRow ) const
730{
731 return CELL( nCol, nRow ).GetStyleTLBR();
732}
733
734const Style& Array::GetCellStyleBLTR( sal_Int32 nCol, sal_Int32 nRow ) const
735{
736 return CELL( nCol, nRow ).GetStyleBLTR();
737}
738
739const Style& Array::GetCellStyleTL( sal_Int32 nCol, sal_Int32 nRow ) const
740{
741 // not in clipping range: always invisible
742 if( !mxImpl->IsInClipRange( nCol, nRow ) )
743 return OBJ_STYLE_NONE;
744 // return style only for top-left cell
745 sal_Int32 nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
746 sal_Int32 nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
747 return ((nCol == nFirstCol) && (nRow == nFirstRow)) ?
748 CELL( nFirstCol, nFirstRow ).GetStyleTLBR() : OBJ_STYLE_NONE;
749}
750
751const Style& Array::GetCellStyleBR( sal_Int32 nCol, sal_Int32 nRow ) const
752{
753 // not in clipping range: always invisible
754 if( !mxImpl->IsInClipRange( nCol, nRow ) )
755 return OBJ_STYLE_NONE;
756 // return style only for bottom-right cell
757 sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
758 sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
759 return ((nCol == nLastCol) && (nRow == nLastRow)) ?
760 CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), mxImpl->GetMergedFirstRow( nCol, nRow ) ).GetStyleTLBR() : OBJ_STYLE_NONE;
761}
762
763const Style& Array::GetCellStyleBL( sal_Int32 nCol, sal_Int32 nRow ) const
764{
765 // not in clipping range: always invisible
766 if( !mxImpl->IsInClipRange( nCol, nRow ) )
767 return OBJ_STYLE_NONE;
768 // return style only for bottom-left cell
769 sal_Int32 nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
770 sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
771 return ((nCol == nFirstCol) && (nRow == nLastRow)) ?
772 CELL( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) ).GetStyleBLTR() : OBJ_STYLE_NONE;
773}
774
775const Style& Array::GetCellStyleTR( sal_Int32 nCol, sal_Int32 nRow ) const
776{
777 // not in clipping range: always invisible
778 if( !mxImpl->IsInClipRange( nCol, nRow ) )
779 return OBJ_STYLE_NONE;
780 // return style only for top-right cell
781 sal_Int32 nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
782 sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
783 return ((nCol == nLastCol) && (nRow == nFirstRow)) ?
784 CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), nFirstRow ).GetStyleBLTR() : OBJ_STYLE_NONE;
785}
786
787// cell merging
788void Array::SetMergedRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
789{
790 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetMergedRange" );
791 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetMergedRange" );
792#if OSL_DEBUG_LEVEL >= 2
793 {
794 bool bFound = false;
795 for( sal_Int32 nCurrCol = nFirstCol; !bFound && (nCurrCol <= nLastCol); ++nCurrCol )
796 for( sal_Int32 nCurrRow = nFirstRow; !bFound && (nCurrRow <= nLastRow); ++nCurrRow )
797 bFound = CELL( nCurrCol, nCurrRow ).IsMerged();
798 DBG_FRAME_CHECK( !bFound, "SetMergedRange", "overlapping merged ranges" );
799 }
800#endif
801 if( mxImpl->IsValidPos( nFirstCol, nFirstRow ) && mxImpl->IsValidPos( nLastCol, nLastRow ) )
802 lclSetMergedRange( mxImpl->maCells, mxImpl->mnWidth, nFirstCol, nFirstRow, nLastCol, nLastRow );
803}
804
805void Array::SetAddMergedLeftSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
806{
807 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedLeftSize" );
808 DBG_FRAME_CHECK( mxImpl->GetMergedFirstCol( nCol, nRow ) == 0, "SetAddMergedLeftSize", "additional border inside array" );
809 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
810 CELLACC( aIt.Col(), aIt.Row() ).mnAddLeft = nAddSize;
811}
812
813void Array::SetAddMergedRightSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
814{
815 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedRightSize" );
816 DBG_FRAME_CHECK( mxImpl->GetMergedLastCol( nCol, nRow ) + 1 == mxImpl->mnWidth, "SetAddMergedRightSize", "additional border inside array" );
817 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
818 CELLACC( aIt.Col(), aIt.Row() ).mnAddRight = nAddSize;
819}
820
821void Array::SetAddMergedTopSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
822{
823 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedTopSize" );
824 DBG_FRAME_CHECK( mxImpl->GetMergedFirstRow( nCol, nRow ) == 0, "SetAddMergedTopSize", "additional border inside array" );
825 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
826 CELLACC( aIt.Col(), aIt.Row() ).mnAddTop = nAddSize;
827}
828
829void Array::SetAddMergedBottomSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
830{
831 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedBottomSize" );
832 DBG_FRAME_CHECK( mxImpl->GetMergedLastRow( nCol, nRow ) + 1 == mxImpl->mnHeight, "SetAddMergedBottomSize", "additional border inside array" );
833 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
834 CELLACC( aIt.Col(), aIt.Row() ).mnAddBottom = nAddSize;
835}
836
837bool Array::IsMerged( sal_Int32 nCol, sal_Int32 nRow ) const
838{
839 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMerged" );
840 return CELL( nCol, nRow ).IsMerged();
841}
842
843void Array::GetMergedOrigin( sal_Int32& rnFirstCol, sal_Int32& rnFirstRow, sal_Int32 nCol, sal_Int32 nRow ) const
844{
845 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetMergedOrigin" );
846 rnFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
847 rnFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
848}
849
850void Array::GetMergedRange( sal_Int32& rnFirstCol, sal_Int32& rnFirstRow,
851 sal_Int32& rnLastCol, sal_Int32& rnLastRow, sal_Int32 nCol, sal_Int32 nRow ) const
852{
853 GetMergedOrigin( rnFirstCol, rnFirstRow, nCol, nRow );
854 rnLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
855 rnLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
856}
857
858// clipping
859void Array::SetClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
860{
861 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetClipRange" );
862 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetClipRange" );
863 mxImpl->mnFirstClipCol = nFirstCol;
864 mxImpl->mnFirstClipRow = nFirstRow;
865 mxImpl->mnLastClipCol = nLastCol;
866 mxImpl->mnLastClipRow = nLastRow;
867}
868
869// cell coordinates
870void Array::SetXOffset( sal_Int32 nXOffset )
871{
872 mxImpl->maXCoords[ 0 ] = nXOffset;
873 mxImpl->mbXCoordsDirty = true;
874}
875
876void Array::SetYOffset( sal_Int32 nYOffset )
877{
878 mxImpl->maYCoords[ 0 ] = nYOffset;
879 mxImpl->mbYCoordsDirty = true;
880}
881
882void Array::SetColWidth( sal_Int32 nCol, sal_Int32 nWidth )
883{
884 DBG_FRAME_CHECK_COL( nCol, "SetColWidth" );
885 mxImpl->maWidths[ nCol ] = nWidth;
886 mxImpl->mbXCoordsDirty = true;
887}
888
889void Array::SetRowHeight( sal_Int32 nRow, sal_Int32 nHeight )
890{
891 DBG_FRAME_CHECK_ROW( nRow, "SetRowHeight" );
892 mxImpl->maHeights[ nRow ] = nHeight;
893 mxImpl->mbYCoordsDirty = true;
894}
895
896void Array::SetAllColWidths( sal_Int32 nWidth )
897{
898 std::fill( mxImpl->maWidths.begin(), mxImpl->maWidths.end(), nWidth );
899 mxImpl->mbXCoordsDirty = true;
900}
901
902void Array::SetAllRowHeights( sal_Int32 nHeight )
903{
904 std::fill( mxImpl->maHeights.begin(), mxImpl->maHeights.end(), nHeight );
905 mxImpl->mbYCoordsDirty = true;
906}
907
908sal_Int32 Array::GetColPosition( sal_Int32 nCol ) const
909{
910 DBG_FRAME_CHECK_COL_1( nCol, "GetColPosition" );
911 return mxImpl->GetColPosition( nCol );
912}
913
914sal_Int32 Array::GetRowPosition( sal_Int32 nRow ) const
915{
916 DBG_FRAME_CHECK_ROW_1( nRow, "GetRowPosition" );
917 return mxImpl->GetRowPosition( nRow );
918}
919
920sal_Int32 Array::GetColWidth( sal_Int32 nFirstCol, sal_Int32 nLastCol ) const
921{
922 DBG_FRAME_CHECK_COL( nFirstCol, "GetColWidth" );
923 DBG_FRAME_CHECK_COL( nLastCol, "GetColWidth" );
924 return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol );
925}
926
927sal_Int32 Array::GetRowHeight( sal_Int32 nFirstRow, sal_Int32 nLastRow ) const
928{
929 DBG_FRAME_CHECK_ROW( nFirstRow, "GetRowHeight" );
930 DBG_FRAME_CHECK_ROW( nLastRow, "GetRowHeight" );
931 return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow );
932}
933
934sal_Int32 Array::GetWidth() const
935{
936 return GetColPosition( mxImpl->mnWidth ) - GetColPosition( 0 );
937}
938
939sal_Int32 Array::GetHeight() const
940{
941 return GetRowPosition( mxImpl->mnHeight ) - GetRowPosition( 0 );
942}
943
944basegfx::B2DRange Array::GetCellRange( sal_Int32 nCol, sal_Int32 nRow ) const
945{
946 // get the Range of the fully expanded cell (if merged)
947 const sal_Int32 nFirstCol(mxImpl->GetMergedFirstCol( nCol, nRow ));
948 const sal_Int32 nFirstRow(mxImpl->GetMergedFirstRow( nCol, nRow ));
949 const sal_Int32 nLastCol(mxImpl->GetMergedLastCol( nCol, nRow ));
950 const sal_Int32 nLastRow(mxImpl->GetMergedLastRow( nCol, nRow ));
951 const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) );
952 const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 );
953 tools::Rectangle aRect(aPoint, aSize);
954
955 // adjust rectangle for partly visible merged cells
956 const Cell& rCell = CELL( nCol, nRow );
957
958 if( rCell.IsMerged() )
959 {
960 // not *sure* what exactly this is good for,
961 // it is just a hard set extension at merged cells,
962 // probably *should* be included in the above extended
963 // GetColPosition/GetColWidth already. This might be
964 // added due to GetColPosition/GetColWidth not working
965 // correctly over PageChanges (if used), but not sure.
966 aRect.AdjustLeft( -(rCell.mnAddLeft) );
967 aRect.AdjustRight(rCell.mnAddRight );
968 aRect.AdjustTop( -(rCell.mnAddTop) );
969 aRect.AdjustBottom(rCell.mnAddBottom );
970 }
971
973}
974
975// return output range of given row/col range in logical coordinates
976basegfx::B2DRange Array::GetB2DRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow) const
977{
978 const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) );
979 const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 );
980
982}
983
984// mirroring
986{
987 CellVec aNewCells;
988 aNewCells.reserve( GetCellCount() );
989
990 sal_Int32 nCol, nRow;
991 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
992 {
993 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
994 {
995 aNewCells.push_back( CELL( mxImpl->GetMirrorCol( nCol ), nRow ) );
996 aNewCells.back().MirrorSelfX();
997 }
998 }
999 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
1000 {
1001 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
1002 {
1003 if( CELL( nCol, nRow ).mbMergeOrig )
1004 {
1005 sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
1006 sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
1007 lclSetMergedRange( aNewCells, mxImpl->mnWidth,
1008 mxImpl->GetMirrorCol( nLastCol ), nRow,
1009 mxImpl->GetMirrorCol( nCol ), nLastRow );
1010 }
1011 }
1012 }
1013 mxImpl->maCells.swap( aNewCells );
1014
1015 std::reverse( mxImpl->maWidths.begin(), mxImpl->maWidths.end() );
1016 mxImpl->mbXCoordsDirty = true;
1017}
1018
1019// drawing
1021 const Array& rArray,
1022 const Style& rStyle,
1023 sal_Int32 col,
1024 sal_Int32 row,
1025 const basegfx::B2DPoint& rOrigin,
1026 const basegfx::B2DVector& rX,
1027 const basegfx::B2DVector& rY,
1029 bool bUpper,
1030 const Color* pForceColor)
1031{
1032 // prepare SdrFrameBorderData
1033 rData.emplace_back(
1034 bUpper ? rOrigin : basegfx::B2DPoint(rOrigin + rY),
1035 rX,
1036 rStyle,
1037 pForceColor);
1038 drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
1039
1040 // get involved styles at start
1041 const Style& rStartFromTR(rArray.GetCellStyleBL( col, row - 1 ));
1042 const Style& rStartLFromT(rArray.GetCellStyleLeft( col, row - 1 ));
1043 const Style& rStartLFromL(rArray.GetCellStyleTop( col - 1, row ));
1044 const Style& rStartLFromB(rArray.GetCellStyleLeft( col, row ));
1045 const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
1046
1047 rInstance.addSdrConnectStyleData(true, rStartFromTR, rX - rY, false);
1048 rInstance.addSdrConnectStyleData(true, rStartLFromT, -rY, true);
1049 rInstance.addSdrConnectStyleData(true, rStartLFromL, -rX, true);
1050 rInstance.addSdrConnectStyleData(true, rStartLFromB, rY, false);
1051 rInstance.addSdrConnectStyleData(true, rStartFromBR, rX + rY, false);
1052
1053 // get involved styles at end
1054 const Style& rEndFromTL(rArray.GetCellStyleBR( col, row - 1 ));
1055 const Style& rEndRFromT(rArray.GetCellStyleRight( col, row - 1 ));
1056 const Style& rEndRFromR(rArray.GetCellStyleTop( col + 1, row ));
1057 const Style& rEndRFromB(rArray.GetCellStyleRight( col, row ));
1058 const Style& rEndFromBL(rArray.GetCellStyleTR( col, row ));
1059
1060 rInstance.addSdrConnectStyleData(false, rEndFromTL, -rX - rY, true);
1061 rInstance.addSdrConnectStyleData(false, rEndRFromT, -rY, true);
1062 rInstance.addSdrConnectStyleData(false, rEndRFromR, rX, false);
1063 rInstance.addSdrConnectStyleData(false, rEndRFromB, rY, false);
1064 rInstance.addSdrConnectStyleData(false, rEndFromBL, rY - rX, true);
1065}
1066
1068 const Array& rArray,
1069 const Style& rStyle,
1070 sal_Int32 col,
1071 sal_Int32 row,
1072 const basegfx::B2DPoint& rOrigin,
1073 const basegfx::B2DVector& rX,
1074 const basegfx::B2DVector& rY,
1076 bool bLeft,
1077 const Color* pForceColor)
1078{
1079 // prepare SdrFrameBorderData
1080 rData.emplace_back(
1081 bLeft ? rOrigin : basegfx::B2DPoint(rOrigin + rX),
1082 rY,
1083 rStyle,
1084 pForceColor);
1085 drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
1086
1087 // get involved styles at start
1088 const Style& rStartFromBL(rArray.GetCellStyleTR( col - 1, row ));
1089 const Style& rStartTFromL(rArray.GetCellStyleTop( col - 1, row ));
1090 const Style& rStartTFromT(rArray.GetCellStyleLeft( col, row - 1 ));
1091 const Style& rStartTFromR(rArray.GetCellStyleTop( col, row ));
1092 const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
1093
1094 rInstance.addSdrConnectStyleData(true, rStartFromBR, rX + rY, false);
1095 rInstance.addSdrConnectStyleData(true, rStartTFromR, rX, false);
1096 rInstance.addSdrConnectStyleData(true, rStartTFromT, -rY, true);
1097 rInstance.addSdrConnectStyleData(true, rStartTFromL, -rX, true);
1098 rInstance.addSdrConnectStyleData(true, rStartFromBL, rY - rX, true);
1099
1100 // get involved styles at end
1101 const Style& rEndFromTL(rArray.GetCellStyleBR( col - 1, row ));
1102 const Style& rEndBFromL(rArray.GetCellStyleBottom( col - 1, row ));
1103 const Style& rEndBFromB(rArray.GetCellStyleLeft( col, row + 1 ));
1104 const Style& rEndBFromR(rArray.GetCellStyleBottom( col, row ));
1105 const Style& rEndFromTR(rArray.GetCellStyleBL( col, row ));
1106
1107 rInstance.addSdrConnectStyleData(false, rEndFromTR, rX - rY, false);
1108 rInstance.addSdrConnectStyleData(false, rEndBFromR, rX, false);
1109 rInstance.addSdrConnectStyleData(false, rEndBFromB, rY, false);
1110 rInstance.addSdrConnectStyleData(false, rEndBFromL, -rX, true);
1111 rInstance.addSdrConnectStyleData(false, rEndFromTL, -rY - rX, true);
1112}
1113
1114static void HelperClipLine(
1115 basegfx::B2DPoint& rStart,
1116 basegfx::B2DVector& rDirection,
1117 const basegfx::B2DRange& rClipRange)
1118{
1119 basegfx::B2DPolygon aLine({rStart, rStart + rDirection});
1120 const basegfx::B2DPolyPolygon aResultPP(
1122 aLine,
1123 rClipRange,
1124 true, // bInside
1125 true)); // bStroke
1126
1127 if(aResultPP.count() > 0)
1128 {
1129 const basegfx::B2DPolygon aResultP(aResultPP.getB2DPolygon(0));
1130
1131 if(aResultP.count() > 0)
1132 {
1133 const basegfx::B2DPoint aResultStart(aResultP.getB2DPoint(0));
1134 const basegfx::B2DPoint aResultEnd(aResultP.getB2DPoint(aResultP.count() - 1));
1135
1136 if(aResultStart != aResultEnd)
1137 {
1138 rStart = aResultStart;
1139 rDirection = aResultEnd - aResultStart;
1140 }
1141 }
1142 }
1143}
1144
1146 const Array& rArray,
1147 const Style& rStyle,
1149 const basegfx::B2DPoint& rOrigin,
1150 const basegfx::B2DVector& rX,
1151 const basegfx::B2DVector& rY,
1152 sal_Int32 nColLeft,
1153 sal_Int32 nColRight,
1154 sal_Int32 nRowTop,
1155 sal_Int32 nRowBottom,
1156 const Color* pForceColor,
1157 const basegfx::B2DRange* pClipRange)
1158{
1159 if(rStyle.IsUsed())
1160 {
1162 basegfx::B2DPoint aStart(rOrigin);
1164
1166 if(nullptr != pClipRange)
1167 {
1168 HelperClipLine(aStart, aDirection, *pClipRange);
1169 }
1170
1172 rData.emplace_back(
1173 aStart,
1174 aDirection,
1175 rStyle,
1176 pForceColor);
1177 drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
1178
1180 const Style& rTLFromRight(rArray.GetCellStyleTop(nColLeft, nRowTop));
1181 const Style& rTLFromBottom(rArray.GetCellStyleLeft(nColLeft, nRowTop));
1182
1183 rInstance.addSdrConnectStyleData(true, rTLFromRight, rX, false);
1184 rInstance.addSdrConnectStyleData(true, rTLFromBottom, rY, false);
1185
1187 const Style& rBRFromBottom(rArray.GetCellStyleRight(nColRight, nRowBottom));
1188 const Style& rBRFromLeft(rArray.GetCellStyleBottom(nColRight, nRowBottom));
1189
1190 rInstance.addSdrConnectStyleData(false, rBRFromBottom, -rY, true);
1191 rInstance.addSdrConnectStyleData(false, rBRFromLeft, -rX, true);
1192 }
1193}
1194
1196 const Array& rArray,
1197 const Style& rStyle,
1199 const basegfx::B2DPoint& rOrigin,
1200 const basegfx::B2DVector& rX,
1201 const basegfx::B2DVector& rY,
1202 sal_Int32 nColLeft,
1203 sal_Int32 nColRight,
1204 sal_Int32 nRowTop,
1205 sal_Int32 nRowBottom,
1206 const Color* pForceColor,
1207 const basegfx::B2DRange* pClipRange)
1208{
1209 if(rStyle.IsUsed())
1210 {
1212 basegfx::B2DPoint aStart(rOrigin + rY);
1214
1216 if(nullptr != pClipRange)
1217 {
1218 HelperClipLine(aStart, aDirection, *pClipRange);
1219 }
1220
1222 rData.emplace_back(
1223 aStart,
1224 aDirection,
1225 rStyle,
1226 pForceColor);
1227 drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
1228
1230 const Style& rBLFromTop(rArray.GetCellStyleLeft(nColLeft, nRowBottom));
1231 const Style& rBLFromBottom(rArray.GetCellStyleBottom(nColLeft, nRowBottom));
1232
1233 rInstance.addSdrConnectStyleData(true, rBLFromTop, -rY, true);
1234 rInstance.addSdrConnectStyleData(true, rBLFromBottom, rX, false);
1235
1237 const Style& rTRFromLeft(rArray.GetCellStyleTop(nColRight, nRowTop));
1238 const Style& rTRFromBottom(rArray.GetCellStyleRight(nColRight, nRowTop));
1239
1240 rInstance.addSdrConnectStyleData(false, rTRFromLeft, -rX, true);
1241 rInstance.addSdrConnectStyleData(false, rTRFromBottom, rY, false);
1242 }
1243}
1244
1246 sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow,
1247 const Color* pForceColor ) const
1248{
1249 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "CreateB2DPrimitiveRange" );
1250 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "CreateB2DPrimitiveRange" );
1251
1252#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
1253 std::vector<basegfx::B2DRange> aClipRanges;
1254#endif
1255
1256 // It may be necessary to extend the loop ranges by one cell to the outside,
1257 // when possible. This is needed e.g. when there is in Calc a Cell with an
1258 // upper CellBorder using DoubleLine and that is right/left connected upwards
1259 // to also DoubleLine. These upper DoubleLines will be extended to meet the
1260 // lower of the upper CellBorder and thus have graphical parts that are
1261 // displayed one cell below and right/left of the target cell - analog to
1262 // other examples in all other directions.
1263 // It would be possible to explicitly test this (if possible by indices at all)
1264 // looping and testing the styles in the outer cells to detect this, but since
1265 // for other usages (e.g. UI) usually nFirstRow==0 and nLastRow==GetRowCount()-1
1266 // (and analog for Col) it is okay to just expand the range when available.
1267 // Do *not* change nFirstRow/nLastRow due to these needed to the boolean tests
1268 // below (!)
1269 // Checked usages, this method is used in Calc EditView/Print/Export stuff and
1270 // in UI (Dialog), not for Writer Tables and Draw/Impress tables. All usages
1271 // seem okay with this change, so I will add it.
1272 const sal_Int32 nStartRow(nFirstRow > 0 ? nFirstRow - 1 : nFirstRow);
1273 const sal_Int32 nEndRow(nLastRow < GetRowCount() - 1 ? nLastRow + 1 : nLastRow);
1274 const sal_Int32 nStartCol(nFirstCol > 0 ? nFirstCol - 1 : nFirstCol);
1275 const sal_Int32 nEndCol(nLastCol < GetColCount() - 1 ? nLastCol + 1 : nLastCol);
1276
1277 // prepare SdrFrameBorderDataVector
1279
1280 // remember for which merged cells crossed lines were already created. To
1281 // do so, hold the sal_Int32 cell index in a set for fast check
1282 std::unordered_set< sal_Int32 > aMergedCells;
1283
1284 for (sal_Int32 nRow(nStartRow); nRow <= nEndRow; ++nRow)
1285 {
1286 for (sal_Int32 nCol(nStartCol); nCol <= nEndCol; ++nCol)
1287 {
1288 // get Cell and CoordinateSystem (*only* for this Cell, do *not* expand for
1289 // merged cells (!)), check if used (non-empty vectors)
1290 const Cell& rCell(CELL(nCol, nRow));
1291 basegfx::B2DHomMatrix aCoordinateSystem(rCell.CreateCoordinateSystemSingleCell(*this, nCol, nRow));
1292 basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0));
1293 basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1));
1294
1295 // get needed local values
1296 basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2));
1297 const bool bOverlapX(rCell.mbOverlapX);
1298 const bool bFirstCol(nCol == nFirstCol);
1299
1300 // handle rotation: If cell is rotated, handle lower/right edge inside
1301 // this local geometry due to the created CoordinateSystem already representing
1302 // the needed transformations.
1303 const bool bRotated(rCell.IsRotated());
1304
1305 // Additionally avoid double-handling by suppressing handling when self not rotated,
1306 // but above/left is rotated and thus already handled. Two directly connected
1307 // rotated will paint/create both edges, they might be rotated differently.
1308 const bool bSuppressLeft(!bRotated && nCol > nFirstCol && CELL(nCol - 1, nRow).IsRotated());
1309 const bool bSuppressAbove(!bRotated && nRow > nFirstRow && CELL(nCol, nRow - 1).IsRotated());
1310
1311 if(!aX.equalZero() && !aY.equalZero())
1312 {
1313 // additionally needed local values
1314 const bool bOverlapY(rCell.mbOverlapY);
1315 const bool bLastCol(nCol == nLastCol);
1316 const bool bFirstRow(nRow == nFirstRow);
1317 const bool bLastRow(nRow == nLastRow);
1318
1319 // create upper line for this Cell
1320 if ((!bOverlapY // true for first line in merged cells or cells
1321 || bFirstRow) // true for non_Calc usages of this tooling
1322 && !bSuppressAbove) // true when above is not rotated, so edge is already handled (see bRotated)
1323 {
1324 // get CellStyle - method will take care to get the correct one, e.g.
1325 // for merged cells (it uses ORIGCELL that works with topLeft's of these)
1326 const Style& rTop(GetCellStyleTop(nCol, nRow));
1327
1328 if(rTop.IsUsed())
1329 {
1330 HelperCreateHorizontalEntry(*this, rTop, nCol, nRow, aOrigin, aX, aY, aData, true, pForceColor);
1331 }
1332 }
1333
1334 // create lower line for this Cell
1335 if (bLastRow // true for non_Calc usages of this tooling
1336 || bRotated) // true if cell is rotated, handle lower edge in local geometry
1337 {
1338 const Style& rBottom(GetCellStyleBottom(nCol, nRow));
1339
1340 if(rBottom.IsUsed())
1341 {
1342 HelperCreateHorizontalEntry(*this, rBottom, nCol, nRow + 1, aOrigin, aX, aY, aData, false, pForceColor);
1343 }
1344 }
1345
1346 // create left line for this Cell
1347 if ((!bOverlapX // true for first column in merged cells or cells
1348 || bFirstCol) // true for non_Calc usages of this tooling
1349 && !bSuppressLeft) // true when left is not rotated, so edge is already handled (see bRotated)
1350 {
1351 const Style& rLeft(GetCellStyleLeft(nCol, nRow));
1352
1353 if(rLeft.IsUsed())
1354 {
1355 HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, aData, true, pForceColor);
1356 }
1357 }
1358
1359 // create right line for this Cell
1360 if (bLastCol // true for non_Calc usages of this tooling
1361 || bRotated) // true if cell is rotated, handle right edge in local geometry
1362 {
1363 const Style& rRight(GetCellStyleRight(nCol, nRow));
1364
1365 if(rRight.IsUsed())
1366 {
1367 HelperCreateVerticalEntry(*this, rRight, nCol + 1, nRow, aOrigin, aX, aY, aData, false, pForceColor);
1368 }
1369 }
1370
1371 // tdf#126269 check for crossed lines, these need special treatment, especially
1372 // for merged cells (see comments in task). Separate treatment of merged and
1373 // non-merged cells to allow better handling of both types
1374 if(rCell.IsMerged())
1375 {
1376 // first check if this merged cell was already handled. To do so,
1377 // calculate and use the index of the TopLeft cell
1378 sal_Int32 nColLeft(nCol), nRowTop(nRow), nColRight(nCol), nRowBottom(nRow);
1379 GetMergedRange(nColLeft, nRowTop, nColRight, nRowBottom, nCol, nRow);
1380 const sal_Int32 nIndexOfMergedCell(mxImpl->GetIndex(nColLeft, nRowTop));
1381
1382 if(aMergedCells.end() == aMergedCells.find(nIndexOfMergedCell))
1383 {
1384 // not found, so not yet handled. Add now to mark as handled
1385 aMergedCells.insert(nIndexOfMergedCell);
1386
1387 // Get and check if diagonal styles are used
1388 // Note: For GetCellStyleBLTR below I tried to use nRowBottom
1389 // as Y-value what seemed more logical, but that
1390 // is wrong. Despite defining a line starting at
1391 // bottom-left, the Style is defined in the cell at top-left
1392 const Style& rTLBR(GetCellStyleTLBR(nColLeft, nRowTop));
1393 const Style& rBLTR(GetCellStyleBLTR(nColLeft, nRowTop));
1394
1395 if(rTLBR.IsUsed() || rBLTR.IsUsed())
1396 {
1397 // test if merged cell overlaps ClipRange at all (needs visualization)
1398 if(mxImpl->OverlapsClipRange(nColLeft, nRowTop, nColRight, nRowBottom))
1399 {
1400 // when merged, get extended coordinate system and derived values
1401 // for the full range of this merged cell. Only work with rMergedCell
1402 // (which is the top-left single cell of the merged cell) from here on
1403 const Cell& rMergedCell(CELL(nColLeft, nRowTop));
1404 aCoordinateSystem = rMergedCell.CreateCoordinateSystemMergedCell(
1405 *this, nColLeft, nRowTop, nColRight, nRowBottom);
1406 aX = basegfx::utils::getColumn(aCoordinateSystem, 0);
1407 aY = basegfx::utils::getColumn(aCoordinateSystem, 1);
1408 aOrigin = basegfx::utils::getColumn(aCoordinateSystem, 2);
1409
1410 // check if clip is needed
1411 basegfx::B2DRange aClipRange;
1412
1413 // first use row/col ClipTest for raw check
1414 bool bNeedToClip(
1415 !mxImpl->IsColInClipRange(nColLeft) ||
1416 !mxImpl->IsRowInClipRange(nRowTop) ||
1417 !mxImpl->IsColInClipRange(nColRight) ||
1418 !mxImpl->IsRowInClipRange(nRowBottom));
1419
1420 if(bNeedToClip)
1421 {
1422 // now get ClipRange and CellRange in logical coordinates
1423 aClipRange = GetB2DRange(
1424 mxImpl->mnFirstClipCol, mxImpl->mnFirstClipRow,
1425 mxImpl->mnLastClipCol, mxImpl->mnLastClipRow);
1426
1427 basegfx::B2DRange aCellRange(
1429 nColLeft, nRowTop,
1430 nColRight, nRowBottom));
1431
1432 // intersect these to get the target ClipRange, ensure
1433 // that clip is needed
1434 aClipRange.intersect(aCellRange);
1435 bNeedToClip = !aClipRange.isEmpty();
1436
1437#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
1438 aClipRanges.push_back(aClipRange);
1439#endif
1440 }
1441
1442 // create top-left to bottom-right geometry
1443 HelperCreateTLBREntry(*this, rTLBR, aData, aOrigin, aX, aY,
1444 nColLeft, nRowTop, nColRight, nRowBottom, pForceColor,
1445 bNeedToClip ? &aClipRange : nullptr);
1446
1447 // create bottom-left to top-right geometry
1448 HelperCreateBLTREntry(*this, rBLTR, aData, aOrigin, aX, aY,
1449 nColLeft, nRowTop, nColRight, nRowBottom, pForceColor,
1450 bNeedToClip ? &aClipRange : nullptr);
1451 }
1452 }
1453 }
1454 }
1455 else
1456 {
1457 // must be in clipping range: else not visible. This
1458 // already clips completely for non-merged cells
1459 if( mxImpl->IsInClipRange( nCol, nRow ) )
1460 {
1461 // get and check if diagonal styles are used
1462 const Style& rTLBR(GetCellStyleTLBR(nCol, nRow));
1463 const Style& rBLTR(GetCellStyleBLTR(nCol, nRow));
1464
1465 if(rTLBR.IsUsed() || rBLTR.IsUsed())
1466 {
1467 HelperCreateTLBREntry(*this, rTLBR, aData, aOrigin, aX, aY,
1468 nCol, nRow, nCol, nRow, pForceColor, nullptr);
1469
1470 HelperCreateBLTREntry(*this, rBLTR, aData, aOrigin, aX, aY,
1471 nCol, nRow, nCol, nRow, pForceColor, nullptr);
1472 }
1473 }
1474 }
1475 }
1476 else if(!aY.equalZero())
1477 {
1478 // cell has height, but no width. Create left vertical line for this Cell
1479 if ((!bOverlapX // true for first column in merged cells or cells
1480 || bFirstCol) // true for non_Calc usages of this tooling
1481 && !bSuppressLeft) // true when left is not rotated, so edge is already handled (see bRotated)
1482 {
1483 const Style& rLeft(GetCellStyleLeft(nCol, nRow));
1484
1485 if (rLeft.IsUsed())
1486 {
1487 HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, aData, true, pForceColor);
1488 }
1489 }
1490 }
1491 else
1492 {
1493 // Cell has *no* size, thus no visualization
1494 }
1495 }
1496 }
1497
1498 // create instance of SdrFrameBorderPrimitive2D if
1499 // SdrFrameBorderDataVector is used
1501
1502 if(!aData.empty())
1503 {
1504 aSequence.append(
1507 std::move(aData),
1508 true))); // force visualization to minimal one discrete unit (pixel)
1509 }
1510
1511#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
1512 for(auto const& rClipRange : aClipRanges)
1513 {
1514 // draw ClipRange in yellow to allow simple interactive optical control in office
1515 aSequence.append(
1519 basegfx::BColor(1.0, 1.0, 0.0))));
1520 }
1521#endif
1522
1523 return aSequence;
1524}
1525
1527{
1529
1530 if (mxImpl->mnWidth && mxImpl->mnHeight)
1531 {
1532 aPrimitives = CreateB2DPrimitiveRange(0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1, nullptr);
1533 }
1534
1535 return aPrimitives;
1536}
1537
1538#undef ORIGCELL
1539#undef LASTCELL
1540#undef CELLACC
1541#undef CELL
1542#undef DBG_FRAME_CHECK_ROW_1
1543#undef DBG_FRAME_CHECK_COL_1
1544#undef DBG_FRAME_CHECK_COLROW
1545#undef DBG_FRAME_CHECK_ROW
1546#undef DBG_FRAME_CHECK_COL
1547#undef DBG_FRAME_CHECK
1548
1549}
1550
1551/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
sal_uInt32 count() const
B2DPoint getMinimum() const
TYPE getWidth() const
void intersect(const Range2D &rRange)
bool isEmpty() const
TYPE getHeight() const
bool equalZero() const
TYPE getX() const
TYPE getY() const
void setX(TYPE fX)
void append(const Primitive2DReference &)
void addSdrConnectStyleData(bool bStart, const svx::frame::Style &rStyle, const basegfx::B2DVector &rNormalizedPerpendicular, bool bStyleMirrored)
Stores frame styles of an array of cells, supports merged ranges.
void SetAddMergedLeftSize(sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize)
Sets an additional left width for the merged range that contains (nCol,nRow).
const Style & GetCellStyleTL(sal_Int32 nCol, sal_Int32 nRow) const
Returns the top-left to bottom-right frame style of the cell (nCol,nRow).
std::unique_ptr< ArrayImpl > mxImpl
~Array()
Destructs the array.
const Style & GetCellStyleLeft(sal_Int32 nCol, sal_Int32 nRow) const
Returns the left frame style of the cell (nCol,nRow).
const Style & GetCellStyleTLBR(sal_Int32 nCol, sal_Int32 nRow) const
Returns the top-left to bottom-right frame style of the cell (nCol,nRow).
sal_Int32 GetCellCount() const
Returns the number of cells in the array.
const Style & GetCellStyleTop(sal_Int32 nCol, sal_Int32 nRow) const
Returns the top frame style of the cell (nCol,nRow).
bool IsMerged(sal_Int32 nCol, sal_Int32 nRow) const
Returns true, if the cell (nCol,nRow) is part of a merged range.
drawinglayer::primitive2d::Primitive2DContainer CreateB2DPrimitiveRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow, const Color *pForceColor) const
Draws the part of the specified range, that is inside the clipping range.
void SetRowHeight(sal_Int32 nRow, sal_Int32 nHeight)
Sets the output height of the specified row.
sal_Int32 GetColWidth(sal_Int32 nFirstCol, sal_Int32 nLastCol) const
Returns the output width of the specified range of columns.
void SetMergedRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow)
Inserts a new merged cell range.
void SetCellStyleBottom(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the bottom frame style of the specified cell (nCol,nRow).
void SetAddMergedBottomSize(sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize)
Sets an additional bottom height for the merged range that contains (nCol,nRow).
bool HasCellRotation() const
Check if at least one cell is rotated.
void SetCellStyleTLBR(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the top-left to bottom-right frame style of the cell (nCol,nRow).
const Style & GetCellStyleBR(sal_Int32 nCol, sal_Int32 nRow) const
Returns the top-left to bottom-right frame style of the cell (nCol,nRow).
void SetCellStyleLeft(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the left frame style of the cell (nCol,nRow).
void SetCellStyleRight(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the right frame style of the cell (nCol,nRow).
void SetAddMergedRightSize(sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize)
Sets an additional right width for the merged range that contains (nCol,nRow).
void SetColWidth(sal_Int32 nCol, sal_Int32 nWidth)
Sets the output width of the specified column.
void SetXOffset(sal_Int32 nXOffset)
Sets the X output coordinate of the left column.
sal_Int32 GetWidth() const
Returns the output width of the entire array.
basegfx::B2DRange GetB2DRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow) const
const Style & GetCellStyleTR(sal_Int32 nCol, sal_Int32 nRow) const
Returns the bottom-left to top-right frame style of the cell (nCol,nRow).
basegfx::B2DRange GetCellRange(sal_Int32 nCol, sal_Int32 nRow) const
Returns the output range of the cell (nCol,nRow).
Array()
Constructs an empty array.
const Style & GetCellStyleBLTR(sal_Int32 nCol, sal_Int32 nRow) const
Returns the bottom-left to top-right frame style of the cell (nCol,nRow).
void Initialize(sal_Int32 nWidth, sal_Int32 nHeight)
Reinitializes the array with the specified size.
void SetColumnStyleLeft(sal_Int32 nCol, const Style &rStyle)
Sets the left frame style of the specified column.
void GetMergedRange(sal_Int32 &rnFirstCol, sal_Int32 &rnFirstRow, sal_Int32 &rnLastCol, sal_Int32 &rnLastRow, sal_Int32 nCol, sal_Int32 nRow) const
Returns the top-left and bottom-right address of the merged range that contains (nCol,...
void SetRowStyleTop(sal_Int32 nRow, const Style &rStyle)
Sets the top frame style of the specified row.
void SetYOffset(sal_Int32 nYOffset)
Sets the Y output coordinate of the top row.
sal_Int32 GetRowHeight(sal_Int32 nFirstRow, sal_Int32 nLastRow) const
Returns the output height of the specified range of rows.
const Style & GetCellStyleBottom(sal_Int32 nCol, sal_Int32 nRow) const
Returns the top frame style of the cell (nCol,nRow).
const Style & GetCellStyleRight(sal_Int32 nCol, sal_Int32 nRow) const
Returns the right frame style of the cell (nCol,nRow).
void SetCellStyleDiag(sal_Int32 nCol, sal_Int32 nRow, const Style &rTLBR, const Style &rBLTR)
Sets both diagonal frame styles of the specified cell (nCol,nRow).
drawinglayer::primitive2d::Primitive2DContainer CreateB2DPrimitiveArray() const
Draws the part of the array, that is inside the clipping range.
void GetMergedOrigin(sal_Int32 &rnFirstCol, sal_Int32 &rnFirstRow, sal_Int32 nCol, sal_Int32 nRow) const
Returns the address of the top-left cell of the merged range that contains (nCol,nRow).
sal_Int32 GetHeight() const
Returns the output height of the entire array.
void SetAddMergedTopSize(sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize)
Sets an additional top height for the merged range that contains (nCol,nRow).
const Style & GetCellStyleBL(sal_Int32 nCol, sal_Int32 nRow) const
Returns the bottom-left to top-right frame style of the cell (nCol,nRow).
void SetAllColWidths(sal_Int32 nWidth)
Sets the same output width for all columns.
sal_Int32 GetColPosition(sal_Int32 nCol) const
Returns the X output coordinate of the left border of the specified column.
void SetCellStyleBLTR(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the bottom-left to top-right frame style of the cell (nCol,nRow).
void SetRowStyleBottom(sal_Int32 nRow, const Style &rStyle)
Sets the bottom frame style of the specified row.
sal_Int32 GetColCount() const
Returns the number of columns in the array.
void SetColumnStyleRight(sal_Int32 nCol, const Style &rStyle)
Sets the right frame style of the specified column.
sal_Int32 GetRowPosition(sal_Int32 nRow) const
Returns the Y output coordinate of the top border of the specified row.
void SetClipRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow)
Sets a clipping range.
void SetAllRowHeights(sal_Int32 nHeight)
Sets the same output height for all rows.
sal_Int32 GetCellIndex(sal_Int32 nCol, sal_Int32 nRow, bool bRTL) const
Returns the cell index from the cell address (nCol,nRow).
void MirrorSelfX()
Mirrors the entire array horizontally.
void SetCellRotation(sal_Int32 nCol, sal_Int32 nRow, SvxRotateMode eRotMode, double fOrientation)
Sets the rotation parameters of the cell (nCol,nRow).
void SetCellStyleTop(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the top frame style of the cell (nCol,nRow).
sal_Int32 GetRowCount() const
Returns the number of rows in the array.
Contains the widths of primary and secondary line of a frame style.
Definition: framelink.hxx:99
bool IsUsed() const
Check if this style is used - this depends on it having any width definition.
Definition: framelink.hxx:136
tools::Long AdjustTop(tools::Long nVertMoveDelta)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
#define DBG_ASSERT(sCon, aError)
FilterGroup & rTarget
SotClipboardFormatId & operator++(SotClipboardFormatId &eFormat)
sal_Int32 mnAddRight
double mfOrientation
#define LASTCELL(col, row)
#define DBG_FRAME_CHECK_COLROW(col, row, funcname)
bool mbOverlapX
#define DBG_FRAME_CHECK_COL(col, funcname)
Style maLeft
sal_Int32 mnAddTop
#define DBG_FRAME_CHECK_ROW_1(row, funcname)
sal_Int32 mnFirstCol
bool mbOverlapY
#define ORIGCELL(col, row)
sal_Int32 mnLastCol
Style maTLBR
Style maBLTR
#define CELL(col, row)
sal_Int32 mnRow
#define DBG_FRAME_CHECK_COL_1(col, funcname)
bool mbMergeOrig
sal_Int32 mnCol
Style maTop
#define DBG_FRAME_CHECK(cond, funcname, error)
#define DBG_FRAME_CHECK_ROW(row, funcname)
#define CELLACC(col, row)
sal_Int32 mnAddLeft
sal_Int32 mnAddBottom
Style maRight
sal_Int32 mnFirstRow
Style maBottom
SvxRotateMode meRotMode
sal_Int32 mnLastRow
RttiCompleteObjectLocator col
constexpr OUStringLiteral aData
B2DHomMatrix createCoordinateSystemTransform(const B2DPoint &rOrigin, const B2DVector &rX, const B2DVector &rY)
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
B2DTuple getColumn(const B2DHomMatrix &rMatrix, sal_uInt16 nCol)
B2DPolyPolygon clipPolygonOnRange(const B2DPolygon &rCandidate, const B2DRange &rRange, bool bInside, bool bStroke)
std::vector< SdrFrameBorderData > SdrFrameBorderDataVector
static void HelperCreateHorizontalEntry(const Array &rArray, const Style &rStyle, sal_Int32 col, sal_Int32 row, const basegfx::B2DPoint &rOrigin, const basegfx::B2DVector &rX, const basegfx::B2DVector &rY, drawinglayer::primitive2d::SdrFrameBorderDataVector &rData, bool bUpper, const Color *pForceColor)
static void HelperCreateBLTREntry(const Array &rArray, const Style &rStyle, drawinglayer::primitive2d::SdrFrameBorderDataVector &rData, const basegfx::B2DPoint &rOrigin, const basegfx::B2DVector &rX, const basegfx::B2DVector &rY, sal_Int32 nColLeft, sal_Int32 nColRight, sal_Int32 nRowTop, sal_Int32 nRowBottom, const Color *pForceColor, const basegfx::B2DRange *pClipRange)
const Style OBJ_STYLE_NONE
static void HelperCreateTLBREntry(const Array &rArray, const Style &rStyle, drawinglayer::primitive2d::SdrFrameBorderDataVector &rData, const basegfx::B2DPoint &rOrigin, const basegfx::B2DVector &rX, const basegfx::B2DVector &rY, sal_Int32 nColLeft, sal_Int32 nColRight, sal_Int32 nRowTop, sal_Int32 nRowBottom, const Color *pForceColor, const basegfx::B2DRange *pClipRange)
static void lclRecalcCoordVec(std::vector< sal_Int32 > &rCoords, const std::vector< sal_Int32 > &rSizes)
static void lclSetMergedRange(CellVec &rCells, sal_Int32 nWidth, sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow)
static void HelperCreateVerticalEntry(const Array &rArray, const Style &rStyle, sal_Int32 col, sal_Int32 row, const basegfx::B2DPoint &rOrigin, const basegfx::B2DVector &rX, const basegfx::B2DVector &rY, drawinglayer::primitive2d::SdrFrameBorderDataVector &rData, bool bLeft, const Color *pForceColor)
static void HelperClipLine(basegfx::B2DPoint &rStart, basegfx::B2DVector &rDirection, const basegfx::B2DRange &rClipRange)
std::vector< Cell > CellVec
const Cell OBJ_CELL_NONE
bool IsRotated(const OUString &rsCommandName, const OUString &rsModuleName)
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
SvxRotateMode
Definition: rotmodit.hxx:30
@ SVX_ROTATE_MODE_BOTTOM
Definition: rotmodit.hxx:34
@ SVX_ROTATE_MODE_STANDARD
Definition: rotmodit.hxx:31
@ SVX_ROTATE_MODE_CENTER
Definition: rotmodit.hxx:33
@ SVX_ROTATE_MODE_TOP
Definition: rotmodit.hxx:32
double mnWidth
double mnHeight
bool IsMergedOverlappedRight(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetMergedFirstCol(sal_Int32 nCol, sal_Int32 nRow) const
std::vector< sal_Int32 > maXCoords
bool IsMergedOverlappedTop(sal_Int32 nCol, sal_Int32 nRow) const
bool OverlapsClipRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow) const
const Cell & GetMergedLastCell(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetMergedLastRow(sal_Int32 nCol, sal_Int32 nRow) const
bool IsRowInClipRange(sal_Int32 nRow) const
bool IsMergedOverlappedLeft(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetMirrorCol(sal_Int32 nCol) const
sal_Int32 GetMergedFirstRow(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetRowPosition(sal_Int32 nRow) const
std::vector< sal_Int32 > maYCoords
const Cell & GetMergedOriginCell(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetIndex(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetMergedLastCol(sal_Int32 nCol, sal_Int32 nRow) const
std::vector< sal_Int32 > maWidths
bool IsColInClipRange(sal_Int32 nCol) const
sal_Int32 GetColPosition(sal_Int32 nCol) const
bool IsInClipRange(sal_Int32 nCol, sal_Int32 nRow) const
Cell & GetCellAcc(sal_Int32 nCol, sal_Int32 nRow)
std::vector< sal_Int32 > maHeights
bool IsValidPos(sal_Int32 nCol, sal_Int32 nRow) const
const Cell & GetCell(sal_Int32 nCol, sal_Int32 nRow) const
bool HasCellRotation() const
bool IsMergedOverlappedBottom(sal_Int32 nCol, sal_Int32 nRow) const
css::drawing::Direction3D aDirection
Cell
Definition: svdotable.hxx:95