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 <tools/debug.hxx>
22 #include <regionband.hxx>
23 #include <osl/diagnose.h>
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
)
40 ImplRegionBand
* pPrevBand
= nullptr;
41 ImplRegionBand
* pBand
= rRef
.mpFirstBand
;
45 ImplRegionBand
* pNewBand
= new ImplRegionBand(*pBand
);
47 // first element? -> set as first into the list
48 if(pBand
== rRef
.mpFirstBand
)
50 mpFirstBand
= pNewBand
;
54 pPrevBand
->mpNextBand
= pNewBand
;
58 pBand
= pBand
->mpNextBand
;
64 RegionBand::RegionBand(const tools::Rectangle
& rRect
)
65 : mpFirstBand(nullptr),
66 mpLastCheckedBand(nullptr)
68 const long nTop(std::min(rRect
.Top(), rRect
.Bottom()));
69 const long nBottom(std::max(rRect
.Top(), rRect
.Bottom()));
70 const long nLeft(std::min(rRect
.Left(), rRect
.Right()));
71 const long nRight(std::max(rRect
.Left(), rRect
.Right()));
73 // add band with boundaries of the rectangle
74 mpFirstBand
= new ImplRegionBand(nTop
, nBottom
);
76 // Set left and right boundaries of the band
77 mpFirstBand
->Union(nLeft
, nRight
);
81 void RegionBand::implReset()
83 ImplRegionBand
* pBand
= mpFirstBand
;
87 ImplRegionBand
* pTempBand
= pBand
->mpNextBand
;
92 mpLastCheckedBand
= nullptr;
93 mpFirstBand
= nullptr;
96 RegionBand::~RegionBand()
101 bool RegionBand::operator==( const RegionBand
& rRegionBand
) const
104 // initialise pointers
105 ImplRegionBand
* pOwnRectBand
= mpFirstBand
;
106 ImplRegionBandSep
* pOwnRectBandSep
= pOwnRectBand
->mpFirstSep
;
107 ImplRegionBand
* pSecondRectBand
= rRegionBand
.mpFirstBand
;
108 ImplRegionBandSep
* pSecondRectBandSep
= pSecondRectBand
->mpFirstSep
;
110 while ( pOwnRectBandSep
&& pSecondRectBandSep
)
112 // get boundaries of current rectangle
113 long nOwnXLeft
= pOwnRectBandSep
->mnXLeft
;
114 long nSecondXLeft
= pSecondRectBandSep
->mnXLeft
;
116 if ( nOwnXLeft
!= nSecondXLeft
)
121 long nOwnYTop
= pOwnRectBand
->mnYTop
;
122 long nSecondYTop
= pSecondRectBand
->mnYTop
;
124 if ( nOwnYTop
!= nSecondYTop
)
129 long nOwnXRight
= pOwnRectBandSep
->mnXRight
;
130 long nSecondXRight
= pSecondRectBandSep
->mnXRight
;
132 if ( nOwnXRight
!= nSecondXRight
)
137 long nOwnYBottom
= pOwnRectBand
->mnYBottom
;
138 long nSecondYBottom
= pSecondRectBand
->mnYBottom
;
140 if ( nOwnYBottom
!= nSecondYBottom
)
145 // get next separation from current band
146 pOwnRectBandSep
= pOwnRectBandSep
->mpNextSep
;
148 // no separation found? -> go to next band!
149 if ( !pOwnRectBandSep
)
152 pOwnRectBand
= pOwnRectBand
->mpNextBand
;
154 // get first separation in current band
157 pOwnRectBandSep
= pOwnRectBand
->mpFirstSep
;
161 // get next separation from current band
162 pSecondRectBandSep
= pSecondRectBandSep
->mpNextSep
;
164 // no separation found? -> go to next band!
165 if ( !pSecondRectBandSep
)
168 pSecondRectBand
= pSecondRectBand
->mpNextBand
;
170 // get first separation in current band
171 if( pSecondRectBand
)
173 pSecondRectBandSep
= pSecondRectBand
->mpFirstSep
;
177 if ( pOwnRectBandSep
&& !pSecondRectBandSep
)
182 if ( !pOwnRectBandSep
&& pSecondRectBandSep
)
191 enum StreamEntryType
{ STREAMENTRY_BANDHEADER
, STREAMENTRY_SEPARATION
, STREAMENTRY_END
};
193 void RegionBand::load(SvStream
& rIStrm
)
195 // clear this instance data
199 ImplRegionBand
* pCurrBand
= nullptr;
201 // get header from first element
202 sal_uInt16
nTmp16(STREAMENTRY_END
);
203 rIStrm
.ReadUInt16(nTmp16
);
205 if (STREAMENTRY_END
== (StreamEntryType
)nTmp16
)
208 size_t nRecordsPossible
= rIStrm
.remainingSize() / (2*sizeof(sal_Int32
));
209 if (!nRecordsPossible
)
211 OSL_ENSURE(false, "premature end of region stream" );
218 // insert new band or new separation?
219 if(STREAMENTRY_BANDHEADER
== (StreamEntryType
)nTmp16
)
222 sal_Int32
nYBottom(0);
224 rIStrm
.ReadInt32( nYTop
);
225 rIStrm
.ReadInt32( nYBottom
);
228 ImplRegionBand
* pNewBand
= new ImplRegionBand( nYTop
, nYBottom
);
230 // first element? -> set as first into the list
233 mpFirstBand
= pNewBand
;
237 pCurrBand
->mpNextBand
= pNewBand
;
240 // save pointer for next creation
241 pCurrBand
= pNewBand
;
246 sal_Int32
nXRight(0);
248 rIStrm
.ReadInt32( nXLeft
);
249 rIStrm
.ReadInt32( nXRight
);
254 pCurrBand
->Union( nXLeft
, nXRight
);
260 OSL_ENSURE(false, "premature end of region stream" );
266 rIStrm
.ReadUInt16( nTmp16
);
268 while (STREAMENTRY_END
!= (StreamEntryType
)nTmp16
&& rIStrm
.good());
271 void RegionBand::save(SvStream
& rOStrm
) const
273 ImplRegionBand
* pBand
= mpFirstBand
;
278 rOStrm
.WriteUInt16( STREAMENTRY_BANDHEADER
);
279 rOStrm
.WriteInt32( pBand
->mnYTop
);
280 rOStrm
.WriteInt32( pBand
->mnYBottom
);
282 // put separations of current band
283 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
288 rOStrm
.WriteUInt16( STREAMENTRY_SEPARATION
);
289 rOStrm
.WriteInt32( pSep
->mnXLeft
);
290 rOStrm
.WriteInt32( pSep
->mnXRight
);
292 // next separation from current band
293 pSep
= pSep
->mpNextSep
;
296 pBand
= pBand
->mpNextBand
;
300 rOStrm
.WriteUInt16( STREAMENTRY_END
);
303 bool RegionBand::isSingleRectangle() const
306 if(mpFirstBand
&& !mpFirstBand
->mpNextBand
)
309 if(mpFirstBand
->mpFirstSep
&& !mpFirstBand
->mpFirstSep
->mpNextSep
)
318 void RegionBand::InsertBand(ImplRegionBand
* pPreviousBand
, ImplRegionBand
* pBandToInsert
)
320 OSL_ASSERT(pBandToInsert
!=nullptr);
324 // Insert band before all others.
327 mpFirstBand
->mpPrevBand
= pBandToInsert
;
330 pBandToInsert
->mpNextBand
= mpFirstBand
;
331 mpFirstBand
= pBandToInsert
;
335 // Insert band directly after pPreviousBand.
336 pBandToInsert
->mpNextBand
= pPreviousBand
->mpNextBand
;
337 pPreviousBand
->mpNextBand
= pBandToInsert
;
338 pBandToInsert
->mpPrevBand
= pPreviousBand
;
343 void RegionBand::processPoints()
345 ImplRegionBand
* pRegionBand
= mpFirstBand
;
349 // generate separations from the lines and process union
350 pRegionBand
->ProcessPoints();
351 pRegionBand
= pRegionBand
->mpNextBand
;
356 /** This function is similar to the RegionBand::InsertBands() method.
357 It creates a minimal set of missing bands so that the entire vertical
358 interval from nTop to nBottom is covered by bands.
360 void RegionBand::ImplAddMissingBands(const long nTop
, const long nBottom
)
362 // Iterate over already existing bands and add missing bands atop the
363 // first and between two bands.
364 ImplRegionBand
* pPreviousBand
= nullptr;
365 ImplRegionBand
* pBand
= ImplGetFirstRegionBand();
366 long nCurrentTop (nTop
);
368 while (pBand
!= nullptr && nCurrentTop
<nBottom
)
370 if (nCurrentTop
< pBand
->mnYTop
)
372 // Create new band above the current band.
373 ImplRegionBand
* pAboveBand
= new ImplRegionBand(
375 ::std::min(nBottom
,pBand
->mnYTop
-1));
376 InsertBand(pPreviousBand
, pAboveBand
);
379 // Adapt the top of the interval to prevent overlapping bands.
380 nCurrentTop
= ::std::max(nTop
, pBand
->mnYBottom
+1);
382 // Advance to next band.
383 pPreviousBand
= pBand
;
384 pBand
= pBand
->mpNextBand
;
387 // We still have to cover two cases:
388 // 1. The region does not yet contain any bands.
389 // 2. The interval nTop->nBottom extends past the bottom most band.
390 if (nCurrentTop
<= nBottom
391 && (pBand
==nullptr || nBottom
>pBand
->mnYBottom
))
393 // When there is no previous band then the new one will be the
394 // first. Otherwise the new band is inserted behind the last band.
404 void RegionBand::CreateBandRange(long nYTop
, long nYBottom
)
407 mpFirstBand
= new ImplRegionBand( nYTop
-1, nYTop
-1 );
409 // begin first search from the first element
410 mpLastCheckedBand
= mpFirstBand
;
411 ImplRegionBand
* pBand
= mpFirstBand
;
413 for ( int i
= nYTop
; i
<= nYBottom
+1; i
++ )
416 ImplRegionBand
* pNewBand
= new ImplRegionBand( i
, i
);
417 pBand
->mpNextBand
= pNewBand
;
419 if ( pBand
!= mpFirstBand
)
421 pNewBand
->mpPrevBand
= pBand
;
424 pBand
= pBand
->mpNextBand
;
429 void RegionBand::InsertLine(const Point
& rStartPt
, const Point
& rEndPt
, long nLineId
)
433 // lines consisting of a single point do not interest here
434 if ( rStartPt
== rEndPt
)
439 LineType eLineType
= (rStartPt
.Y() > rEndPt
.Y()) ? LINE_DESCENDING
: LINE_ASCENDING
;
440 if ( rStartPt
.X() == rEndPt
.X() )
443 const long nEndY
= rEndPt
.Y();
450 for ( ; nY
<= nEndY
; nY
++ )
452 Point
aNewPoint( nX
, nY
);
453 InsertPoint( aNewPoint
, nLineId
,
454 (aNewPoint
== rEndPt
) || (aNewPoint
== rStartPt
),
460 for ( ; nY
>= nEndY
; nY
-- )
462 Point
aNewPoint( nX
, nY
);
463 InsertPoint( aNewPoint
, nLineId
,
464 (aNewPoint
== rEndPt
) || (aNewPoint
== rStartPt
),
469 else if ( rStartPt
.Y() != rEndPt
.Y() )
471 const long nDX
= labs( rEndPt
.X() - rStartPt
.X() );
472 const long nDY
= labs( rEndPt
.Y() - rStartPt
.Y() );
473 const long nStartX
= rStartPt
.X();
474 const long nStartY
= rStartPt
.Y();
475 const long nEndX
= rEndPt
.X();
476 const long nEndY
= rEndPt
.Y();
477 const long nXInc
= ( nStartX
< nEndX
) ? 1 : -1;
478 const long nYInc
= ( nStartY
< nEndY
) ? 1 : -1;
482 const long nDYX
= ( nDY
- nDX
) * 2;
483 const long nDY2
= nDY
<< 1;
484 long nD
= nDY2
- nDX
;
486 for ( nX
= nStartX
, nY
= nStartY
; nX
!= nEndX
; nX
+= nXInc
)
488 InsertPoint( Point( nX
, nY
), nLineId
, nStartX
== nX
, eLineType
);
501 const long nDYX
= ( nDX
- nDY
) * 2;
502 const long nDY2
= nDX
<< 1;
503 long nD
= nDY2
- nDY
;
505 for ( nX
= nStartX
, nY
= nStartY
; nY
!= nEndY
; nY
+= nYInc
)
507 InsertPoint( Point( nX
, nY
), nLineId
, nStartY
== nY
, eLineType
);
520 InsertPoint( Point( nEndX
, nEndY
), nLineId
, true, eLineType
);
524 void RegionBand::InsertPoint(const Point
&rPoint
, long nLineID
, bool bEndPoint
, LineType eLineType
)
526 SAL_WARN_IF( mpFirstBand
== nullptr, "vcl", "RegionBand::InsertPoint - no bands available!" );
528 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
530 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
534 if ( rPoint
.Y() > mpLastCheckedBand
->mnYTop
)
537 while ( mpLastCheckedBand
)
539 // Insert point if possible
540 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
542 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
546 mpLastCheckedBand
= mpLastCheckedBand
->mpNextBand
;
549 OSL_ENSURE(false, "RegionBand::InsertPoint reached the end of the list!" );
554 while ( mpLastCheckedBand
)
556 // Insert point if possible
557 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
559 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
563 mpLastCheckedBand
= mpLastCheckedBand
->mpPrevBand
;
566 OSL_ENSURE(false, "RegionBand::InsertPoint reached the beginning of the list!" );
569 OSL_ENSURE(false, "RegionBand::InsertPoint point not inserted!" );
571 // reinitialize pointer (should never be reached!)
572 mpLastCheckedBand
= mpFirstBand
;
575 bool RegionBand::OptimizeBandList()
577 ImplRegionBand
* pPrevBand
= nullptr;
578 ImplRegionBand
* pBand
= mpFirstBand
;
582 const bool bBTEqual
= pBand
->mpNextBand
&& (pBand
->mnYBottom
== pBand
->mpNextBand
->mnYTop
);
584 // no separation? -> remove!
585 if ( pBand
->IsEmpty() || (bBTEqual
&& (pBand
->mnYBottom
== pBand
->mnYTop
)) )
588 ImplRegionBand
* pOldBand
= pBand
;
590 // previous element of the list
591 if ( pBand
== mpFirstBand
)
592 mpFirstBand
= pBand
->mpNextBand
;
594 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
596 pBand
= pBand
->mpNextBand
;
603 pBand
->mnYBottom
= pBand
->mpNextBand
->mnYTop
-1;
605 // this and next band with equal separations? -> combine!
606 if ( pBand
->mpNextBand
&&
607 ((pBand
->mnYBottom
+1) == pBand
->mpNextBand
->mnYTop
) &&
608 (*pBand
== *pBand
->mpNextBand
) )
610 // expand current height
611 pBand
->mnYBottom
= pBand
->mpNextBand
->mnYBottom
;
613 // remove next band from list
614 ImplRegionBand
* pDeletedBand
= pBand
->mpNextBand
;
615 pBand
->mpNextBand
= pDeletedBand
->mpNextBand
;
622 // count rectangles within band
623 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
626 pSep
= pSep
->mpNextSep
;
630 pBand
= pBand
->mpNextBand
;
639 SAL_WARN_IF( pBand
->mpFirstSep
== nullptr, "vcl", "Exiting RegionBand::OptimizeBandList(): empty band in region!" );
641 if ( pBand
->mnYBottom
< pBand
->mnYTop
)
642 OSL_ENSURE(false, "RegionBand::OptimizeBandList(): YBottomBoundary < YTopBoundary" );
644 if ( pBand
->mpNextBand
)
646 if ( pBand
->mnYBottom
>= pBand
->mpNextBand
->mnYTop
)
647 OSL_ENSURE(false, "RegionBand::OptimizeBandList(): overlapping bands in region!" );
650 pBand
= pBand
->mpNextBand
;
654 return (nullptr != mpFirstBand
);
657 void RegionBand::Move(long nHorzMove
, long nVertMove
)
659 ImplRegionBand
* pBand
= mpFirstBand
;
663 // process the vertical move
666 pBand
->mnYTop
= pBand
->mnYTop
+ nVertMove
;
667 pBand
->mnYBottom
= pBand
->mnYBottom
+ nVertMove
;
670 // process the horizontal move
673 pBand
->MoveX(nHorzMove
);
676 pBand
= pBand
->mpNextBand
;
681 void RegionBand::Scale(double fScaleX
, double fScaleY
)
683 ImplRegionBand
* pBand
= mpFirstBand
;
687 // process the vertical move
690 pBand
->mnYTop
= basegfx::fround(pBand
->mnYTop
* fScaleY
);
691 pBand
->mnYBottom
= basegfx::fround(pBand
->mnYBottom
* fScaleY
);
694 // process the horizontal move
697 pBand
->ScaleX(fScaleX
);
700 pBand
= pBand
->mpNextBand
;
705 void RegionBand::InsertBands(long nTop
, long nBottom
)
707 // region empty? -> set rectangle as first entry!
710 // add band with boundaries of the rectangle
711 mpFirstBand
= new ImplRegionBand( nTop
, nBottom
);
715 // find/insert bands for the boundaries of the rectangle
716 bool bTopBoundaryInserted
= false;
717 bool bTop2BoundaryInserted
= false;
718 bool bBottomBoundaryInserted
= false;
720 // special case: top boundary is above the first band
721 ImplRegionBand
* pNewBand
;
723 if ( nTop
< mpFirstBand
->mnYTop
)
725 // create new band above the first in the list
726 pNewBand
= new ImplRegionBand( nTop
, mpFirstBand
->mnYTop
);
728 if ( nBottom
< mpFirstBand
->mnYTop
)
730 pNewBand
->mnYBottom
= nBottom
;
733 // insert band into the list
734 pNewBand
->mpNextBand
= mpFirstBand
;
735 mpFirstBand
= pNewBand
;
737 bTopBoundaryInserted
= true;
740 // insert band(s) into the list
741 ImplRegionBand
* pBand
= mpFirstBand
;
745 // Insert Bands if possible
746 if ( !bTopBoundaryInserted
)
748 bTopBoundaryInserted
= InsertSingleBand( pBand
, nTop
- 1 );
751 if ( !bTop2BoundaryInserted
)
753 bTop2BoundaryInserted
= InsertSingleBand( pBand
, nTop
);
756 if ( !bBottomBoundaryInserted
&& (nTop
!= nBottom
) )
758 bBottomBoundaryInserted
= InsertSingleBand( pBand
, nBottom
);
761 // both boundaries inserted? -> nothing more to do
762 if ( bTopBoundaryInserted
&& bTop2BoundaryInserted
&& bBottomBoundaryInserted
)
767 // insert bands between two bands if necessary
768 if ( pBand
->mpNextBand
)
770 if ( (pBand
->mnYBottom
+ 1) < pBand
->mpNextBand
->mnYTop
)
772 // copy band with list and set new boundary
773 pNewBand
= new ImplRegionBand( pBand
->mnYBottom
+1, pBand
->mpNextBand
->mnYTop
-1 );
775 // insert band into the list
776 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
777 pBand
->mpNextBand
= pNewBand
;
781 pBand
= pBand
->mpNextBand
;
786 bool RegionBand::InsertSingleBand(ImplRegionBand
* pBand
, long nYBandPosition
)
788 // boundary already included in band with height 1? -> nothing to do!
789 if ( (pBand
->mnYTop
== pBand
->mnYBottom
) && (nYBandPosition
== pBand
->mnYTop
) )
794 // insert single height band on top?
795 ImplRegionBand
* pNewBand
;
797 if ( nYBandPosition
== pBand
->mnYTop
)
799 // copy band with list and set new boundary
800 pNewBand
= new ImplRegionBand( *pBand
);
801 pNewBand
->mnYTop
= nYBandPosition
+1;
803 // insert band into the list
804 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
805 pBand
->mnYBottom
= nYBandPosition
;
806 pBand
->mpNextBand
= pNewBand
;
811 // top of new rectangle within the current band? -> insert new band and copy data
812 if ( (nYBandPosition
> pBand
->mnYTop
) && (nYBandPosition
< pBand
->mnYBottom
) )
814 // copy band with list and set new boundary
815 pNewBand
= new ImplRegionBand( *pBand
);
816 pNewBand
->mnYTop
= nYBandPosition
;
818 // insert band into the list
819 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
820 pBand
->mnYBottom
= nYBandPosition
;
821 pBand
->mpNextBand
= pNewBand
;
823 // copy band with list and set new boundary
824 pNewBand
= new ImplRegionBand( *pBand
);
825 pNewBand
->mnYTop
= nYBandPosition
;
827 // insert band into the list
828 pBand
->mpNextBand
->mnYTop
= nYBandPosition
+1;
830 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
831 pBand
->mnYBottom
= nYBandPosition
- 1;
832 pBand
->mpNextBand
= pNewBand
;
837 // create new band behind the current in the list
838 if ( !pBand
->mpNextBand
)
840 if ( nYBandPosition
== pBand
->mnYBottom
)
842 // copy band with list and set new boundary
843 pNewBand
= new ImplRegionBand( *pBand
);
844 pNewBand
->mnYTop
= pBand
->mnYBottom
;
845 pNewBand
->mnYBottom
= nYBandPosition
;
847 pBand
->mnYBottom
= nYBandPosition
-1;
849 // append band to the list
850 pBand
->mpNextBand
= pNewBand
;
854 if ( nYBandPosition
> pBand
->mnYBottom
)
857 pNewBand
= new ImplRegionBand( pBand
->mnYBottom
+ 1, nYBandPosition
);
859 // append band to the list
860 pBand
->mpNextBand
= pNewBand
;
868 void RegionBand::Union(long nLeft
, long nTop
, long nRight
, long nBottom
)
870 SAL_WARN_IF( nLeft
> nRight
, "vcl", "RegionBand::Union() - nLeft > nRight" );
871 SAL_WARN_IF( nTop
> nBottom
, "vcl", "RegionBand::Union() - nTop > nBottom" );
874 ImplRegionBand
* pBand
= mpFirstBand
;
877 if ( pBand
->mnYTop
>= nTop
)
879 if ( pBand
->mnYBottom
<= nBottom
)
880 pBand
->Union( nLeft
, nRight
);
884 long nCurY
= pBand
->mnYBottom
;
885 pBand
= pBand
->mpNextBand
;
888 if ( (pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
) )
890 OSL_ENSURE(false, "RegionBand::Union() - Bands not sorted!" );
892 pBand
= pBand
->mpNextBand
;
899 pBand
= pBand
->mpNextBand
;
904 void RegionBand::Intersect(long nLeft
, long nTop
, long nRight
, long nBottom
)
906 // process intersections
907 ImplRegionBand
* pPrevBand
= nullptr;
908 ImplRegionBand
* pBand
= mpFirstBand
;
912 // band within intersection boundary? -> process. otherwise remove
913 if((pBand
->mnYTop
>= nTop
) && (pBand
->mnYBottom
<= nBottom
))
915 // process intersection
916 pBand
->Intersect(nLeft
, nRight
);
918 pBand
= pBand
->mpNextBand
;
922 ImplRegionBand
* pOldBand
= pBand
;
924 if(pBand
== mpFirstBand
)
926 mpFirstBand
= pBand
->mpNextBand
;
930 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
933 pBand
= pBand
->mpNextBand
;
940 void RegionBand::Union(const RegionBand
& rSource
)
942 // apply all rectangles from rSource to this
943 ImplRegionBand
* pBand
= rSource
.mpFirstBand
;
947 // insert bands if the boundaries are not already in the list
948 InsertBands(pBand
->mnYTop
, pBand
->mnYBottom
);
950 // process all elements of the list
951 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
955 Union(pSep
->mnXLeft
, pBand
->mnYTop
, pSep
->mnXRight
, pBand
->mnYBottom
);
956 pSep
= pSep
->mpNextSep
;
959 pBand
= pBand
->mpNextBand
;
964 void RegionBand::Exclude(long nLeft
, long nTop
, long nRight
, long nBottom
)
966 SAL_WARN_IF( nLeft
> nRight
, "vcl", "RegionBand::Exclude() - nLeft > nRight" );
967 SAL_WARN_IF( nTop
> nBottom
, "vcl", "RegionBand::Exclude() - nTop > nBottom" );
970 ImplRegionBand
* pBand
= mpFirstBand
;
974 if(pBand
->mnYTop
>= nTop
)
976 if(pBand
->mnYBottom
<= nBottom
)
978 pBand
->Exclude(nLeft
, nRight
);
983 long nCurY
= pBand
->mnYBottom
;
984 pBand
= pBand
->mpNextBand
;
988 if((pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
))
990 OSL_ENSURE(false, "RegionBand::Exclude() - Bands not sorted!" );
993 pBand
= pBand
->mpNextBand
;
1000 pBand
= pBand
->mpNextBand
;
1005 void RegionBand::XOr(long nLeft
, long nTop
, long nRight
, long nBottom
)
1007 SAL_WARN_IF( nLeft
> nRight
, "vcl", "RegionBand::Exclude() - nLeft > nRight" );
1008 SAL_WARN_IF( nTop
> nBottom
, "vcl", "RegionBand::Exclude() - nTop > nBottom" );
1011 ImplRegionBand
* pBand
= mpFirstBand
;
1015 if(pBand
->mnYTop
>= nTop
)
1017 if(pBand
->mnYBottom
<= nBottom
)
1019 pBand
->XOr(nLeft
, nRight
);
1024 long nCurY
= pBand
->mnYBottom
;
1025 pBand
= pBand
->mpNextBand
;
1029 if((pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
))
1031 OSL_ENSURE(false, "RegionBand::XOr() - Bands not sorted!" );
1034 pBand
= pBand
->mpNextBand
;
1041 pBand
= pBand
->mpNextBand
;
1046 void RegionBand::Intersect(const RegionBand
& rSource
)
1048 // mark all bands as untouched
1049 ImplRegionBand
* pBand
= mpFirstBand
;
1053 pBand
->mbTouched
= false;
1054 pBand
= pBand
->mpNextBand
;
1057 pBand
= rSource
.mpFirstBand
;
1061 // insert bands if the boundaries are not already in the list
1062 InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1064 // process all elements of the list
1065 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1070 if ( pSep
== pBand
->mpFirstSep
)
1072 // process intersection and do not remove untouched bands
1073 Exclude( LONG_MIN
+1, pBand
->mnYTop
, pSep
->mnXLeft
-1, pBand
->mnYBottom
);
1077 if ( pSep
->mpNextSep
== nullptr )
1079 // process intersection and do not remove untouched bands
1080 Exclude( pSep
->mnXRight
+1, pBand
->mnYTop
, LONG_MAX
-1, pBand
->mnYBottom
);
1084 // process intersection and do not remove untouched bands
1085 Exclude( pSep
->mnXRight
+1, pBand
->mnYTop
, pSep
->mpNextSep
->mnXLeft
-1, pBand
->mnYBottom
);
1088 pSep
= pSep
->mpNextSep
;
1091 pBand
= pBand
->mpNextBand
;
1094 // remove all untouched bands if bands already left
1095 ImplRegionBand
* pPrevBand
= nullptr;
1096 pBand
= mpFirstBand
;
1100 if ( !pBand
->mbTouched
)
1103 ImplRegionBand
* pOldBand
= pBand
;
1105 // previous element of the list
1106 if ( pBand
== mpFirstBand
)
1108 mpFirstBand
= pBand
->mpNextBand
;
1112 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
1115 pBand
= pBand
->mpNextBand
;
1121 pBand
= pBand
->mpNextBand
;
1127 bool RegionBand::Exclude(const RegionBand
& rSource
)
1129 // apply all rectangles to the region passed to this region
1130 ImplRegionBand
* pBand
= rSource
.mpFirstBand
;
1134 // insert bands if the boundaries are not already in the list
1135 InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1137 // process all elements of the list
1138 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1142 Exclude( pSep
->mnXLeft
, pBand
->mnYTop
, pSep
->mnXRight
, pBand
->mnYBottom
);
1143 pSep
= pSep
->mpNextSep
;
1146 // to test less bands, already check in the loop
1147 if ( !OptimizeBandList() )
1152 pBand
= pBand
->mpNextBand
;
1158 tools::Rectangle
RegionBand::GetBoundRect() const
1161 // get the boundaries of the first band
1162 long nYTop(mpFirstBand
->mnYTop
);
1163 long nYBottom(mpFirstBand
->mnYBottom
);
1164 long nXLeft(mpFirstBand
->GetXLeftBoundary());
1165 long nXRight(mpFirstBand
->GetXRightBoundary());
1167 // look in the band list (don't test first band again!)
1168 ImplRegionBand
* pBand
= mpFirstBand
->mpNextBand
;
1172 nYBottom
= pBand
->mnYBottom
;
1173 nXLeft
= std::min( nXLeft
, pBand
->GetXLeftBoundary() );
1174 nXRight
= std::max( nXRight
, pBand
->GetXRightBoundary() );
1176 pBand
= pBand
->mpNextBand
;
1179 return tools::Rectangle( nXLeft
, nYTop
, nXRight
, nYBottom
);
1182 void RegionBand::XOr(const RegionBand
& rSource
)
1184 ImplRegionBand
* pBand
= rSource
.mpFirstBand
;
1188 // insert bands if the boundaries are not already in the list
1189 InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1191 // process all elements of the list
1192 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1196 XOr( pSep
->mnXLeft
, pBand
->mnYTop
, pSep
->mnXRight
, pBand
->mnYBottom
);
1197 pSep
= pSep
->mpNextSep
;
1200 pBand
= pBand
->mpNextBand
;
1204 bool RegionBand::IsInside(const Point
& rPoint
) const
1208 ImplRegionBand
* pBand
= mpFirstBand
;
1212 // is point within band?
1213 if((pBand
->mnYTop
<= rPoint
.Y()) && (pBand
->mnYBottom
>= rPoint
.Y()))
1215 // is point within separation of the band?
1216 return pBand
->IsInside(rPoint
.X());
1219 pBand
= pBand
->mpNextBand
;
1225 void RegionBand::GetRegionRectangles(RectangleVector
& rTarget
) const
1227 // clear result vector
1229 ImplRegionBand
* pCurrRectBand
= mpFirstBand
;
1230 tools::Rectangle aRectangle
;
1232 while(pCurrRectBand
)
1234 ImplRegionBandSep
* pCurrRectBandSep
= pCurrRectBand
->mpFirstSep
;
1236 aRectangle
.Top() = pCurrRectBand
->mnYTop
;
1237 aRectangle
.Bottom() = pCurrRectBand
->mnYBottom
;
1239 while(pCurrRectBandSep
)
1241 aRectangle
.Left() = pCurrRectBandSep
->mnXLeft
;
1242 aRectangle
.Right() = pCurrRectBandSep
->mnXRight
;
1243 rTarget
.push_back(aRectangle
);
1244 pCurrRectBandSep
= pCurrRectBandSep
->mpNextSep
;
1247 pCurrRectBand
= pCurrRectBand
->mpNextBand
;
1251 sal_uInt32
RegionBand::getRectangleCount() const
1253 sal_uInt32 nCount
= 0;
1254 const ImplRegionBand
* pBand
= mpFirstBand
;
1258 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1263 pSep
= pSep
->mpNextSep
;
1266 pBand
= pBand
->mpNextBand
;
1273 const char* ImplDbgTestRegionBand(const void* pObj
)
1275 const RegionBand
* pRegionBand
= static_cast< const RegionBand
* >(pObj
);
1279 const ImplRegionBand
* pBand
= pRegionBand
->ImplGetFirstRegionBand();
1283 if(pBand
->mnYBottom
< pBand
->mnYTop
)
1285 return "YBottom < YTop";
1288 if(pBand
->mpNextBand
)
1290 if(pBand
->mnYBottom
>= pBand
->mpNextBand
->mnYTop
)
1292 return "overlapping bands in region";
1296 if(pBand
->mbTouched
)
1298 return "Band-mbTouched overwrite";
1301 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1305 if(pSep
->mnXRight
< pSep
->mnXLeft
)
1307 return "XLeft < XRight";
1312 if(pSep
->mnXRight
>= pSep
->mpNextSep
->mnXLeft
)
1314 return "overlapping separations in region";
1318 if ( pSep
->mbRemoved
)
1320 return "Sep-mbRemoved overwrite";
1323 pSep
= pSep
->mpNextSep
;
1326 pBand
= pBand
->mpNextBand
;
1334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */