1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <tools/stream.hxx>
21 #include <regionband.hxx>
22 #include <osl/diagnose.h>
23 #include <sal/log.hxx>
25 RegionBand::RegionBand()
26 : mpFirstBand(nullptr),
27 mpLastCheckedBand(nullptr)
31 RegionBand::RegionBand(const RegionBand
& rRef
)
32 : mpFirstBand(nullptr),
33 mpLastCheckedBand(nullptr)
38 RegionBand
& RegionBand::operator=(const RegionBand
& rRef
)
42 ImplRegionBand
* pPrevBand
= nullptr;
43 ImplRegionBand
* pBand
= rRef
.mpFirstBand
;
47 ImplRegionBand
* pNewBand
= new ImplRegionBand(*pBand
);
49 // first element? -> set as first into the list
50 if(pBand
== rRef
.mpFirstBand
)
52 mpFirstBand
= pNewBand
;
56 pPrevBand
->mpNextBand
= pNewBand
;
60 pBand
= pBand
->mpNextBand
;
66 RegionBand::RegionBand(const tools::Rectangle
& rRect
)
67 : mpFirstBand(nullptr),
68 mpLastCheckedBand(nullptr)
70 const long nTop(std::min(rRect
.Top(), rRect
.Bottom()));
71 const long nBottom(std::max(rRect
.Top(), rRect
.Bottom()));
72 const long nLeft(std::min(rRect
.Left(), rRect
.Right()));
73 const long nRight(std::max(rRect
.Left(), rRect
.Right()));
75 // add band with boundaries of the rectangle
76 mpFirstBand
= new ImplRegionBand(nTop
, nBottom
);
78 // Set left and right boundaries of the band
79 mpFirstBand
->Union(nLeft
, nRight
);
83 void RegionBand::implReset()
85 ImplRegionBand
* pBand
= mpFirstBand
;
89 ImplRegionBand
* pTempBand
= pBand
->mpNextBand
;
94 mpLastCheckedBand
= nullptr;
95 mpFirstBand
= nullptr;
98 RegionBand::~RegionBand()
103 bool RegionBand::operator==( const RegionBand
& rRegionBand
) const
106 // initialise pointers
107 ImplRegionBand
* pOwnRectBand
= mpFirstBand
;
108 ImplRegionBandSep
* pOwnRectBandSep
= pOwnRectBand
->mpFirstSep
;
109 ImplRegionBand
* pSecondRectBand
= rRegionBand
.mpFirstBand
;
110 ImplRegionBandSep
* pSecondRectBandSep
= pSecondRectBand
->mpFirstSep
;
112 while ( pOwnRectBandSep
&& pSecondRectBandSep
)
114 // get boundaries of current rectangle
115 long nOwnXLeft
= pOwnRectBandSep
->mnXLeft
;
116 long nSecondXLeft
= pSecondRectBandSep
->mnXLeft
;
118 if ( nOwnXLeft
!= nSecondXLeft
)
123 long nOwnYTop
= pOwnRectBand
->mnYTop
;
124 long nSecondYTop
= pSecondRectBand
->mnYTop
;
126 if ( nOwnYTop
!= nSecondYTop
)
131 long nOwnXRight
= pOwnRectBandSep
->mnXRight
;
132 long nSecondXRight
= pSecondRectBandSep
->mnXRight
;
134 if ( nOwnXRight
!= nSecondXRight
)
139 long nOwnYBottom
= pOwnRectBand
->mnYBottom
;
140 long nSecondYBottom
= pSecondRectBand
->mnYBottom
;
142 if ( nOwnYBottom
!= nSecondYBottom
)
147 // get next separation from current band
148 pOwnRectBandSep
= pOwnRectBandSep
->mpNextSep
;
150 // no separation found? -> go to next band!
151 if ( !pOwnRectBandSep
)
154 pOwnRectBand
= pOwnRectBand
->mpNextBand
;
156 // get first separation in current band
159 pOwnRectBandSep
= pOwnRectBand
->mpFirstSep
;
163 // get next separation from current band
164 pSecondRectBandSep
= pSecondRectBandSep
->mpNextSep
;
166 // no separation found? -> go to next band!
167 if ( !pSecondRectBandSep
)
170 pSecondRectBand
= pSecondRectBand
->mpNextBand
;
172 // get first separation in current band
173 if( pSecondRectBand
)
175 pSecondRectBandSep
= pSecondRectBand
->mpFirstSep
;
179 if ( pOwnRectBandSep
&& !pSecondRectBandSep
)
184 if ( !pOwnRectBandSep
&& pSecondRectBandSep
)
193 enum StreamEntryType
{ STREAMENTRY_BANDHEADER
, STREAMENTRY_SEPARATION
, STREAMENTRY_END
};
195 bool RegionBand::load(SvStream
& rIStrm
)
197 // clear this instance data
201 ImplRegionBand
* pCurrBand
= nullptr;
203 // get header from first element
204 sal_uInt16
nTmp16(STREAMENTRY_END
);
205 rIStrm
.ReadUInt16(nTmp16
);
207 if (STREAMENTRY_END
== static_cast<StreamEntryType
>(nTmp16
))
210 size_t nRecordsPossible
= rIStrm
.remainingSize() / (2*sizeof(sal_Int32
));
211 if (!nRecordsPossible
)
213 OSL_ENSURE(false, "premature end of region stream" );
220 // insert new band or new separation?
221 if(STREAMENTRY_BANDHEADER
== static_cast<StreamEntryType
>(nTmp16
))
224 sal_Int32
nYBottom(0);
226 rIStrm
.ReadInt32( nYTop
);
227 rIStrm
.ReadInt32( nYBottom
);
230 ImplRegionBand
* pNewBand
= new ImplRegionBand( nYTop
, nYBottom
);
232 // first element? -> set as first into the list
235 mpFirstBand
= pNewBand
;
239 pCurrBand
->mpNextBand
= pNewBand
;
242 // save pointer for next creation
243 pCurrBand
= pNewBand
;
248 sal_Int32
nXRight(0);
250 rIStrm
.ReadInt32( nXLeft
);
251 rIStrm
.ReadInt32( nXRight
);
256 pCurrBand
->Union( nXLeft
, nXRight
);
262 OSL_ENSURE(false, "premature end of region stream" );
268 rIStrm
.ReadUInt16( nTmp16
);
270 while (STREAMENTRY_END
!= static_cast<StreamEntryType
>(nTmp16
) && rIStrm
.good());
271 if (!CheckConsistency())
279 void RegionBand::save(SvStream
& rOStrm
) const
281 ImplRegionBand
* pBand
= mpFirstBand
;
286 rOStrm
.WriteUInt16( STREAMENTRY_BANDHEADER
);
287 rOStrm
.WriteInt32( pBand
->mnYTop
);
288 rOStrm
.WriteInt32( pBand
->mnYBottom
);
290 // put separations of current band
291 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
296 rOStrm
.WriteUInt16( STREAMENTRY_SEPARATION
);
297 rOStrm
.WriteInt32( pSep
->mnXLeft
);
298 rOStrm
.WriteInt32( pSep
->mnXRight
);
300 // next separation from current band
301 pSep
= pSep
->mpNextSep
;
304 pBand
= pBand
->mpNextBand
;
308 rOStrm
.WriteUInt16( STREAMENTRY_END
);
311 bool RegionBand::isSingleRectangle() const
314 if(mpFirstBand
&& !mpFirstBand
->mpNextBand
)
317 if(mpFirstBand
->mpFirstSep
&& !mpFirstBand
->mpFirstSep
->mpNextSep
)
326 void RegionBand::InsertBand(ImplRegionBand
* pPreviousBand
, ImplRegionBand
* pBandToInsert
)
328 OSL_ASSERT(pBandToInsert
!=nullptr);
332 // Insert band before all others.
335 mpFirstBand
->mpPrevBand
= pBandToInsert
;
338 pBandToInsert
->mpNextBand
= mpFirstBand
;
339 mpFirstBand
= pBandToInsert
;
343 // Insert band directly after pPreviousBand.
344 pBandToInsert
->mpNextBand
= pPreviousBand
->mpNextBand
;
345 pPreviousBand
->mpNextBand
= pBandToInsert
;
346 pBandToInsert
->mpPrevBand
= pPreviousBand
;
351 void RegionBand::processPoints()
353 ImplRegionBand
* pRegionBand
= mpFirstBand
;
357 // generate separations from the lines and process union
358 pRegionBand
->ProcessPoints();
359 pRegionBand
= pRegionBand
->mpNextBand
;
364 /** This function is similar to the RegionBand::InsertBands() method.
365 It creates a minimal set of missing bands so that the entire vertical
366 interval from nTop to nBottom is covered by bands.
368 void RegionBand::ImplAddMissingBands(const long nTop
, const long nBottom
)
370 // Iterate over already existing bands and add missing bands atop the
371 // first and between two bands.
372 ImplRegionBand
* pPreviousBand
= nullptr;
373 ImplRegionBand
* pBand
= ImplGetFirstRegionBand();
374 long nCurrentTop (nTop
);
376 while (pBand
!= nullptr && nCurrentTop
<nBottom
)
378 if (nCurrentTop
< pBand
->mnYTop
)
380 // Create new band above the current band.
381 ImplRegionBand
* pAboveBand
= new ImplRegionBand(
383 ::std::min(nBottom
,pBand
->mnYTop
-1));
384 InsertBand(pPreviousBand
, pAboveBand
);
387 // Adapt the top of the interval to prevent overlapping bands.
388 nCurrentTop
= ::std::max(nTop
, pBand
->mnYBottom
+1);
390 // Advance to next band.
391 pPreviousBand
= pBand
;
392 pBand
= pBand
->mpNextBand
;
395 // We still have to cover two cases:
396 // 1. The region does not yet contain any bands.
397 // 2. The interval nTop->nBottom extends past the bottom most band.
398 if (nCurrentTop
<= nBottom
399 && (pBand
==nullptr || nBottom
>pBand
->mnYBottom
))
401 // When there is no previous band then the new one will be the
402 // first. Otherwise the new band is inserted behind the last band.
412 void RegionBand::CreateBandRange(long nYTop
, long nYBottom
)
415 mpFirstBand
= new ImplRegionBand( nYTop
-1, nYTop
-1 );
417 // begin first search from the first element
418 mpLastCheckedBand
= mpFirstBand
;
419 ImplRegionBand
* pBand
= mpFirstBand
;
421 for ( long i
= nYTop
; i
<= nYBottom
+1; i
++ )
424 ImplRegionBand
* pNewBand
= new ImplRegionBand( i
, i
);
425 pBand
->mpNextBand
= pNewBand
;
427 if ( pBand
!= mpFirstBand
)
429 pNewBand
->mpPrevBand
= pBand
;
432 pBand
= pBand
->mpNextBand
;
437 void RegionBand::InsertLine(const Point
& rStartPt
, const Point
& rEndPt
, long nLineId
)
441 // lines consisting of a single point do not interest here
442 if ( rStartPt
== rEndPt
)
447 LineType eLineType
= (rStartPt
.Y() > rEndPt
.Y()) ? LineType::Descending
: LineType::Ascending
;
448 if ( rStartPt
.X() == rEndPt
.X() )
451 const long nEndY
= rEndPt
.Y();
458 for ( ; nY
<= nEndY
; nY
++ )
460 Point
aNewPoint( nX
, nY
);
461 InsertPoint( aNewPoint
, nLineId
,
462 (aNewPoint
== rEndPt
) || (aNewPoint
== rStartPt
),
468 for ( ; nY
>= nEndY
; nY
-- )
470 Point
aNewPoint( nX
, nY
);
471 InsertPoint( aNewPoint
, nLineId
,
472 (aNewPoint
== rEndPt
) || (aNewPoint
== rStartPt
),
477 else if ( rStartPt
.Y() != rEndPt
.Y() )
479 const long nDX
= labs( rEndPt
.X() - rStartPt
.X() );
480 const long nDY
= labs( rEndPt
.Y() - rStartPt
.Y() );
481 const long nStartX
= rStartPt
.X();
482 const long nStartY
= rStartPt
.Y();
483 const long nEndX
= rEndPt
.X();
484 const long nEndY
= rEndPt
.Y();
485 const long nXInc
= ( nStartX
< nEndX
) ? 1 : -1;
486 const long nYInc
= ( nStartY
< nEndY
) ? 1 : -1;
490 const long nDYX
= ( nDY
- nDX
) * 2;
491 const long nDY2
= nDY
<< 1;
492 long nD
= nDY2
- nDX
;
494 for ( nX
= nStartX
, nY
= nStartY
; nX
!= nEndX
; nX
+= nXInc
)
496 InsertPoint( Point( nX
, nY
), nLineId
, nStartX
== nX
, eLineType
);
509 const long nDYX
= ( nDX
- nDY
) * 2;
510 const long nDY2
= nDX
<< 1;
511 long nD
= nDY2
- nDY
;
513 for ( nX
= nStartX
, nY
= nStartY
; nY
!= nEndY
; nY
+= nYInc
)
515 InsertPoint( Point( nX
, nY
), nLineId
, nStartY
== nY
, eLineType
);
528 InsertPoint( Point( nEndX
, nEndY
), nLineId
, true, eLineType
);
532 void RegionBand::InsertPoint(const Point
&rPoint
, long nLineID
, bool bEndPoint
, LineType eLineType
)
534 SAL_WARN_IF( mpFirstBand
== nullptr, "vcl", "RegionBand::InsertPoint - no bands available!" );
536 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
538 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
542 if ( rPoint
.Y() > mpLastCheckedBand
->mnYTop
)
545 while ( mpLastCheckedBand
)
547 // Insert point if possible
548 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
550 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
554 mpLastCheckedBand
= mpLastCheckedBand
->mpNextBand
;
557 OSL_ENSURE(false, "RegionBand::InsertPoint reached the end of the list!" );
562 while ( mpLastCheckedBand
)
564 // Insert point if possible
565 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
567 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
571 mpLastCheckedBand
= mpLastCheckedBand
->mpPrevBand
;
574 OSL_ENSURE(false, "RegionBand::InsertPoint reached the beginning of the list!" );
577 OSL_ENSURE(false, "RegionBand::InsertPoint point not inserted!" );
579 // reinitialize pointer (should never be reached!)
580 mpLastCheckedBand
= mpFirstBand
;
583 bool RegionBand::OptimizeBandList()
585 ImplRegionBand
* pPrevBand
= nullptr;
586 ImplRegionBand
* pBand
= mpFirstBand
;
590 const bool bBTEqual
= pBand
->mpNextBand
&& (pBand
->mnYBottom
== pBand
->mpNextBand
->mnYTop
);
592 // no separation? -> remove!
593 if ( pBand
->IsEmpty() || (bBTEqual
&& (pBand
->mnYBottom
== pBand
->mnYTop
)) )
596 ImplRegionBand
* pOldBand
= pBand
;
598 // previous element of the list
599 if ( pBand
== mpFirstBand
)
600 mpFirstBand
= pBand
->mpNextBand
;
602 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
604 pBand
= pBand
->mpNextBand
;
611 pBand
->mnYBottom
= pBand
->mpNextBand
->mnYTop
-1;
613 // this and next band with equal separations? -> combine!
614 if ( pBand
->mpNextBand
&&
615 ((pBand
->mnYBottom
+1) == pBand
->mpNextBand
->mnYTop
) &&
616 (*pBand
== *pBand
->mpNextBand
) )
618 // expand current height
619 pBand
->mnYBottom
= pBand
->mpNextBand
->mnYBottom
;
621 // remove next band from list
622 ImplRegionBand
* pDeletedBand
= pBand
->mpNextBand
;
623 pBand
->mpNextBand
= pDeletedBand
->mpNextBand
;
630 // count rectangles within band
631 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
634 pSep
= pSep
->mpNextSep
;
638 pBand
= pBand
->mpNextBand
;
647 SAL_WARN_IF( pBand
->mpFirstSep
== nullptr, "vcl", "Exiting RegionBand::OptimizeBandList(): empty band in region!" );
649 if ( pBand
->mnYBottom
< pBand
->mnYTop
)
650 OSL_ENSURE(false, "RegionBand::OptimizeBandList(): YBottomBoundary < YTopBoundary" );
652 if ( pBand
->mpNextBand
&& pBand
->mnYBottom
>= pBand
->mpNextBand
->mnYTop
)
653 OSL_ENSURE(false, "RegionBand::OptimizeBandList(): overlapping bands in region!" );
655 pBand
= pBand
->mpNextBand
;
659 return (nullptr != mpFirstBand
);
662 void RegionBand::Move(long nHorzMove
, long nVertMove
)
664 ImplRegionBand
* pBand
= mpFirstBand
;
668 // process the vertical move
671 pBand
->mnYTop
= pBand
->mnYTop
+ nVertMove
;
672 pBand
->mnYBottom
= pBand
->mnYBottom
+ nVertMove
;
675 // process the horizontal move
678 pBand
->MoveX(nHorzMove
);
681 pBand
= pBand
->mpNextBand
;
686 void RegionBand::Scale(double fScaleX
, double fScaleY
)
688 ImplRegionBand
* pBand
= mpFirstBand
;
692 // process the vertical move
695 pBand
->mnYTop
= basegfx::fround(pBand
->mnYTop
* fScaleY
);
696 pBand
->mnYBottom
= basegfx::fround(pBand
->mnYBottom
* fScaleY
);
699 // process the horizontal move
702 pBand
->ScaleX(fScaleX
);
705 pBand
= pBand
->mpNextBand
;
710 void RegionBand::InsertBands(long nTop
, long nBottom
)
712 // region empty? -> set rectangle as first entry!
715 // add band with boundaries of the rectangle
716 mpFirstBand
= new ImplRegionBand( nTop
, nBottom
);
720 // find/insert bands for the boundaries of the rectangle
721 bool bTopBoundaryInserted
= false;
722 bool bTop2BoundaryInserted
= false;
723 bool bBottomBoundaryInserted
= false;
725 // special case: top boundary is above the first band
726 ImplRegionBand
* pNewBand
;
728 if ( nTop
< mpFirstBand
->mnYTop
)
730 // create new band above the first in the list
731 pNewBand
= new ImplRegionBand( nTop
, mpFirstBand
->mnYTop
);
733 if ( nBottom
< mpFirstBand
->mnYTop
)
735 pNewBand
->mnYBottom
= nBottom
;
738 // insert band into the list
739 pNewBand
->mpNextBand
= mpFirstBand
;
740 mpFirstBand
= pNewBand
;
742 bTopBoundaryInserted
= true;
745 // insert band(s) into the list
746 ImplRegionBand
* pBand
= mpFirstBand
;
750 // Insert Bands if possible
751 if ( !bTopBoundaryInserted
)
753 bTopBoundaryInserted
= InsertSingleBand( pBand
, nTop
- 1 );
756 if ( !bTop2BoundaryInserted
)
758 bTop2BoundaryInserted
= InsertSingleBand( pBand
, nTop
);
761 if ( !bBottomBoundaryInserted
&& (nTop
!= nBottom
) )
763 bBottomBoundaryInserted
= InsertSingleBand( pBand
, nBottom
);
766 // both boundaries inserted? -> nothing more to do
767 if ( bTopBoundaryInserted
&& bTop2BoundaryInserted
&& bBottomBoundaryInserted
)
772 // insert bands between two bands if necessary
773 if ( pBand
->mpNextBand
)
775 if ( (pBand
->mnYBottom
+ 1) < pBand
->mpNextBand
->mnYTop
)
777 // copy band with list and set new boundary
778 pNewBand
= new ImplRegionBand( pBand
->mnYBottom
+1, pBand
->mpNextBand
->mnYTop
-1 );
780 // insert band into the list
781 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
782 pBand
->mpNextBand
= pNewBand
;
786 pBand
= pBand
->mpNextBand
;
791 bool RegionBand::InsertSingleBand(ImplRegionBand
* pBand
, long nYBandPosition
)
793 // boundary already included in band with height 1? -> nothing to do!
794 if ( (pBand
->mnYTop
== pBand
->mnYBottom
) && (nYBandPosition
== pBand
->mnYTop
) )
799 // insert single height band on top?
800 ImplRegionBand
* pNewBand
;
802 if ( nYBandPosition
== pBand
->mnYTop
)
804 // copy band with list and set new boundary
805 pNewBand
= new ImplRegionBand( *pBand
);
806 pNewBand
->mnYTop
= nYBandPosition
+1;
808 // insert band into the list
809 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
810 pBand
->mnYBottom
= nYBandPosition
;
811 pBand
->mpNextBand
= pNewBand
;
816 // top of new rectangle within the current band? -> insert new band and copy data
817 if ( (nYBandPosition
> pBand
->mnYTop
) && (nYBandPosition
< pBand
->mnYBottom
) )
819 // copy band with list and set new boundary
820 pNewBand
= new ImplRegionBand( *pBand
);
821 pNewBand
->mnYTop
= nYBandPosition
;
823 // insert band into the list
824 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
825 pBand
->mnYBottom
= nYBandPosition
;
826 pBand
->mpNextBand
= pNewBand
;
828 // copy band with list and set new boundary
829 pNewBand
= new ImplRegionBand( *pBand
);
830 pNewBand
->mnYTop
= nYBandPosition
;
832 // insert band into the list
833 pBand
->mpNextBand
->mnYTop
= nYBandPosition
+1;
835 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
836 pBand
->mnYBottom
= nYBandPosition
- 1;
837 pBand
->mpNextBand
= pNewBand
;
842 // create new band behind the current in the list
843 if ( !pBand
->mpNextBand
)
845 if ( nYBandPosition
== pBand
->mnYBottom
)
847 // copy band with list and set new boundary
848 pNewBand
= new ImplRegionBand( *pBand
);
849 pNewBand
->mnYTop
= pBand
->mnYBottom
;
850 pNewBand
->mnYBottom
= nYBandPosition
;
852 pBand
->mnYBottom
= nYBandPosition
-1;
854 // append band to the list
855 pBand
->mpNextBand
= pNewBand
;
859 if ( nYBandPosition
> pBand
->mnYBottom
)
862 pNewBand
= new ImplRegionBand( pBand
->mnYBottom
+ 1, nYBandPosition
);
864 // append band to the list
865 pBand
->mpNextBand
= pNewBand
;
873 void RegionBand::Union(long nLeft
, long nTop
, long nRight
, long nBottom
)
875 SAL_WARN_IF( nLeft
> nRight
, "vcl", "RegionBand::Union() - nLeft > nRight" );
876 SAL_WARN_IF( nTop
> nBottom
, "vcl", "RegionBand::Union() - nTop > nBottom" );
879 ImplRegionBand
* pBand
= mpFirstBand
;
882 if ( pBand
->mnYTop
>= nTop
)
884 if ( pBand
->mnYBottom
<= nBottom
)
885 pBand
->Union( nLeft
, nRight
);
889 long nCurY
= pBand
->mnYBottom
;
890 pBand
= pBand
->mpNextBand
;
893 if ( (pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
) )
895 OSL_ENSURE(false, "RegionBand::Union() - Bands not sorted!" );
897 pBand
= pBand
->mpNextBand
;
904 pBand
= pBand
->mpNextBand
;
909 void RegionBand::Intersect(long nLeft
, long nTop
, long nRight
, long nBottom
)
911 // process intersections
912 ImplRegionBand
* pPrevBand
= nullptr;
913 ImplRegionBand
* pBand
= mpFirstBand
;
917 // band within intersection boundary? -> process. otherwise remove
918 if((pBand
->mnYTop
>= nTop
) && (pBand
->mnYBottom
<= nBottom
))
920 // process intersection
921 pBand
->Intersect(nLeft
, nRight
);
923 pBand
= pBand
->mpNextBand
;
927 ImplRegionBand
* pOldBand
= pBand
;
929 if(pBand
== mpFirstBand
)
931 mpFirstBand
= pBand
->mpNextBand
;
935 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
938 pBand
= pBand
->mpNextBand
;
945 void RegionBand::Union(const RegionBand
& rSource
)
947 // apply all rectangles from rSource to this
948 ImplRegionBand
* pBand
= rSource
.mpFirstBand
;
952 // insert bands if the boundaries are not already in the list
953 InsertBands(pBand
->mnYTop
, pBand
->mnYBottom
);
955 // process all elements of the list
956 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
960 Union(pSep
->mnXLeft
, pBand
->mnYTop
, pSep
->mnXRight
, pBand
->mnYBottom
);
961 pSep
= pSep
->mpNextSep
;
964 pBand
= pBand
->mpNextBand
;
969 void RegionBand::Exclude(long nLeft
, long nTop
, long nRight
, long nBottom
)
971 SAL_WARN_IF( nLeft
> nRight
, "vcl", "RegionBand::Exclude() - nLeft > nRight" );
972 SAL_WARN_IF( nTop
> nBottom
, "vcl", "RegionBand::Exclude() - nTop > nBottom" );
975 ImplRegionBand
* pBand
= mpFirstBand
;
979 if(pBand
->mnYTop
>= nTop
)
981 if(pBand
->mnYBottom
<= nBottom
)
983 pBand
->Exclude(nLeft
, nRight
);
988 long nCurY
= pBand
->mnYBottom
;
989 pBand
= pBand
->mpNextBand
;
993 if((pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
))
995 OSL_ENSURE(false, "RegionBand::Exclude() - Bands not sorted!" );
998 pBand
= pBand
->mpNextBand
;
1005 pBand
= pBand
->mpNextBand
;
1010 void RegionBand::XOr(long nLeft
, long nTop
, long nRight
, long nBottom
)
1012 SAL_WARN_IF( nLeft
> nRight
, "vcl", "RegionBand::Exclude() - nLeft > nRight" );
1013 SAL_WARN_IF( nTop
> nBottom
, "vcl", "RegionBand::Exclude() - nTop > nBottom" );
1016 ImplRegionBand
* pBand
= mpFirstBand
;
1020 if(pBand
->mnYTop
>= nTop
)
1022 if(pBand
->mnYBottom
<= nBottom
)
1024 pBand
->XOr(nLeft
, nRight
);
1029 long nCurY
= pBand
->mnYBottom
;
1030 pBand
= pBand
->mpNextBand
;
1034 if((pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
))
1036 OSL_ENSURE(false, "RegionBand::XOr() - Bands not sorted!" );
1039 pBand
= pBand
->mpNextBand
;
1046 pBand
= pBand
->mpNextBand
;
1051 void RegionBand::Intersect(const RegionBand
& rSource
)
1053 // mark all bands as untouched
1054 ImplRegionBand
* pBand
= mpFirstBand
;
1058 pBand
->mbTouched
= false;
1059 pBand
= pBand
->mpNextBand
;
1062 pBand
= rSource
.mpFirstBand
;
1066 // insert bands if the boundaries are not already in the list
1067 InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1069 // process all elements of the list
1070 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1075 if ( pSep
== pBand
->mpFirstSep
)
1077 // process intersection and do not remove untouched bands
1078 Exclude( LONG_MIN
+1, pBand
->mnYTop
, pSep
->mnXLeft
-1, pBand
->mnYBottom
);
1082 if ( pSep
->mpNextSep
== nullptr )
1084 // process intersection and do not remove untouched bands
1085 Exclude( pSep
->mnXRight
+1, pBand
->mnYTop
, LONG_MAX
-1, pBand
->mnYBottom
);
1089 // process intersection and do not remove untouched bands
1090 Exclude( pSep
->mnXRight
+1, pBand
->mnYTop
, pSep
->mpNextSep
->mnXLeft
-1, pBand
->mnYBottom
);
1093 pSep
= pSep
->mpNextSep
;
1096 pBand
= pBand
->mpNextBand
;
1099 // remove all untouched bands if bands already left
1100 ImplRegionBand
* pPrevBand
= nullptr;
1101 pBand
= mpFirstBand
;
1105 if ( !pBand
->mbTouched
)
1108 ImplRegionBand
* pOldBand
= pBand
;
1110 // previous element of the list
1111 if ( pBand
== mpFirstBand
)
1113 mpFirstBand
= pBand
->mpNextBand
;
1117 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
1120 pBand
= pBand
->mpNextBand
;
1126 pBand
= pBand
->mpNextBand
;
1132 bool RegionBand::Exclude(const RegionBand
& rSource
)
1134 // apply all rectangles to the region passed to this region
1135 ImplRegionBand
* pBand
= rSource
.mpFirstBand
;
1139 // insert bands if the boundaries are not already in the list
1140 InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1142 // process all elements of the list
1143 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1147 Exclude( pSep
->mnXLeft
, pBand
->mnYTop
, pSep
->mnXRight
, pBand
->mnYBottom
);
1148 pSep
= pSep
->mpNextSep
;
1151 // to test less bands, already check in the loop
1152 if ( !OptimizeBandList() )
1157 pBand
= pBand
->mpNextBand
;
1163 bool RegionBand::CheckConsistency() const
1167 // look in the band list (don't test first band again!)
1168 const ImplRegionBand
* pBand
= mpFirstBand
->mpNextBand
;
1171 if (!pBand
->mpFirstSep
)
1173 pBand
= pBand
->mpNextBand
;
1178 tools::Rectangle
RegionBand::GetBoundRect() const
1181 // get the boundaries of the first band
1182 long nYTop(mpFirstBand
->mnYTop
);
1183 long nYBottom(mpFirstBand
->mnYBottom
);
1184 long nXLeft(mpFirstBand
->GetXLeftBoundary());
1185 long nXRight(mpFirstBand
->GetXRightBoundary());
1187 // look in the band list (don't test first band again!)
1188 ImplRegionBand
* pBand
= mpFirstBand
->mpNextBand
;
1192 nYBottom
= pBand
->mnYBottom
;
1193 nXLeft
= std::min( nXLeft
, pBand
->GetXLeftBoundary() );
1194 nXRight
= std::max( nXRight
, pBand
->GetXRightBoundary() );
1196 pBand
= pBand
->mpNextBand
;
1199 return tools::Rectangle( nXLeft
, nYTop
, nXRight
, nYBottom
);
1202 void RegionBand::XOr(const RegionBand
& rSource
)
1204 ImplRegionBand
* pBand
= rSource
.mpFirstBand
;
1208 // insert bands if the boundaries are not already in the list
1209 InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1211 // process all elements of the list
1212 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1216 XOr( pSep
->mnXLeft
, pBand
->mnYTop
, pSep
->mnXRight
, pBand
->mnYBottom
);
1217 pSep
= pSep
->mpNextSep
;
1220 pBand
= pBand
->mpNextBand
;
1224 bool RegionBand::IsInside(const Point
& rPoint
) const
1228 ImplRegionBand
* pBand
= mpFirstBand
;
1232 // is point within band?
1233 if((pBand
->mnYTop
<= rPoint
.Y()) && (pBand
->mnYBottom
>= rPoint
.Y()))
1235 // is point within separation of the band?
1236 return pBand
->IsInside(rPoint
.X());
1239 pBand
= pBand
->mpNextBand
;
1245 void RegionBand::GetRegionRectangles(RectangleVector
& rTarget
) const
1247 // clear result vector
1249 ImplRegionBand
* pCurrRectBand
= mpFirstBand
;
1250 tools::Rectangle aRectangle
;
1252 while(pCurrRectBand
)
1254 ImplRegionBandSep
* pCurrRectBandSep
= pCurrRectBand
->mpFirstSep
;
1256 aRectangle
.SetTop( pCurrRectBand
->mnYTop
);
1257 aRectangle
.SetBottom( pCurrRectBand
->mnYBottom
);
1259 while(pCurrRectBandSep
)
1261 aRectangle
.SetLeft( pCurrRectBandSep
->mnXLeft
);
1262 aRectangle
.SetRight( pCurrRectBandSep
->mnXRight
);
1263 rTarget
.push_back(aRectangle
);
1264 pCurrRectBandSep
= pCurrRectBandSep
->mpNextSep
;
1267 pCurrRectBand
= pCurrRectBand
->mpNextBand
;
1271 sal_uInt32
RegionBand::getRectangleCount() const
1273 sal_uInt32 nCount
= 0;
1274 const ImplRegionBand
* pBand
= mpFirstBand
;
1278 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1283 pSep
= pSep
->mpNextSep
;
1286 pBand
= pBand
->mpNextBand
;
1293 const char* ImplDbgTestRegionBand(const void* pObj
)
1295 const RegionBand
* pRegionBand
= static_cast< const RegionBand
* >(pObj
);
1299 const ImplRegionBand
* pBand
= pRegionBand
->ImplGetFirstRegionBand();
1303 if(pBand
->mnYBottom
< pBand
->mnYTop
)
1305 return "YBottom < YTop";
1308 if(pBand
->mpNextBand
)
1310 if(pBand
->mnYBottom
>= pBand
->mpNextBand
->mnYTop
)
1312 return "overlapping bands in region";
1316 if(pBand
->mbTouched
)
1318 return "Band-mbTouched overwrite";
1321 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1325 if(pSep
->mnXRight
< pSep
->mnXLeft
)
1327 return "XLeft < XRight";
1332 if(pSep
->mnXRight
>= pSep
->mpNextSep
->mnXLeft
)
1334 return "overlapping separations in region";
1338 if ( pSep
->mbRemoved
)
1340 return "Sep-mbRemoved overwrite";
1343 pSep
= pSep
->mpNextSep
;
1346 pBand
= pBand
->mpNextBand
;
1354 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */