Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / source / gdi / regionband.cxx
blob2e54cd89194e0c57dcb282ee4c9c8c78e5f6319d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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)
35 *this = rRef;
38 RegionBand& RegionBand::operator=(const RegionBand& rRef)
40 ImplRegionBand* pPrevBand = nullptr;
41 ImplRegionBand* pBand = rRef.mpFirstBand;
43 while(pBand)
45 ImplRegionBand* pNewBand = new ImplRegionBand(*pBand);
47 // first element? -> set as first into the list
48 if(pBand == rRef.mpFirstBand)
50 mpFirstBand = pNewBand;
52 else
54 pPrevBand->mpNextBand = pNewBand;
57 pPrevBand = pNewBand;
58 pBand = pBand->mpNextBand;
61 return *this;
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;
85 while(pBand)
87 ImplRegionBand* pTempBand = pBand->mpNextBand;
88 delete pBand;
89 pBand = pTempBand;
92 mpLastCheckedBand = nullptr;
93 mpFirstBand = nullptr;
96 RegionBand::~RegionBand()
98 implReset();
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 )
118 return false;
121 long nOwnYTop = pOwnRectBand->mnYTop;
122 long nSecondYTop = pSecondRectBand->mnYTop;
124 if ( nOwnYTop != nSecondYTop )
126 return false;
129 long nOwnXRight = pOwnRectBandSep->mnXRight;
130 long nSecondXRight = pSecondRectBandSep->mnXRight;
132 if ( nOwnXRight != nSecondXRight )
134 return false;
137 long nOwnYBottom = pOwnRectBand->mnYBottom;
138 long nSecondYBottom = pSecondRectBand->mnYBottom;
140 if ( nOwnYBottom != nSecondYBottom )
142 return false;
145 // get next separation from current band
146 pOwnRectBandSep = pOwnRectBandSep->mpNextSep;
148 // no separation found? -> go to next band!
149 if ( !pOwnRectBandSep )
151 // get next band
152 pOwnRectBand = pOwnRectBand->mpNextBand;
154 // get first separation in current band
155 if( pOwnRectBand )
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 )
167 // get next band
168 pSecondRectBand = pSecondRectBand->mpNextBand;
170 // get first separation in current band
171 if( pSecondRectBand )
173 pSecondRectBandSep = pSecondRectBand->mpFirstSep;
177 if ( pOwnRectBandSep && !pSecondRectBandSep )
179 return false;
182 if ( !pOwnRectBandSep && pSecondRectBandSep )
184 return false;
188 return true;
191 enum StreamEntryType { STREAMENTRY_BANDHEADER, STREAMENTRY_SEPARATION, STREAMENTRY_END };
193 void RegionBand::load(SvStream& rIStrm)
195 // clear this instance data
196 implReset();
198 // get all bands
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)
206 return;
208 size_t nRecordsPossible = rIStrm.remainingSize() / (2*sizeof(sal_Int32));
209 if (!nRecordsPossible)
211 OSL_ENSURE(false, "premature end of region stream" );
212 implReset();
213 return;
218 // insert new band or new separation?
219 if(STREAMENTRY_BANDHEADER == (StreamEntryType)nTmp16)
221 sal_Int32 nYTop(0);
222 sal_Int32 nYBottom(0);
224 rIStrm.ReadInt32( nYTop );
225 rIStrm.ReadInt32( nYBottom );
227 // create band
228 ImplRegionBand* pNewBand = new ImplRegionBand( nYTop, nYBottom );
230 // first element? -> set as first into the list
231 if ( !pCurrBand )
233 mpFirstBand = pNewBand;
235 else
237 pCurrBand->mpNextBand = pNewBand;
240 // save pointer for next creation
241 pCurrBand = pNewBand;
243 else
245 sal_Int32 nXLeft(0);
246 sal_Int32 nXRight(0);
248 rIStrm.ReadInt32( nXLeft );
249 rIStrm.ReadInt32( nXRight );
251 // add separation
252 if ( pCurrBand )
254 pCurrBand->Union( nXLeft, nXRight );
258 if( rIStrm.IsEof() )
260 OSL_ENSURE(false, "premature end of region stream" );
261 implReset();
262 return;
265 // get next header
266 rIStrm.ReadUInt16( nTmp16 );
268 while (STREAMENTRY_END != (StreamEntryType)nTmp16 && rIStrm.good());
271 void RegionBand::save(SvStream& rOStrm) const
273 ImplRegionBand* pBand = mpFirstBand;
275 while(pBand)
277 // put boundaries
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;
285 while(pSep)
287 // put separation
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;
299 // put endmarker
300 rOStrm.WriteUInt16( STREAMENTRY_END );
303 bool RegionBand::isSingleRectangle() const
305 // just one band?
306 if(mpFirstBand && !mpFirstBand->mpNextBand)
308 // just one sep?
309 if(mpFirstBand->mpFirstSep && !mpFirstBand->mpFirstSep->mpNextSep)
311 return true;
315 return false;
318 void RegionBand::InsertBand(ImplRegionBand* pPreviousBand, ImplRegionBand* pBandToInsert)
320 OSL_ASSERT(pBandToInsert!=nullptr);
322 if(!pPreviousBand)
324 // Insert band before all others.
325 if(mpFirstBand)
327 mpFirstBand->mpPrevBand = pBandToInsert;
330 pBandToInsert->mpNextBand = mpFirstBand;
331 mpFirstBand = pBandToInsert;
333 else
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;
347 while(pRegionBand)
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(
374 nCurrentTop,
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.
395 InsertBand(
396 pPreviousBand,
397 new ImplRegionBand(
398 nCurrentTop,
399 nBottom));
404 void RegionBand::CreateBandRange(long nYTop, long nYBottom)
406 // add top band
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++ )
415 // create new band
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)
431 long nX, nY;
433 // lines consisting of a single point do not interest here
434 if ( rStartPt == rEndPt )
436 return;
439 LineType eLineType = (rStartPt.Y() > rEndPt.Y()) ? LINE_DESCENDING : LINE_ASCENDING;
440 if ( rStartPt.X() == rEndPt.X() )
442 // vertical line
443 const long nEndY = rEndPt.Y();
445 nX = rStartPt.X();
446 nY = rStartPt.Y();
448 if( nEndY > nY )
450 for ( ; nY <= nEndY; nY++ )
452 Point aNewPoint( nX, nY );
453 InsertPoint( aNewPoint, nLineId,
454 (aNewPoint == rEndPt) || (aNewPoint == rStartPt),
455 eLineType );
458 else
460 for ( ; nY >= nEndY; nY-- )
462 Point aNewPoint( nX, nY );
463 InsertPoint( aNewPoint, nLineId,
464 (aNewPoint == rEndPt) || (aNewPoint == rStartPt),
465 eLineType );
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;
480 if ( nDX >= nDY )
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 );
490 if ( nD < 0 )
491 nD += nDY2;
492 else
494 nD += nDYX;
495 nY += nYInc;
499 else
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 );
509 if ( nD < 0 )
510 nD += nDY2;
511 else
513 nD += nDYX;
514 nX += nXInc;
519 // last point
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 );
531 return;
534 if ( rPoint.Y() > mpLastCheckedBand->mnYTop )
536 // Search ascending
537 while ( mpLastCheckedBand )
539 // Insert point if possible
540 if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
542 mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
543 return;
546 mpLastCheckedBand = mpLastCheckedBand->mpNextBand;
549 OSL_ENSURE(false, "RegionBand::InsertPoint reached the end of the list!" );
551 else
553 // Search descending
554 while ( mpLastCheckedBand )
556 // Insert point if possible
557 if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
559 mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
560 return;
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;
580 while ( pBand )
582 const bool bBTEqual = pBand->mpNextBand && (pBand->mnYBottom == pBand->mpNextBand->mnYTop);
584 // no separation? -> remove!
585 if ( pBand->IsEmpty() || (bBTEqual && (pBand->mnYBottom == pBand->mnYTop)) )
587 // save pointer
588 ImplRegionBand* pOldBand = pBand;
590 // previous element of the list
591 if ( pBand == mpFirstBand )
592 mpFirstBand = pBand->mpNextBand;
593 else
594 pPrevBand->mpNextBand = pBand->mpNextBand;
596 pBand = pBand->mpNextBand;
597 delete pOldBand;
599 else
601 // fixup
602 if ( bBTEqual )
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;
616 delete pDeletedBand;
618 // check band again!
620 else
622 // count rectangles within band
623 ImplRegionBandSep* pSep = pBand->mpFirstSep;
624 while ( pSep )
626 pSep = pSep->mpNextSep;
629 pPrevBand = pBand;
630 pBand = pBand->mpNextBand;
635 #ifdef DBG_UTIL
636 pBand = mpFirstBand;
637 while ( pBand )
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;
652 #endif
654 return (nullptr != mpFirstBand);
657 void RegionBand::Move(long nHorzMove, long nVertMove)
659 ImplRegionBand* pBand = mpFirstBand;
661 while(pBand)
663 // process the vertical move
664 if(nVertMove)
666 pBand->mnYTop = pBand->mnYTop + nVertMove;
667 pBand->mnYBottom = pBand->mnYBottom + nVertMove;
670 // process the horizontal move
671 if(nHorzMove)
673 pBand->MoveX(nHorzMove);
676 pBand = pBand->mpNextBand;
681 void RegionBand::Scale(double fScaleX, double fScaleY)
683 ImplRegionBand* pBand = mpFirstBand;
685 while(pBand)
687 // process the vertical move
688 if(0.0 != fScaleY)
690 pBand->mnYTop = basegfx::fround(pBand->mnYTop * fScaleY);
691 pBand->mnYBottom = basegfx::fround(pBand->mnYBottom * fScaleY);
694 // process the horizontal move
695 if(0.0 != fScaleX)
697 pBand->ScaleX(fScaleX);
700 pBand = pBand->mpNextBand;
705 void RegionBand::InsertBands(long nTop, long nBottom)
707 // region empty? -> set rectangle as first entry!
708 if ( !mpFirstBand )
710 // add band with boundaries of the rectangle
711 mpFirstBand = new ImplRegionBand( nTop, nBottom );
712 return;
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;
743 while ( pBand )
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 )
764 break;
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) )
791 return true;
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;
808 return true;
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;
834 return true;
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;
851 return true;
854 if ( nYBandPosition > pBand->mnYBottom )
856 // create new band
857 pNewBand = new ImplRegionBand( pBand->mnYBottom + 1, nYBandPosition );
859 // append band to the list
860 pBand->mpNextBand = pNewBand;
861 return true;
865 return false;
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" );
873 // process union
874 ImplRegionBand* pBand = mpFirstBand;
875 while ( pBand )
877 if ( pBand->mnYTop >= nTop )
879 if ( pBand->mnYBottom <= nBottom )
880 pBand->Union( nLeft, nRight );
881 else
883 #ifdef DBG_UTIL
884 long nCurY = pBand->mnYBottom;
885 pBand = pBand->mpNextBand;
886 while ( pBand )
888 if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) )
890 OSL_ENSURE(false, "RegionBand::Union() - Bands not sorted!" );
892 pBand = pBand->mpNextBand;
894 #endif
895 break;
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;
910 while(pBand)
912 // band within intersection boundary? -> process. otherwise remove
913 if((pBand->mnYTop >= nTop) && (pBand->mnYBottom <= nBottom))
915 // process intersection
916 pBand->Intersect(nLeft, nRight);
917 pPrevBand = pBand;
918 pBand = pBand->mpNextBand;
920 else
922 ImplRegionBand* pOldBand = pBand;
924 if(pBand == mpFirstBand)
926 mpFirstBand = pBand->mpNextBand;
928 else
930 pPrevBand->mpNextBand = pBand->mpNextBand;
933 pBand = pBand->mpNextBand;
934 delete pOldBand;
940 void RegionBand::Union(const RegionBand& rSource)
942 // apply all rectangles from rSource to this
943 ImplRegionBand* pBand = rSource.mpFirstBand;
945 while ( pBand )
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;
953 while(pSep)
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" );
969 // process exclude
970 ImplRegionBand* pBand = mpFirstBand;
972 while(pBand)
974 if(pBand->mnYTop >= nTop)
976 if(pBand->mnYBottom <= nBottom)
978 pBand->Exclude(nLeft, nRight);
980 else
982 #ifdef DBG_UTIL
983 long nCurY = pBand->mnYBottom;
984 pBand = pBand->mpNextBand;
986 while(pBand)
988 if((pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY))
990 OSL_ENSURE(false, "RegionBand::Exclude() - Bands not sorted!" );
993 pBand = pBand->mpNextBand;
995 #endif
996 break;
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" );
1010 // process xor
1011 ImplRegionBand* pBand = mpFirstBand;
1013 while(pBand)
1015 if(pBand->mnYTop >= nTop)
1017 if(pBand->mnYBottom <= nBottom)
1019 pBand->XOr(nLeft, nRight);
1021 else
1023 #ifdef DBG_UTIL
1024 long nCurY = pBand->mnYBottom;
1025 pBand = pBand->mpNextBand;
1027 while(pBand)
1029 if((pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY))
1031 OSL_ENSURE(false, "RegionBand::XOr() - Bands not sorted!" );
1034 pBand = pBand->mpNextBand;
1036 #endif
1037 break;
1041 pBand = pBand->mpNextBand;
1046 void RegionBand::Intersect(const RegionBand& rSource)
1048 // mark all bands as untouched
1049 ImplRegionBand* pBand = mpFirstBand;
1051 while ( pBand )
1053 pBand->mbTouched = false;
1054 pBand = pBand->mpNextBand;
1057 pBand = rSource.mpFirstBand;
1059 while ( pBand )
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;
1067 while ( pSep )
1069 // left boundary?
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 );
1076 // right boundary?
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 );
1082 else
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;
1098 while ( pBand )
1100 if ( !pBand->mbTouched )
1102 // save pointer
1103 ImplRegionBand* pOldBand = pBand;
1105 // previous element of the list
1106 if ( pBand == mpFirstBand )
1108 mpFirstBand = pBand->mpNextBand;
1110 else
1112 pPrevBand->mpNextBand = pBand->mpNextBand;
1115 pBand = pBand->mpNextBand;
1116 delete pOldBand;
1118 else
1120 pPrevBand = pBand;
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;
1132 while ( pBand )
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;
1140 while ( pSep )
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() )
1149 return false;
1152 pBand = pBand->mpNextBand;
1155 return true;
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;
1170 while ( pBand )
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;
1186 while ( pBand )
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;
1194 while ( pSep )
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
1207 // search band list
1208 ImplRegionBand* pBand = mpFirstBand;
1210 while(pBand)
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;
1222 return false;
1225 void RegionBand::GetRegionRectangles(RectangleVector& rTarget) const
1227 // clear result vector
1228 rTarget.clear();
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;
1256 while(pBand)
1258 ImplRegionBandSep* pSep = pBand->mpFirstSep;
1260 while(pSep)
1262 nCount++;
1263 pSep = pSep->mpNextSep;
1266 pBand = pBand->mpNextBand;
1269 return nCount;
1272 #ifdef DBG_UTIL
1273 const char* ImplDbgTestRegionBand(const void* pObj)
1275 const RegionBand* pRegionBand = static_cast< const RegionBand* >(pObj);
1277 if(pRegionBand)
1279 const ImplRegionBand* pBand = pRegionBand->ImplGetFirstRegionBand();
1281 while(pBand)
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;
1303 while(pSep)
1305 if(pSep->mnXRight < pSep->mnXLeft)
1307 return "XLeft < XRight";
1310 if(pSep->mpNextSep)
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;
1330 return nullptr;
1332 #endif
1334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */