bump product version to 7.2.5.1
[LibreOffice.git] / vcl / source / gdi / regionband.cxx
blob31d942735d0b6fbbf45fe450133698608da11ec8
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 <sal/config.h>
22 #include <cstdlib>
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)
39 *this = rRef;
42 RegionBand& RegionBand::operator=(const RegionBand& rRef)
44 if (this != &rRef)
46 ImplRegionBand* pPrevBand = nullptr;
47 ImplRegionBand* pBand = rRef.mpFirstBand;
49 while(pBand)
51 ImplRegionBand* pNewBand = new ImplRegionBand(*pBand);
53 // first element? -> set as first into the list
54 if(pBand == rRef.mpFirstBand)
56 mpFirstBand = pNewBand;
58 else
60 pPrevBand->mpNextBand = pNewBand;
63 pPrevBand = pNewBand;
64 pBand = pBand->mpNextBand;
67 return *this;
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;
91 while(pBand)
93 ImplRegionBand* pTempBand = pBand->mpNextBand;
94 delete pBand;
95 pBand = pTempBand;
98 mpLastCheckedBand = nullptr;
99 mpFirstBand = nullptr;
102 RegionBand::~RegionBand()
104 implReset();
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 )
124 return false;
127 tools::Long nOwnYTop = pOwnRectBand->mnYTop;
128 tools::Long nSecondYTop = pSecondRectBand->mnYTop;
130 if ( nOwnYTop != nSecondYTop )
132 return false;
135 tools::Long nOwnXRight = pOwnRectBandSep->mnXRight;
136 tools::Long nSecondXRight = pSecondRectBandSep->mnXRight;
138 if ( nOwnXRight != nSecondXRight )
140 return false;
143 tools::Long nOwnYBottom = pOwnRectBand->mnYBottom;
144 tools::Long nSecondYBottom = pSecondRectBand->mnYBottom;
146 if ( nOwnYBottom != nSecondYBottom )
148 return false;
151 // get next separation from current band
152 pOwnRectBandSep = pOwnRectBandSep->mpNextSep;
154 // no separation found? -> go to next band!
155 if ( !pOwnRectBandSep )
157 // get next band
158 pOwnRectBand = pOwnRectBand->mpNextBand;
160 // get first separation in current band
161 if( pOwnRectBand )
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 )
173 // get next band
174 pSecondRectBand = pSecondRectBand->mpNextBand;
176 // get first separation in current band
177 if( pSecondRectBand )
179 pSecondRectBandSep = pSecondRectBand->mpFirstSep;
183 if ( pOwnRectBandSep && !pSecondRectBandSep )
185 return false;
188 if ( !pOwnRectBandSep && pSecondRectBandSep )
190 return false;
194 return true;
197 namespace {
199 enum StreamEntryType { STREAMENTRY_BANDHEADER, STREAMENTRY_SEPARATION, STREAMENTRY_END };
203 bool RegionBand::load(SvStream& rIStrm)
205 // clear this instance data
206 implReset();
208 // get all bands
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))
216 return false;
218 size_t nRecordsPossible = rIStrm.remainingSize() / (2*sizeof(sal_Int32));
219 if (!nRecordsPossible)
221 OSL_ENSURE(false, "premature end of region stream" );
222 implReset();
223 return false;
228 // insert new band or new separation?
229 if(STREAMENTRY_BANDHEADER == static_cast<StreamEntryType>(nTmp16))
231 sal_Int32 nYTop(0);
232 sal_Int32 nYBottom(0);
234 rIStrm.ReadInt32( nYTop );
235 rIStrm.ReadInt32( nYBottom );
237 // create band
238 ImplRegionBand* pNewBand = new ImplRegionBand( nYTop, nYBottom );
240 // first element? -> set as first into the list
241 if ( !pCurrBand )
243 mpFirstBand = pNewBand;
245 else
247 pCurrBand->mpNextBand = pNewBand;
250 // save pointer for next creation
251 pCurrBand = pNewBand;
253 else
255 sal_Int32 nXLeft(0);
256 sal_Int32 nXRight(0);
258 rIStrm.ReadInt32( nXLeft );
259 rIStrm.ReadInt32( nXRight );
261 // add separation
262 if ( pCurrBand )
264 pCurrBand->Union( nXLeft, nXRight );
268 if( rIStrm.eof() )
270 OSL_ENSURE(false, "premature end of region stream" );
271 implReset();
272 return false;
275 // get next header
276 rIStrm.ReadUInt16( nTmp16 );
278 while (STREAMENTRY_END != static_cast<StreamEntryType>(nTmp16) && rIStrm.good());
279 if (!CheckConsistency())
281 implReset();
282 return false;
284 return true;
287 void RegionBand::save(SvStream& rOStrm) const
289 ImplRegionBand* pBand = mpFirstBand;
291 while(pBand)
293 // put boundaries
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;
301 while(pSep)
303 // put separation
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;
315 // put endmarker
316 rOStrm.WriteUInt16( STREAMENTRY_END );
319 bool RegionBand::isSingleRectangle() const
321 // just one band?
322 if(mpFirstBand && !mpFirstBand->mpNextBand)
324 // just one sep?
325 if(mpFirstBand->mpFirstSep && !mpFirstBand->mpFirstSep->mpNextSep)
327 return true;
331 return false;
334 void RegionBand::InsertBand(ImplRegionBand* pPreviousBand, ImplRegionBand* pBandToInsert)
336 OSL_ASSERT(pBandToInsert!=nullptr);
338 if(!pPreviousBand)
340 // Insert band before all others.
341 if(mpFirstBand)
343 mpFirstBand->mpPrevBand = pBandToInsert;
346 pBandToInsert->mpNextBand = mpFirstBand;
347 mpFirstBand = pBandToInsert;
349 else
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;
363 while(pRegionBand)
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(
390 nCurrentTop,
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.
411 InsertBand(
412 pPreviousBand,
413 new ImplRegionBand(
414 nCurrentTop,
415 nBottom));
420 void RegionBand::CreateBandRange(tools::Long nYTop, tools::Long nYBottom)
422 // add top band
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++ )
431 // create new band
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)
447 tools::Long nX, nY;
449 // lines consisting of a single point do not interest here
450 if ( rStartPt == rEndPt )
452 return;
455 LineType eLineType = (rStartPt.Y() > rEndPt.Y()) ? LineType::Descending : LineType::Ascending;
456 if ( rStartPt.X() == rEndPt.X() )
458 // vertical line
459 const tools::Long nEndY = rEndPt.Y();
461 nX = rStartPt.X();
462 nY = rStartPt.Y();
464 if( nEndY > nY )
466 for ( ; nY <= nEndY; nY++ )
468 Point aNewPoint( nX, nY );
469 InsertPoint( aNewPoint, nLineId,
470 (aNewPoint == rEndPt) || (aNewPoint == rStartPt),
471 eLineType );
474 else
476 for ( ; nY >= nEndY; nY-- )
478 Point aNewPoint( nX, nY );
479 InsertPoint( aNewPoint, nLineId,
480 (aNewPoint == rEndPt) || (aNewPoint == rStartPt),
481 eLineType );
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;
496 if ( nDX >= nDY )
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 );
506 if ( nD < 0 )
507 nD += nDY2;
508 else
510 nD += nDYX;
511 nY += nYInc;
515 else
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 );
525 if ( nD < 0 )
526 nD += nDY2;
527 else
529 nD += nDYX;
530 nX += nXInc;
535 // last point
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 );
547 return;
550 if ( rPoint.Y() > mpLastCheckedBand->mnYTop )
552 // Search ascending
553 while ( mpLastCheckedBand )
555 // Insert point if possible
556 if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
558 mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
559 return;
562 mpLastCheckedBand = mpLastCheckedBand->mpNextBand;
565 OSL_ENSURE(false, "RegionBand::InsertPoint reached the end of the list!" );
567 else
569 // Search descending
570 while ( mpLastCheckedBand )
572 // Insert point if possible
573 if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
575 mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
576 return;
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;
596 while ( pBand )
598 const bool bBTEqual = pBand->mpNextBand && (pBand->mnYBottom == pBand->mpNextBand->mnYTop);
600 // no separation? -> remove!
601 if ( pBand->IsEmpty() || (bBTEqual && (pBand->mnYBottom == pBand->mnYTop)) )
603 // save pointer
604 ImplRegionBand* pOldBand = pBand;
606 // previous element of the list
607 if ( pBand == mpFirstBand )
608 mpFirstBand = pBand->mpNextBand;
609 else
610 pPrevBand->mpNextBand = pBand->mpNextBand;
612 pBand = pBand->mpNextBand;
613 delete pOldBand;
615 else
617 // fixup
618 if ( bBTEqual )
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;
632 delete pDeletedBand;
634 // check band again!
636 else
638 // count rectangles within band
639 ImplRegionBandSep* pSep = pBand->mpFirstSep;
640 while ( pSep )
642 pSep = pSep->mpNextSep;
645 pPrevBand = pBand;
646 pBand = pBand->mpNextBand;
651 #ifdef DBG_UTIL
652 pBand = mpFirstBand;
653 while ( pBand )
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;
665 #endif
667 return (nullptr != mpFirstBand);
670 void RegionBand::Move(tools::Long nHorzMove, tools::Long nVertMove)
672 ImplRegionBand* pBand = mpFirstBand;
674 while(pBand)
676 // process the vertical move
677 if(nVertMove)
679 pBand->mnYTop = pBand->mnYTop + nVertMove;
680 pBand->mnYBottom = pBand->mnYBottom + nVertMove;
683 // process the horizontal move
684 if(nHorzMove)
686 pBand->MoveX(nHorzMove);
689 pBand = pBand->mpNextBand;
694 void RegionBand::Scale(double fScaleX, double fScaleY)
696 ImplRegionBand* pBand = mpFirstBand;
698 while(pBand)
700 // process the vertical move
701 if(0.0 != fScaleY)
703 pBand->mnYTop = basegfx::fround(pBand->mnYTop * fScaleY);
704 pBand->mnYBottom = basegfx::fround(pBand->mnYBottom * fScaleY);
707 // process the horizontal move
708 if(0.0 != fScaleX)
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!
721 if ( !mpFirstBand )
723 // add band with boundaries of the rectangle
724 mpFirstBand = new ImplRegionBand( nTop, nBottom );
725 return;
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;
756 while ( pBand )
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 )
777 break;
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) )
804 return true;
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;
821 return true;
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;
847 return true;
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;
864 return true;
867 if ( nYBandPosition > pBand->mnYBottom )
869 // create new band
870 pNewBand = new ImplRegionBand( pBand->mnYBottom + 1, nYBandPosition );
872 // append band to the list
873 pBand->mpNextBand = pNewBand;
874 return true;
878 return false;
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" );
886 // process union
887 ImplRegionBand* pBand = mpFirstBand;
888 while ( pBand )
890 if ( pBand->mnYTop >= nTop )
892 if ( pBand->mnYBottom <= nBottom )
893 pBand->Union( nLeft, nRight );
894 else
896 #ifdef DBG_UTIL
897 tools::Long nCurY = pBand->mnYBottom;
898 pBand = pBand->mpNextBand;
899 while ( pBand )
901 if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) )
903 OSL_ENSURE(false, "RegionBand::Union() - Bands not sorted!" );
905 pBand = pBand->mpNextBand;
907 #endif
908 break;
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;
923 while(pBand)
925 // band within intersection boundary? -> process. otherwise remove
926 if((pBand->mnYTop >= nTop) && (pBand->mnYBottom <= nBottom))
928 // process intersection
929 pBand->Intersect(nLeft, nRight);
930 pPrevBand = pBand;
931 pBand = pBand->mpNextBand;
933 else
935 ImplRegionBand* pOldBand = pBand;
937 if(pBand == mpFirstBand)
939 mpFirstBand = pBand->mpNextBand;
941 else
943 pPrevBand->mpNextBand = pBand->mpNextBand;
946 pBand = pBand->mpNextBand;
947 delete pOldBand;
953 void RegionBand::Union(const RegionBand& rSource)
955 // apply all rectangles from rSource to this
956 ImplRegionBand* pBand = rSource.mpFirstBand;
958 while ( pBand )
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;
966 while(pSep)
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" );
982 // process exclude
983 ImplRegionBand* pBand = mpFirstBand;
985 while(pBand)
987 if(pBand->mnYTop >= nTop)
989 if(pBand->mnYBottom <= nBottom)
991 pBand->Exclude(nLeft, nRight);
993 else
995 #ifdef DBG_UTIL
996 tools::Long nCurY = pBand->mnYBottom;
997 pBand = pBand->mpNextBand;
999 while(pBand)
1001 if((pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY))
1003 OSL_ENSURE(false, "RegionBand::Exclude() - Bands not sorted!" );
1006 pBand = pBand->mpNextBand;
1008 #endif
1009 break;
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" );
1023 // process xor
1024 ImplRegionBand* pBand = mpFirstBand;
1026 while(pBand)
1028 if(pBand->mnYTop >= nTop)
1030 if(pBand->mnYBottom <= nBottom)
1032 pBand->XOr(nLeft, nRight);
1034 else
1036 #ifdef DBG_UTIL
1037 tools::Long nCurY = pBand->mnYBottom;
1038 pBand = pBand->mpNextBand;
1040 while(pBand)
1042 if((pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY))
1044 OSL_ENSURE(false, "RegionBand::XOr() - Bands not sorted!" );
1047 pBand = pBand->mpNextBand;
1049 #endif
1050 break;
1054 pBand = pBand->mpNextBand;
1059 void RegionBand::Intersect(const RegionBand& rSource)
1061 // mark all bands as untouched
1062 ImplRegionBand* pBand = mpFirstBand;
1064 while ( pBand )
1066 pBand->mbTouched = false;
1067 pBand = pBand->mpNextBand;
1070 pBand = rSource.mpFirstBand;
1072 while ( pBand )
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;
1080 while ( pSep )
1082 // left boundary?
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 );
1089 // right boundary?
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 );
1095 else
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;
1111 while ( pBand )
1113 if ( !pBand->mbTouched )
1115 // save pointer
1116 ImplRegionBand* pOldBand = pBand;
1118 // previous element of the list
1119 if ( pBand == mpFirstBand )
1121 mpFirstBand = pBand->mpNextBand;
1123 else
1125 pPrevBand->mpNextBand = pBand->mpNextBand;
1128 pBand = pBand->mpNextBand;
1129 delete pOldBand;
1131 else
1133 pPrevBand = pBand;
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;
1145 while ( pBand )
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;
1153 while ( pSep )
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() )
1162 return false;
1165 pBand = pBand->mpNextBand;
1168 return true;
1171 bool RegionBand::CheckConsistency() const
1173 if (!mpFirstBand)
1174 return true;
1175 // look in the band list (don't test first band again!)
1176 const ImplRegionBand* pBand = mpFirstBand->mpNextBand;
1177 while (pBand)
1179 if (!pBand->mpFirstSep)
1180 return false;
1181 pBand = pBand->mpNextBand;
1183 return true;
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;
1198 while ( pBand )
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;
1214 while ( pBand )
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;
1222 while ( pSep )
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
1235 // search band list
1236 ImplRegionBand* pBand = mpFirstBand;
1238 while(pBand)
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;
1250 return false;
1253 void RegionBand::GetRegionRectangles(RectangleVector& rTarget) const
1255 // clear result vector
1256 rTarget.clear();
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;
1284 while(pBand)
1286 ImplRegionBandSep* pSep = pBand->mpFirstSep;
1288 while(pSep)
1290 nCount++;
1291 pSep = pSep->mpNextSep;
1294 pBand = pBand->mpNextBand;
1297 return nCount;
1300 #ifdef DBG_UTIL
1301 const char* ImplDbgTestRegionBand(const void* pObj)
1303 const RegionBand* pRegionBand = static_cast< const RegionBand* >(pObj);
1305 if(pRegionBand)
1307 const ImplRegionBand* pBand = pRegionBand->ImplGetFirstRegionBand();
1309 while(pBand)
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;
1331 while(pSep)
1333 if(pSep->mnXRight < pSep->mnXLeft)
1335 return "XLeft < XRight";
1338 if(pSep->mpNextSep)
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;
1358 return nullptr;
1360 #endif
1362 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */