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 <sal/config.h>
24 #include <tools/stream.hxx>
25 #include <regionband.hxx>
26 #include <osl/diagnose.h>
27 #include <sal/log.hxx>
29 RegionBand::RegionBand()
30 : mpFirstBand(nullptr),
31 mpLastCheckedBand(nullptr)
35 RegionBand::RegionBand(const RegionBand
& rRef
)
36 : mpFirstBand(nullptr),
37 mpLastCheckedBand(nullptr)
42 RegionBand
& RegionBand::operator=(const RegionBand
& rRef
)
46 ImplRegionBand
* pPrevBand
= nullptr;
47 ImplRegionBand
* pBand
= rRef
.mpFirstBand
;
51 ImplRegionBand
* pNewBand
= new ImplRegionBand(*pBand
);
53 // first element? -> set as first into the list
54 if(pBand
== rRef
.mpFirstBand
)
56 mpFirstBand
= pNewBand
;
60 pPrevBand
->mpNextBand
= pNewBand
;
64 pBand
= pBand
->mpNextBand
;
70 RegionBand::RegionBand(const tools::Rectangle
& rRect
)
71 : mpFirstBand(nullptr),
72 mpLastCheckedBand(nullptr)
74 const tools::Long
nTop(std::min(rRect
.Top(), rRect
.Bottom()));
75 const tools::Long
nBottom(std::max(rRect
.Top(), rRect
.Bottom()));
76 const tools::Long
nLeft(std::min(rRect
.Left(), rRect
.Right()));
77 const tools::Long
nRight(std::max(rRect
.Left(), rRect
.Right()));
79 // add band with boundaries of the rectangle
80 mpFirstBand
= new ImplRegionBand(nTop
, nBottom
);
82 // Set left and right boundaries of the band
83 mpFirstBand
->Union(nLeft
, nRight
);
87 void RegionBand::implReset()
89 ImplRegionBand
* pBand
= mpFirstBand
;
93 ImplRegionBand
* pTempBand
= pBand
->mpNextBand
;
98 mpLastCheckedBand
= nullptr;
99 mpFirstBand
= nullptr;
102 RegionBand::~RegionBand()
107 bool RegionBand::operator==( const RegionBand
& rRegionBand
) const
110 // initialise pointers
111 ImplRegionBand
* pOwnRectBand
= mpFirstBand
;
112 ImplRegionBandSep
* pOwnRectBandSep
= pOwnRectBand
->mpFirstSep
;
113 ImplRegionBand
* pSecondRectBand
= rRegionBand
.mpFirstBand
;
114 ImplRegionBandSep
* pSecondRectBandSep
= pSecondRectBand
->mpFirstSep
;
116 while ( pOwnRectBandSep
&& pSecondRectBandSep
)
118 // get boundaries of current rectangle
119 tools::Long nOwnXLeft
= pOwnRectBandSep
->mnXLeft
;
120 tools::Long nSecondXLeft
= pSecondRectBandSep
->mnXLeft
;
122 if ( nOwnXLeft
!= nSecondXLeft
)
127 tools::Long nOwnYTop
= pOwnRectBand
->mnYTop
;
128 tools::Long nSecondYTop
= pSecondRectBand
->mnYTop
;
130 if ( nOwnYTop
!= nSecondYTop
)
135 tools::Long nOwnXRight
= pOwnRectBandSep
->mnXRight
;
136 tools::Long nSecondXRight
= pSecondRectBandSep
->mnXRight
;
138 if ( nOwnXRight
!= nSecondXRight
)
143 tools::Long nOwnYBottom
= pOwnRectBand
->mnYBottom
;
144 tools::Long nSecondYBottom
= pSecondRectBand
->mnYBottom
;
146 if ( nOwnYBottom
!= nSecondYBottom
)
151 // get next separation from current band
152 pOwnRectBandSep
= pOwnRectBandSep
->mpNextSep
;
154 // no separation found? -> go to next band!
155 if ( !pOwnRectBandSep
)
158 pOwnRectBand
= pOwnRectBand
->mpNextBand
;
160 // get first separation in current band
163 pOwnRectBandSep
= pOwnRectBand
->mpFirstSep
;
167 // get next separation from current band
168 pSecondRectBandSep
= pSecondRectBandSep
->mpNextSep
;
170 // no separation found? -> go to next band!
171 if ( !pSecondRectBandSep
)
174 pSecondRectBand
= pSecondRectBand
->mpNextBand
;
176 // get first separation in current band
177 if( pSecondRectBand
)
179 pSecondRectBandSep
= pSecondRectBand
->mpFirstSep
;
183 if ( pOwnRectBandSep
&& !pSecondRectBandSep
)
188 if ( !pOwnRectBandSep
&& pSecondRectBandSep
)
199 enum StreamEntryType
{ STREAMENTRY_BANDHEADER
, STREAMENTRY_SEPARATION
, STREAMENTRY_END
};
203 bool RegionBand::load(SvStream
& rIStrm
)
205 // clear this instance data
209 ImplRegionBand
* pCurrBand
= nullptr;
211 // get header from first element
212 sal_uInt16
nTmp16(STREAMENTRY_END
);
213 rIStrm
.ReadUInt16(nTmp16
);
215 if (STREAMENTRY_END
== static_cast<StreamEntryType
>(nTmp16
))
218 size_t nRecordsPossible
= rIStrm
.remainingSize() / (2*sizeof(sal_Int32
));
219 if (!nRecordsPossible
)
221 OSL_ENSURE(false, "premature end of region stream" );
228 // insert new band or new separation?
229 if(STREAMENTRY_BANDHEADER
== static_cast<StreamEntryType
>(nTmp16
))
232 sal_Int32
nYBottom(0);
234 rIStrm
.ReadInt32( nYTop
);
235 rIStrm
.ReadInt32( nYBottom
);
238 ImplRegionBand
* pNewBand
= new ImplRegionBand( nYTop
, nYBottom
);
240 // first element? -> set as first into the list
243 mpFirstBand
= pNewBand
;
247 pCurrBand
->mpNextBand
= pNewBand
;
250 // save pointer for next creation
251 pCurrBand
= pNewBand
;
256 sal_Int32
nXRight(0);
258 rIStrm
.ReadInt32( nXLeft
);
259 rIStrm
.ReadInt32( nXRight
);
264 pCurrBand
->Union( nXLeft
, nXRight
);
270 OSL_ENSURE(false, "premature end of region stream" );
276 rIStrm
.ReadUInt16( nTmp16
);
278 while (STREAMENTRY_END
!= static_cast<StreamEntryType
>(nTmp16
) && rIStrm
.good());
279 if (!CheckConsistency())
287 void RegionBand::save(SvStream
& rOStrm
) const
289 ImplRegionBand
* pBand
= mpFirstBand
;
294 rOStrm
.WriteUInt16( STREAMENTRY_BANDHEADER
);
295 rOStrm
.WriteInt32( pBand
->mnYTop
);
296 rOStrm
.WriteInt32( pBand
->mnYBottom
);
298 // put separations of current band
299 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
304 rOStrm
.WriteUInt16( STREAMENTRY_SEPARATION
);
305 rOStrm
.WriteInt32( pSep
->mnXLeft
);
306 rOStrm
.WriteInt32( pSep
->mnXRight
);
308 // next separation from current band
309 pSep
= pSep
->mpNextSep
;
312 pBand
= pBand
->mpNextBand
;
316 rOStrm
.WriteUInt16( STREAMENTRY_END
);
319 bool RegionBand::isSingleRectangle() const
322 if(mpFirstBand
&& !mpFirstBand
->mpNextBand
)
325 if(mpFirstBand
->mpFirstSep
&& !mpFirstBand
->mpFirstSep
->mpNextSep
)
334 void RegionBand::InsertBand(ImplRegionBand
* pPreviousBand
, ImplRegionBand
* pBandToInsert
)
336 OSL_ASSERT(pBandToInsert
!=nullptr);
340 // Insert band before all others.
343 mpFirstBand
->mpPrevBand
= pBandToInsert
;
346 pBandToInsert
->mpNextBand
= mpFirstBand
;
347 mpFirstBand
= pBandToInsert
;
351 // Insert band directly after pPreviousBand.
352 pBandToInsert
->mpNextBand
= pPreviousBand
->mpNextBand
;
353 pPreviousBand
->mpNextBand
= pBandToInsert
;
354 pBandToInsert
->mpPrevBand
= pPreviousBand
;
359 void RegionBand::processPoints()
361 ImplRegionBand
* pRegionBand
= mpFirstBand
;
365 // generate separations from the lines and process union
366 pRegionBand
->ProcessPoints();
367 pRegionBand
= pRegionBand
->mpNextBand
;
372 /** This function is similar to the RegionBand::InsertBands() method.
373 It creates a minimal set of missing bands so that the entire vertical
374 interval from nTop to nBottom is covered by bands.
376 void RegionBand::ImplAddMissingBands(const tools::Long nTop
, const tools::Long nBottom
)
378 // Iterate over already existing bands and add missing bands atop the
379 // first and between two bands.
380 ImplRegionBand
* pPreviousBand
= nullptr;
381 ImplRegionBand
* pBand
= ImplGetFirstRegionBand();
382 tools::Long
nCurrentTop (nTop
);
384 while (pBand
!= nullptr && nCurrentTop
<nBottom
)
386 if (nCurrentTop
< pBand
->mnYTop
)
388 // Create new band above the current band.
389 ImplRegionBand
* pAboveBand
= new ImplRegionBand(
391 ::std::min(nBottom
,pBand
->mnYTop
-1));
392 InsertBand(pPreviousBand
, pAboveBand
);
395 // Adapt the top of the interval to prevent overlapping bands.
396 nCurrentTop
= ::std::max(nTop
, pBand
->mnYBottom
+1);
398 // Advance to next band.
399 pPreviousBand
= pBand
;
400 pBand
= pBand
->mpNextBand
;
403 // We still have to cover two cases:
404 // 1. The region does not yet contain any bands.
405 // 2. The interval nTop->nBottom extends past the bottom most band.
406 if (nCurrentTop
<= nBottom
407 && (pBand
==nullptr || nBottom
>pBand
->mnYBottom
))
409 // When there is no previous band then the new one will be the
410 // first. Otherwise the new band is inserted behind the last band.
420 void RegionBand::CreateBandRange(tools::Long nYTop
, tools::Long nYBottom
)
423 mpFirstBand
= new ImplRegionBand( nYTop
-1, nYTop
-1 );
425 // begin first search from the first element
426 mpLastCheckedBand
= mpFirstBand
;
427 ImplRegionBand
* pBand
= mpFirstBand
;
429 for ( tools::Long i
= nYTop
; i
<= nYBottom
+1; i
++ )
432 ImplRegionBand
* pNewBand
= new ImplRegionBand( i
, i
);
433 pBand
->mpNextBand
= pNewBand
;
435 if ( pBand
!= mpFirstBand
)
437 pNewBand
->mpPrevBand
= pBand
;
440 pBand
= pBand
->mpNextBand
;
445 void RegionBand::InsertLine(const Point
& rStartPt
, const Point
& rEndPt
, tools::Long nLineId
)
449 // lines consisting of a single point do not interest here
450 if ( rStartPt
== rEndPt
)
455 LineType eLineType
= (rStartPt
.Y() > rEndPt
.Y()) ? LineType::Descending
: LineType::Ascending
;
456 if ( rStartPt
.X() == rEndPt
.X() )
459 const tools::Long nEndY
= rEndPt
.Y();
466 for ( ; nY
<= nEndY
; nY
++ )
468 Point
aNewPoint( nX
, nY
);
469 InsertPoint( aNewPoint
, nLineId
,
470 (aNewPoint
== rEndPt
) || (aNewPoint
== rStartPt
),
476 for ( ; nY
>= nEndY
; nY
-- )
478 Point
aNewPoint( nX
, nY
);
479 InsertPoint( aNewPoint
, nLineId
,
480 (aNewPoint
== rEndPt
) || (aNewPoint
== rStartPt
),
485 else if ( rStartPt
.Y() != rEndPt
.Y() )
487 const tools::Long nDX
= std::abs( rEndPt
.X() - rStartPt
.X() );
488 const tools::Long nDY
= std::abs( rEndPt
.Y() - rStartPt
.Y() );
489 const tools::Long nStartX
= rStartPt
.X();
490 const tools::Long nStartY
= rStartPt
.Y();
491 const tools::Long nEndX
= rEndPt
.X();
492 const tools::Long nEndY
= rEndPt
.Y();
493 const tools::Long nXInc
= ( nStartX
< nEndX
) ? 1 : -1;
494 const tools::Long nYInc
= ( nStartY
< nEndY
) ? 1 : -1;
498 const tools::Long nDYX
= ( nDY
- nDX
) * 2;
499 const tools::Long nDY2
= nDY
<< 1;
500 tools::Long nD
= nDY2
- nDX
;
502 for ( nX
= nStartX
, nY
= nStartY
; nX
!= nEndX
; nX
+= nXInc
)
504 InsertPoint( Point( nX
, nY
), nLineId
, nStartX
== nX
, eLineType
);
517 const tools::Long nDYX
= ( nDX
- nDY
) * 2;
518 const tools::Long nDY2
= nDX
<< 1;
519 tools::Long nD
= nDY2
- nDY
;
521 for ( nX
= nStartX
, nY
= nStartY
; nY
!= nEndY
; nY
+= nYInc
)
523 InsertPoint( Point( nX
, nY
), nLineId
, nStartY
== nY
, eLineType
);
536 InsertPoint( Point( nEndX
, nEndY
), nLineId
, true, eLineType
);
540 void RegionBand::InsertPoint(const Point
&rPoint
, tools::Long nLineID
, bool bEndPoint
, LineType eLineType
)
542 SAL_WARN_IF( mpFirstBand
== nullptr, "vcl", "RegionBand::InsertPoint - no bands available!" );
544 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
546 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
550 if ( rPoint
.Y() > mpLastCheckedBand
->mnYTop
)
553 while ( mpLastCheckedBand
)
555 // Insert point if possible
556 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
558 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
562 mpLastCheckedBand
= mpLastCheckedBand
->mpNextBand
;
565 OSL_ENSURE(false, "RegionBand::InsertPoint reached the end of the list!" );
570 while ( mpLastCheckedBand
)
572 // Insert point if possible
573 if ( rPoint
.Y() == mpLastCheckedBand
->mnYTop
)
575 mpLastCheckedBand
->InsertPoint( rPoint
.X(), nLineID
, bEndPoint
, eLineType
);
579 mpLastCheckedBand
= mpLastCheckedBand
->mpPrevBand
;
582 OSL_ENSURE(false, "RegionBand::InsertPoint reached the beginning of the list!" );
585 OSL_ENSURE(false, "RegionBand::InsertPoint point not inserted!" );
587 // reinitialize pointer (should never be reached!)
588 mpLastCheckedBand
= mpFirstBand
;
591 bool RegionBand::OptimizeBandList()
593 ImplRegionBand
* pPrevBand
= nullptr;
594 ImplRegionBand
* pBand
= mpFirstBand
;
598 const bool bBTEqual
= pBand
->mpNextBand
&& (pBand
->mnYBottom
== pBand
->mpNextBand
->mnYTop
);
600 // no separation? -> remove!
601 if ( pBand
->IsEmpty() || (bBTEqual
&& (pBand
->mnYBottom
== pBand
->mnYTop
)) )
604 ImplRegionBand
* pOldBand
= pBand
;
606 // previous element of the list
607 if ( pBand
== mpFirstBand
)
608 mpFirstBand
= pBand
->mpNextBand
;
610 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
612 pBand
= pBand
->mpNextBand
;
619 pBand
->mnYBottom
= pBand
->mpNextBand
->mnYTop
-1;
621 // this and next band with equal separations? -> combine!
622 if ( pBand
->mpNextBand
&&
623 ((pBand
->mnYBottom
+1) == pBand
->mpNextBand
->mnYTop
) &&
624 (*pBand
== *pBand
->mpNextBand
) )
626 // expand current height
627 pBand
->mnYBottom
= pBand
->mpNextBand
->mnYBottom
;
629 // remove next band from list
630 ImplRegionBand
* pDeletedBand
= pBand
->mpNextBand
;
631 pBand
->mpNextBand
= pDeletedBand
->mpNextBand
;
638 // count rectangles within band
639 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
642 pSep
= pSep
->mpNextSep
;
646 pBand
= pBand
->mpNextBand
;
655 SAL_WARN_IF( pBand
->mpFirstSep
== nullptr, "vcl", "Exiting RegionBand::OptimizeBandList(): empty band in region!" );
657 if ( pBand
->mnYBottom
< pBand
->mnYTop
)
658 OSL_ENSURE(false, "RegionBand::OptimizeBandList(): YBottomBoundary < YTopBoundary" );
660 if ( pBand
->mpNextBand
&& pBand
->mnYBottom
>= pBand
->mpNextBand
->mnYTop
)
661 OSL_ENSURE(false, "RegionBand::OptimizeBandList(): overlapping bands in region!" );
663 pBand
= pBand
->mpNextBand
;
667 return (nullptr != mpFirstBand
);
670 void RegionBand::Move(tools::Long nHorzMove
, tools::Long nVertMove
)
672 ImplRegionBand
* pBand
= mpFirstBand
;
676 // process the vertical move
679 pBand
->mnYTop
= pBand
->mnYTop
+ nVertMove
;
680 pBand
->mnYBottom
= pBand
->mnYBottom
+ nVertMove
;
683 // process the horizontal move
686 pBand
->MoveX(nHorzMove
);
689 pBand
= pBand
->mpNextBand
;
694 void RegionBand::Scale(double fScaleX
, double fScaleY
)
696 ImplRegionBand
* pBand
= mpFirstBand
;
700 // process the vertical move
703 pBand
->mnYTop
= basegfx::fround(pBand
->mnYTop
* fScaleY
);
704 pBand
->mnYBottom
= basegfx::fround(pBand
->mnYBottom
* fScaleY
);
707 // process the horizontal move
710 pBand
->ScaleX(fScaleX
);
713 pBand
= pBand
->mpNextBand
;
718 void RegionBand::InsertBands(tools::Long nTop
, tools::Long nBottom
)
720 // region empty? -> set rectangle as first entry!
723 // add band with boundaries of the rectangle
724 mpFirstBand
= new ImplRegionBand( nTop
, nBottom
);
728 // find/insert bands for the boundaries of the rectangle
729 bool bTopBoundaryInserted
= false;
730 bool bTop2BoundaryInserted
= false;
731 bool bBottomBoundaryInserted
= false;
733 // special case: top boundary is above the first band
734 ImplRegionBand
* pNewBand
;
736 if ( nTop
< mpFirstBand
->mnYTop
)
738 // create new band above the first in the list
739 pNewBand
= new ImplRegionBand( nTop
, mpFirstBand
->mnYTop
);
741 if ( nBottom
< mpFirstBand
->mnYTop
)
743 pNewBand
->mnYBottom
= nBottom
;
746 // insert band into the list
747 pNewBand
->mpNextBand
= mpFirstBand
;
748 mpFirstBand
= pNewBand
;
750 bTopBoundaryInserted
= true;
753 // insert band(s) into the list
754 ImplRegionBand
* pBand
= mpFirstBand
;
758 // Insert Bands if possible
759 if ( !bTopBoundaryInserted
)
761 bTopBoundaryInserted
= InsertSingleBand( pBand
, nTop
- 1 );
764 if ( !bTop2BoundaryInserted
)
766 bTop2BoundaryInserted
= InsertSingleBand( pBand
, nTop
);
769 if ( !bBottomBoundaryInserted
&& (nTop
!= nBottom
) )
771 bBottomBoundaryInserted
= InsertSingleBand( pBand
, nBottom
);
774 // both boundaries inserted? -> nothing more to do
775 if ( bTopBoundaryInserted
&& bTop2BoundaryInserted
&& bBottomBoundaryInserted
)
780 // insert bands between two bands if necessary
781 if ( pBand
->mpNextBand
)
783 if ( (pBand
->mnYBottom
+ 1) < pBand
->mpNextBand
->mnYTop
)
785 // copy band with list and set new boundary
786 pNewBand
= new ImplRegionBand( pBand
->mnYBottom
+1, pBand
->mpNextBand
->mnYTop
-1 );
788 // insert band into the list
789 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
790 pBand
->mpNextBand
= pNewBand
;
794 pBand
= pBand
->mpNextBand
;
799 bool RegionBand::InsertSingleBand(ImplRegionBand
* pBand
, tools::Long nYBandPosition
)
801 // boundary already included in band with height 1? -> nothing to do!
802 if ( (pBand
->mnYTop
== pBand
->mnYBottom
) && (nYBandPosition
== pBand
->mnYTop
) )
807 // insert single height band on top?
808 ImplRegionBand
* pNewBand
;
810 if ( nYBandPosition
== pBand
->mnYTop
)
812 // copy band with list and set new boundary
813 pNewBand
= new ImplRegionBand( *pBand
);
814 pNewBand
->mnYTop
= nYBandPosition
+1;
816 // insert band into the list
817 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
818 pBand
->mnYBottom
= nYBandPosition
;
819 pBand
->mpNextBand
= pNewBand
;
824 // top of new rectangle within the current band? -> insert new band and copy data
825 if ( (nYBandPosition
> pBand
->mnYTop
) && (nYBandPosition
< pBand
->mnYBottom
) )
827 // copy band with list and set new boundary
828 pNewBand
= new ImplRegionBand( *pBand
);
829 pNewBand
->mnYTop
= nYBandPosition
;
831 // insert band into the list
832 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
833 pBand
->mnYBottom
= nYBandPosition
;
834 pBand
->mpNextBand
= pNewBand
;
836 // copy band with list and set new boundary
837 pNewBand
= new ImplRegionBand( *pBand
);
838 pNewBand
->mnYTop
= nYBandPosition
;
840 // insert band into the list
841 pBand
->mpNextBand
->mnYTop
= nYBandPosition
+1;
843 pNewBand
->mpNextBand
= pBand
->mpNextBand
;
844 pBand
->mnYBottom
= nYBandPosition
- 1;
845 pBand
->mpNextBand
= pNewBand
;
850 // create new band behind the current in the list
851 if ( !pBand
->mpNextBand
)
853 if ( nYBandPosition
== pBand
->mnYBottom
)
855 // copy band with list and set new boundary
856 pNewBand
= new ImplRegionBand( *pBand
);
857 pNewBand
->mnYTop
= pBand
->mnYBottom
;
858 pNewBand
->mnYBottom
= nYBandPosition
;
860 pBand
->mnYBottom
= nYBandPosition
-1;
862 // append band to the list
863 pBand
->mpNextBand
= pNewBand
;
867 if ( nYBandPosition
> pBand
->mnYBottom
)
870 pNewBand
= new ImplRegionBand( pBand
->mnYBottom
+ 1, nYBandPosition
);
872 // append band to the list
873 pBand
->mpNextBand
= pNewBand
;
881 void RegionBand::Union(tools::Long nLeft
, tools::Long nTop
, tools::Long nRight
, tools::Long nBottom
)
883 SAL_WARN_IF( nLeft
> nRight
, "vcl", "RegionBand::Union() - nLeft > nRight" );
884 SAL_WARN_IF( nTop
> nBottom
, "vcl", "RegionBand::Union() - nTop > nBottom" );
887 ImplRegionBand
* pBand
= mpFirstBand
;
890 if ( pBand
->mnYTop
>= nTop
)
892 if ( pBand
->mnYBottom
<= nBottom
)
893 pBand
->Union( nLeft
, nRight
);
897 tools::Long nCurY
= pBand
->mnYBottom
;
898 pBand
= pBand
->mpNextBand
;
901 if ( (pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
) )
903 OSL_ENSURE(false, "RegionBand::Union() - Bands not sorted!" );
905 pBand
= pBand
->mpNextBand
;
912 pBand
= pBand
->mpNextBand
;
917 void RegionBand::Intersect(tools::Long nLeft
, tools::Long nTop
, tools::Long nRight
, tools::Long nBottom
)
919 // process intersections
920 ImplRegionBand
* pPrevBand
= nullptr;
921 ImplRegionBand
* pBand
= mpFirstBand
;
925 // band within intersection boundary? -> process. otherwise remove
926 if((pBand
->mnYTop
>= nTop
) && (pBand
->mnYBottom
<= nBottom
))
928 // process intersection
929 pBand
->Intersect(nLeft
, nRight
);
931 pBand
= pBand
->mpNextBand
;
935 ImplRegionBand
* pOldBand
= pBand
;
937 if(pBand
== mpFirstBand
)
939 mpFirstBand
= pBand
->mpNextBand
;
943 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
946 pBand
= pBand
->mpNextBand
;
953 void RegionBand::Union(const RegionBand
& rSource
)
955 // apply all rectangles from rSource to this
956 ImplRegionBand
* pBand
= rSource
.mpFirstBand
;
960 // insert bands if the boundaries are not already in the list
961 InsertBands(pBand
->mnYTop
, pBand
->mnYBottom
);
963 // process all elements of the list
964 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
968 Union(pSep
->mnXLeft
, pBand
->mnYTop
, pSep
->mnXRight
, pBand
->mnYBottom
);
969 pSep
= pSep
->mpNextSep
;
972 pBand
= pBand
->mpNextBand
;
977 void RegionBand::Exclude(tools::Long nLeft
, tools::Long nTop
, tools::Long nRight
, tools::Long nBottom
)
979 SAL_WARN_IF( nLeft
> nRight
, "vcl", "RegionBand::Exclude() - nLeft > nRight" );
980 SAL_WARN_IF( nTop
> nBottom
, "vcl", "RegionBand::Exclude() - nTop > nBottom" );
983 ImplRegionBand
* pBand
= mpFirstBand
;
987 if(pBand
->mnYTop
>= nTop
)
989 if(pBand
->mnYBottom
<= nBottom
)
991 pBand
->Exclude(nLeft
, nRight
);
996 tools::Long nCurY
= pBand
->mnYBottom
;
997 pBand
= pBand
->mpNextBand
;
1001 if((pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
))
1003 OSL_ENSURE(false, "RegionBand::Exclude() - Bands not sorted!" );
1006 pBand
= pBand
->mpNextBand
;
1013 pBand
= pBand
->mpNextBand
;
1018 void RegionBand::XOr(tools::Long nLeft
, tools::Long nTop
, tools::Long nRight
, tools::Long nBottom
)
1020 SAL_WARN_IF( nLeft
> nRight
, "vcl", "RegionBand::Exclude() - nLeft > nRight" );
1021 SAL_WARN_IF( nTop
> nBottom
, "vcl", "RegionBand::Exclude() - nTop > nBottom" );
1024 ImplRegionBand
* pBand
= mpFirstBand
;
1028 if(pBand
->mnYTop
>= nTop
)
1030 if(pBand
->mnYBottom
<= nBottom
)
1032 pBand
->XOr(nLeft
, nRight
);
1037 tools::Long nCurY
= pBand
->mnYBottom
;
1038 pBand
= pBand
->mpNextBand
;
1042 if((pBand
->mnYTop
< nCurY
) || (pBand
->mnYBottom
< nCurY
))
1044 OSL_ENSURE(false, "RegionBand::XOr() - Bands not sorted!" );
1047 pBand
= pBand
->mpNextBand
;
1054 pBand
= pBand
->mpNextBand
;
1059 void RegionBand::Intersect(const RegionBand
& rSource
)
1061 // mark all bands as untouched
1062 ImplRegionBand
* pBand
= mpFirstBand
;
1066 pBand
->mbTouched
= false;
1067 pBand
= pBand
->mpNextBand
;
1070 pBand
= rSource
.mpFirstBand
;
1074 // insert bands if the boundaries are not already in the list
1075 InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1077 // process all elements of the list
1078 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1083 if ( pSep
== pBand
->mpFirstSep
)
1085 // process intersection and do not remove untouched bands
1086 Exclude( LONG_MIN
+1, pBand
->mnYTop
, pSep
->mnXLeft
-1, pBand
->mnYBottom
);
1090 if ( pSep
->mpNextSep
== nullptr )
1092 // process intersection and do not remove untouched bands
1093 Exclude( pSep
->mnXRight
+1, pBand
->mnYTop
, LONG_MAX
-1, pBand
->mnYBottom
);
1097 // process intersection and do not remove untouched bands
1098 Exclude( pSep
->mnXRight
+1, pBand
->mnYTop
, pSep
->mpNextSep
->mnXLeft
-1, pBand
->mnYBottom
);
1101 pSep
= pSep
->mpNextSep
;
1104 pBand
= pBand
->mpNextBand
;
1107 // remove all untouched bands if bands already left
1108 ImplRegionBand
* pPrevBand
= nullptr;
1109 pBand
= mpFirstBand
;
1113 if ( !pBand
->mbTouched
)
1116 ImplRegionBand
* pOldBand
= pBand
;
1118 // previous element of the list
1119 if ( pBand
== mpFirstBand
)
1121 mpFirstBand
= pBand
->mpNextBand
;
1125 pPrevBand
->mpNextBand
= pBand
->mpNextBand
;
1128 pBand
= pBand
->mpNextBand
;
1134 pBand
= pBand
->mpNextBand
;
1140 bool RegionBand::Exclude(const RegionBand
& rSource
)
1142 // apply all rectangles to the region passed to this region
1143 ImplRegionBand
* pBand
= rSource
.mpFirstBand
;
1147 // insert bands if the boundaries are not already in the list
1148 InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1150 // process all elements of the list
1151 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1155 Exclude( pSep
->mnXLeft
, pBand
->mnYTop
, pSep
->mnXRight
, pBand
->mnYBottom
);
1156 pSep
= pSep
->mpNextSep
;
1159 // to test less bands, already check in the loop
1160 if ( !OptimizeBandList() )
1165 pBand
= pBand
->mpNextBand
;
1171 bool RegionBand::CheckConsistency() const
1175 // look in the band list (don't test first band again!)
1176 const ImplRegionBand
* pBand
= mpFirstBand
->mpNextBand
;
1179 if (!pBand
->mpFirstSep
)
1181 pBand
= pBand
->mpNextBand
;
1186 tools::Rectangle
RegionBand::GetBoundRect() const
1189 // get the boundaries of the first band
1190 tools::Long
nYTop(mpFirstBand
->mnYTop
);
1191 tools::Long
nYBottom(mpFirstBand
->mnYBottom
);
1192 tools::Long
nXLeft(mpFirstBand
->GetXLeftBoundary());
1193 tools::Long
nXRight(mpFirstBand
->GetXRightBoundary());
1195 // look in the band list (don't test first band again!)
1196 ImplRegionBand
* pBand
= mpFirstBand
->mpNextBand
;
1200 nYBottom
= pBand
->mnYBottom
;
1201 nXLeft
= std::min( nXLeft
, pBand
->GetXLeftBoundary() );
1202 nXRight
= std::max( nXRight
, pBand
->GetXRightBoundary() );
1204 pBand
= pBand
->mpNextBand
;
1207 return tools::Rectangle( nXLeft
, nYTop
, nXRight
, nYBottom
);
1210 void RegionBand::XOr(const RegionBand
& rSource
)
1212 ImplRegionBand
* pBand
= rSource
.mpFirstBand
;
1216 // insert bands if the boundaries are not already in the list
1217 InsertBands( pBand
->mnYTop
, pBand
->mnYBottom
);
1219 // process all elements of the list
1220 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1224 XOr( pSep
->mnXLeft
, pBand
->mnYTop
, pSep
->mnXRight
, pBand
->mnYBottom
);
1225 pSep
= pSep
->mpNextSep
;
1228 pBand
= pBand
->mpNextBand
;
1232 bool RegionBand::IsInside(const Point
& rPoint
) const
1236 ImplRegionBand
* pBand
= mpFirstBand
;
1240 // is point within band?
1241 if((pBand
->mnYTop
<= rPoint
.Y()) && (pBand
->mnYBottom
>= rPoint
.Y()))
1243 // is point within separation of the band?
1244 return pBand
->IsInside(rPoint
.X());
1247 pBand
= pBand
->mpNextBand
;
1253 void RegionBand::GetRegionRectangles(RectangleVector
& rTarget
) const
1255 // clear result vector
1257 ImplRegionBand
* pCurrRectBand
= mpFirstBand
;
1258 tools::Rectangle aRectangle
;
1260 while(pCurrRectBand
)
1262 ImplRegionBandSep
* pCurrRectBandSep
= pCurrRectBand
->mpFirstSep
;
1264 aRectangle
.SetTop( pCurrRectBand
->mnYTop
);
1265 aRectangle
.SetBottom( pCurrRectBand
->mnYBottom
);
1267 while(pCurrRectBandSep
)
1269 aRectangle
.SetLeft( pCurrRectBandSep
->mnXLeft
);
1270 aRectangle
.SetRight( pCurrRectBandSep
->mnXRight
);
1271 rTarget
.push_back(aRectangle
);
1272 pCurrRectBandSep
= pCurrRectBandSep
->mpNextSep
;
1275 pCurrRectBand
= pCurrRectBand
->mpNextBand
;
1279 sal_uInt32
RegionBand::getRectangleCount() const
1281 sal_uInt32 nCount
= 0;
1282 const ImplRegionBand
* pBand
= mpFirstBand
;
1286 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1291 pSep
= pSep
->mpNextSep
;
1294 pBand
= pBand
->mpNextBand
;
1301 const char* ImplDbgTestRegionBand(const void* pObj
)
1303 const RegionBand
* pRegionBand
= static_cast< const RegionBand
* >(pObj
);
1307 const ImplRegionBand
* pBand
= pRegionBand
->ImplGetFirstRegionBand();
1311 if(pBand
->mnYBottom
< pBand
->mnYTop
)
1313 return "YBottom < YTop";
1316 if(pBand
->mpNextBand
)
1318 if(pBand
->mnYBottom
>= pBand
->mpNextBand
->mnYTop
)
1320 return "overlapping bands in region";
1324 if(pBand
->mbTouched
)
1326 return "Band-mbTouched overwrite";
1329 ImplRegionBandSep
* pSep
= pBand
->mpFirstSep
;
1333 if(pSep
->mnXRight
< pSep
->mnXLeft
)
1335 return "XLeft < XRight";
1340 if(pSep
->mnXRight
>= pSep
->mpNextSep
->mnXLeft
)
1342 return "overlapping separations in region";
1346 if ( pSep
->mbRemoved
)
1348 return "Sep-mbRemoved overwrite";
1351 pSep
= pSep
->mpNextSep
;
1354 pBand
= pBand
->mpNextBand
;
1362 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */