update dev300-m58
[ooovba.git] / vcl / source / gdi / regband.cxx
blobf11ae41deec0963e56422b3f4083568c332ec9c8
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: regband.cxx,v $
10 * $Revision: 1.9.158.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
33 #include <tools/debug.hxx>
34 #include <vcl/salbtype.hxx>
35 #include <vcl/regband.hxx>
37 #include <algorithm>
40 // =======================================================================
42 // ImplRegionBand
44 // Jedes Band enthaelt die zwischen der enthaltenen Ober- und Untergrenze
45 // enthaltenen Rechtecke. Bei den Operationen Union, Intersect, XOr und
46 // Exclude werden immer Rechtecke der gleichen Hoehe ausgewerte; die
47 // Grenzen der Baender sind immer so zu waehlen, dasz dies moeglich ist.
49 // Die Rechtecke in den Baendern werden nach Moeglichkeit zusammengefaszt.
51 // Bei der Umwandlung von Polygonen werden alle Punkte des Polygons
52 // in die einzelnen Baender eingetragen (sie stehen fuer jedes Band als
53 // Punkte in einer Liste). Nach dem Eintragen der Punkte werden diese
54 // in Rechtecke umgewandelt und die Liste der Punkte geloescht.
56 // -----------------------------------------------------------------------
58 ImplRegionBand::ImplRegionBand( long nTop, long nBottom )
60 // save boundaries
61 mnYTop = nTop;
62 mnYBottom = nBottom;
64 // initialize lists
65 mpNextBand = NULL;
66 mpPrevBand = NULL;
67 mpFirstSep = NULL;
68 mpFirstBandPoint = NULL;
69 mbTouched = FALSE;
72 // -----------------------------------------------------------------------
74 ImplRegionBand::ImplRegionBand(
75 const ImplRegionBand& rRegionBand,
76 const bool bIgnorePoints)
78 // copy boundaries
79 mnYTop = rRegionBand.mnYTop;
80 mnYBottom = rRegionBand.mnYBottom;
81 mbTouched = rRegionBand.mbTouched;
83 // initialisation
84 mpNextBand = NULL;
85 mpPrevBand = NULL;
86 mpFirstSep = NULL;
87 mpFirstBandPoint = NULL;
89 // copy all elements of the list with separations
90 ImplRegionBandSep* pNewSep;
91 ImplRegionBandSep* pPrevSep = 0;
92 ImplRegionBandSep* pSep = rRegionBand.mpFirstSep;
93 while ( pSep )
95 // create new and copy data
96 pNewSep = new ImplRegionBandSep;
97 pNewSep->mnXLeft = pSep->mnXLeft;
98 pNewSep->mnXRight = pSep->mnXRight;
99 pNewSep->mbRemoved = pSep->mbRemoved;
100 pNewSep->mpNextSep = NULL;
101 if ( pSep == rRegionBand.mpFirstSep )
102 mpFirstSep = pNewSep;
103 else
104 pPrevSep->mpNextSep = pNewSep;
106 pPrevSep = pNewSep;
107 pSep = pSep->mpNextSep;
110 if ( ! bIgnorePoints)
112 // Copy points.
113 ImplRegionBandPoint* pPoint = mpFirstBandPoint;
114 ImplRegionBandPoint* pPrevPointCopy = NULL;
115 while (pPoint != NULL)
117 ImplRegionBandPoint* pPointCopy = new ImplRegionBandPoint();
118 pPointCopy->mnX = pPoint->mnX;
119 pPointCopy->mnLineId = pPoint->mnLineId;
120 pPointCopy->mbEndPoint = pPoint->mbEndPoint;
121 pPointCopy->meLineType = pPoint->meLineType;
123 if (pPrevPointCopy != NULL)
124 pPrevPointCopy->mpNextBandPoint = pPointCopy;
125 else
126 mpFirstBandPoint = pPointCopy;
128 pPrevPointCopy = pPointCopy;
129 pPoint = pPoint->mpNextBandPoint;
134 // -----------------------------------------------------------------------
136 ImplRegionBand::~ImplRegionBand()
138 DBG_ASSERT( mpFirstBandPoint == NULL, "ImplRegionBand::~ImplRegionBand -> pointlist not empty" );
140 // delete elements of the list
141 ImplRegionBandSep* pSep = mpFirstSep;
142 while ( pSep )
144 ImplRegionBandSep* pTempSep = pSep->mpNextSep;
145 delete pSep;
146 pSep = pTempSep;
149 // delete elements of the list
150 ImplRegionBandPoint* pPoint = mpFirstBandPoint;
151 while ( pPoint )
153 ImplRegionBandPoint* pTempPoint = pPoint->mpNextBandPoint;
154 delete pPoint;
155 pPoint = pTempPoint;
159 // -----------------------------------------------------------------------
161 // generate separations from lines and process union with existing
162 // separations
164 void ImplRegionBand::ProcessPoints()
166 // check Pointlist
167 ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint;
168 while ( pRegionBandPoint )
170 // within list?
171 if ( pRegionBandPoint && pRegionBandPoint->mpNextBandPoint )
173 // start/stop?
174 if ( pRegionBandPoint->mbEndPoint && pRegionBandPoint->mpNextBandPoint->mbEndPoint )
176 // same direction? -> remove next point!
177 if ( pRegionBandPoint->meLineType == pRegionBandPoint->mpNextBandPoint->meLineType )
179 ImplRegionBandPoint* pSaveRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
180 pRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint;
181 delete pSaveRegionBandPoint;
186 // continue with next element in the list
187 pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
190 pRegionBandPoint = mpFirstBandPoint;
191 while ( pRegionBandPoint && pRegionBandPoint->mpNextBandPoint )
193 Union( pRegionBandPoint->mnX, pRegionBandPoint->mpNextBandPoint->mnX );
195 ImplRegionBandPoint* pNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint;
197 // remove allready processed points
198 delete pRegionBandPoint->mpNextBandPoint;
199 delete pRegionBandPoint;
201 // continue with next element in the list
202 pRegionBandPoint = pNextBandPoint;
205 // remove last element if necessary
206 if ( pRegionBandPoint )
207 delete pRegionBandPoint;
209 // list is now empty
210 mpFirstBandPoint = NULL;
213 // -----------------------------------------------------------------------
215 // generate separations from lines and process union with existing
216 // separations
218 BOOL ImplRegionBand::InsertPoint( long nX, long nLineId,
219 BOOL bEndPoint, LineType eLineType )
221 if ( !mpFirstBandPoint )
223 mpFirstBandPoint = new ImplRegionBandPoint;
224 mpFirstBandPoint->mnX = nX;
225 mpFirstBandPoint->mnLineId = nLineId;
226 mpFirstBandPoint->mbEndPoint = bEndPoint;
227 mpFirstBandPoint->meLineType = eLineType;
228 mpFirstBandPoint->mpNextBandPoint = NULL;
229 return TRUE;
232 // look if line allready touched the band
233 ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint;
234 ImplRegionBandPoint* pLastTestedRegionBandPoint = NULL;
235 while( pRegionBandPoint )
237 if ( pRegionBandPoint->mnLineId == nLineId )
239 if ( bEndPoint )
241 if( !pRegionBandPoint->mbEndPoint )
243 // remove old band point
244 if( !mpFirstBandPoint->mpNextBandPoint )
246 // if we've only got one point => replace first point
247 pRegionBandPoint->mnX = nX;
248 pRegionBandPoint->mbEndPoint = TRUE;
249 return TRUE;
251 else
253 // remove current point
254 if( !pLastTestedRegionBandPoint )
256 // remove and delete old first point
257 ImplRegionBandPoint* pSaveBandPoint = mpFirstBandPoint;
258 mpFirstBandPoint = mpFirstBandPoint->mpNextBandPoint;
259 delete pSaveBandPoint;
261 else
263 // remove and delete current band point
264 pLastTestedRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint;
265 delete pRegionBandPoint;
268 break;
272 else
273 return FALSE;
276 // use next element
277 pLastTestedRegionBandPoint = pRegionBandPoint;
278 pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
281 // search appropriate position and insert point into the list
282 ImplRegionBandPoint* pNewRegionBandPoint;
284 pRegionBandPoint = mpFirstBandPoint;
285 pLastTestedRegionBandPoint = NULL;
286 while ( pRegionBandPoint )
288 // new point completly left? -> insert as first point
289 if ( nX <= pRegionBandPoint->mnX )
291 pNewRegionBandPoint = new ImplRegionBandPoint;
292 pNewRegionBandPoint->mnX = nX;
293 pNewRegionBandPoint->mnLineId = nLineId;
294 pNewRegionBandPoint->mbEndPoint = bEndPoint;
295 pNewRegionBandPoint->meLineType = eLineType;
296 pNewRegionBandPoint->mpNextBandPoint = pRegionBandPoint;
298 // connections to the new point
299 if ( !pLastTestedRegionBandPoint )
300 mpFirstBandPoint = pNewRegionBandPoint;
301 else
302 pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
304 return TRUE;
307 // use next element
308 pLastTestedRegionBandPoint = pRegionBandPoint;
309 pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
312 // not inserted -> add to the end of the list
313 pNewRegionBandPoint = new ImplRegionBandPoint;
314 pNewRegionBandPoint->mnX = nX;
315 pNewRegionBandPoint->mnLineId = nLineId;
316 pNewRegionBandPoint->mbEndPoint = bEndPoint;
317 pNewRegionBandPoint->meLineType = eLineType;
318 pNewRegionBandPoint->mpNextBandPoint = NULL;
320 // connections to the new point
321 pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
323 return TRUE;
326 // -----------------------------------------------------------------------
328 void ImplRegionBand::MoveX( long nHorzMove )
330 // move all x-separations
331 ImplRegionBandSep* pSep = mpFirstSep;
332 while ( pSep )
334 pSep->mnXLeft += nHorzMove;
335 pSep->mnXRight += nHorzMove;
336 pSep = pSep->mpNextSep;
340 // -----------------------------------------------------------------------
342 void ImplRegionBand::ScaleX( double fHorzScale )
344 ImplRegionBandSep* pSep = mpFirstSep;
345 while ( pSep )
347 pSep->mnXLeft = FRound( pSep->mnXLeft * fHorzScale );
348 pSep->mnXRight = FRound( pSep->mnXRight * fHorzScale );
349 pSep = pSep->mpNextSep;
353 // -----------------------------------------------------------------------
355 // combine overlaping sparations
357 BOOL ImplRegionBand::OptimizeBand()
359 ImplRegionBandSep* pPrevSep = 0;
360 ImplRegionBandSep* pSep = mpFirstSep;
361 while ( pSep )
363 // remove?
364 if ( pSep->mbRemoved || (pSep->mnXRight < pSep->mnXLeft) )
366 ImplRegionBandSep* pOldSep = pSep;
367 if ( pSep == mpFirstSep )
368 mpFirstSep = pSep->mpNextSep;
369 else
370 pPrevSep->mpNextSep = pSep->mpNextSep;
371 pSep = pSep->mpNextSep;
372 delete pOldSep;
373 continue;
376 // overlaping separations? -> combine!
377 if ( pSep->mpNextSep )
379 if ( (pSep->mnXRight+1) >= pSep->mpNextSep->mnXLeft )
381 if ( pSep->mpNextSep->mnXRight > pSep->mnXRight )
382 pSep->mnXRight = pSep->mpNextSep->mnXRight;
384 ImplRegionBandSep* pOldSep = pSep->mpNextSep;
385 pSep->mpNextSep = pOldSep->mpNextSep;
386 delete pOldSep;
387 continue;
391 pPrevSep = pSep;
392 pSep = pSep->mpNextSep;
395 return TRUE;
398 // -----------------------------------------------------------------------
400 void ImplRegionBand::Union( long nXLeft, long nXRight )
402 DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Union(): nxLeft > nXRight" );
404 // band empty? -> add element
405 if ( !mpFirstSep )
407 mpFirstSep = new ImplRegionBandSep;
408 mpFirstSep->mnXLeft = nXLeft;
409 mpFirstSep->mnXRight = nXRight;
410 mpFirstSep->mbRemoved = FALSE;
411 mpFirstSep->mpNextSep = NULL;
412 return;
415 // process real union
416 ImplRegionBandSep* pNewSep;
417 ImplRegionBandSep* pPrevSep = 0;
418 ImplRegionBandSep* pSep = mpFirstSep;
419 while ( pSep )
421 // new separation completely inside? nothing to do!
422 if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
423 return;
425 // new separation completly left? -> new separation!
426 if ( nXRight < pSep->mnXLeft )
428 pNewSep = new ImplRegionBandSep;
429 pNewSep->mnXLeft = nXLeft;
430 pNewSep->mnXRight = nXRight;
431 pNewSep->mbRemoved = FALSE;
433 pNewSep->mpNextSep = pSep;
434 if ( pSep == mpFirstSep )
435 mpFirstSep = pNewSep;
436 else
437 pPrevSep->mpNextSep = pNewSep;
438 break;
441 // new separation overlaping from left? -> extend boundary
442 if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
443 pSep->mnXLeft = nXLeft;
445 // new separation overlaping from right? -> extend boundary
446 if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
448 pSep->mnXRight = nXRight;
449 break;
452 // not inserted, but last element? -> add to the end of the list
453 if ( !pSep->mpNextSep && (nXLeft > pSep->mnXRight) )
455 pNewSep = new ImplRegionBandSep;
456 pNewSep->mnXLeft = nXLeft;
457 pNewSep->mnXRight = nXRight;
458 pNewSep->mbRemoved = FALSE;
460 pSep->mpNextSep = pNewSep;
461 pNewSep->mpNextSep = NULL;
462 break;
465 pPrevSep = pSep;
466 pSep = pSep->mpNextSep;
469 OptimizeBand();
472 // -----------------------------------------------------------------------
474 void ImplRegionBand::Intersect( long nXLeft, long nXRight )
476 DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Intersect(): nxLeft > nXRight" );
478 // band has been touched
479 mbTouched = TRUE;
481 // band empty? -> nothing to do
482 if ( !mpFirstSep )
483 return;
485 // process real intersection
486 ImplRegionBandSep* pSep = mpFirstSep;
487 while ( pSep )
489 // new separation completly outside? -> remove separation
490 if ( (nXRight < pSep->mnXLeft) || (nXLeft > pSep->mnXRight) )
491 // will be removed from the optimizer
492 pSep->mbRemoved = TRUE;
494 // new separation overlaping from left? -> reduce right boundary
495 if ( (nXLeft <= pSep->mnXLeft) &&
496 (nXRight <= pSep->mnXRight) &&
497 (nXRight >= pSep->mnXLeft) )
498 pSep->mnXRight = nXRight;
500 // new separation overlaping from right? -> reduce right boundary
501 if ( (nXLeft >= pSep->mnXLeft) &&
502 (nXLeft <= pSep->mnXRight) &&
503 (nXRight >= pSep->mnXRight) )
504 pSep->mnXLeft = nXLeft;
506 // new separation within the actual one? -> reduce both boundaries
507 if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
509 pSep->mnXRight = nXRight;
510 pSep->mnXLeft = nXLeft;
513 pSep = pSep->mpNextSep;
516 OptimizeBand();
519 // -----------------------------------------------------------------------
521 void ImplRegionBand::Exclude( long nXLeft, long nXRight )
523 DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Exclude(): nxLeft > nXRight" );
525 // band has been touched
526 mbTouched = TRUE;
528 // band empty? -> nothing to do
529 if ( !mpFirstSep )
530 return;
532 // process real exclusion
533 ImplRegionBandSep* pNewSep;
534 ImplRegionBandSep* pPrevSep = 0;
535 ImplRegionBandSep* pSep = mpFirstSep;
536 while ( pSep )
538 BOOL bSepProcessed = FALSE;
540 // new separation completely overlapping? -> remove separation
541 if ( (nXLeft <= pSep->mnXLeft) && (nXRight >= pSep->mnXRight) )
543 // will be removed from the optimizer
544 pSep->mbRemoved = TRUE;
545 bSepProcessed = TRUE;
548 // new separation overlaping from left? -> reduce boundary
549 if ( !bSepProcessed )
551 if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
553 pSep->mnXLeft = nXRight+1;
554 bSepProcessed = TRUE;
558 // new separation overlaping from right? -> reduce boundary
559 if ( !bSepProcessed )
561 if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
563 pSep->mnXRight = nXLeft-1;
564 bSepProcessed = TRUE;
568 // new separation within the actual one? -> reduce boundary
569 // and add new entry for reminder
570 if ( !bSepProcessed )
572 if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
574 pNewSep = new ImplRegionBandSep;
575 pNewSep->mnXLeft = pSep->mnXLeft;
576 pNewSep->mnXRight = nXLeft-1;
577 pNewSep->mbRemoved = FALSE;
579 pSep->mnXLeft = nXRight+1;
581 // connections from the new separation
582 pNewSep->mpNextSep = pSep;
584 // connections to the new separation
585 if ( pSep == mpFirstSep )
586 mpFirstSep = pNewSep;
587 else
588 pPrevSep->mpNextSep = pNewSep;
592 pPrevSep = pSep;
593 pSep = pSep->mpNextSep;
596 OptimizeBand();
599 // -----------------------------------------------------------------------
601 void ImplRegionBand::XOr( long nXLeft, long nXRight )
603 DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::XOr(): nxLeft > nXRight" );
605 // #i46602# Reworked rectangle Xor
607 // In general, we can distinguish 11 cases of intersection
608 // (details below). The old implementation explicitely handled 7
609 // cases (numbered in the order of appearance, use CVS to get your
610 // hands on the old version), therefore, I've sticked to that
611 // order, and added four more cases. The code below references
612 // those numbers via #1, #2, etc.
614 // Num Mnem newX:oldX newY:oldY Description Result Can quit?
616 // #1 Empty band - - The band is empty, thus, simply add new bandSep just add Yes
618 // #2 apart - - The rectangles are disjunct, add new one as is just add Yes
620 // #3 atop == == The rectangles are _exactly_ the same, remove existing just remove Yes
622 // #4 around < > The new rectangle extends the old to both sides intersect No
624 // #5 left < < The new rectangle is left of the old (but intersects) intersect Yes
626 // #5b left-atop < == The new is left of the old, and coincides on the right intersect Yes
628 // #6 right > > The new is right of the old (but intersects) intersect No
630 // #6b right-atop == > The new is right of the old, and coincides on the left intersect No
632 // #7 inside > < The new is fully inside the old intersect Yes
634 // #8 inside-right > == The new is fully inside the old, coincides on the right intersect Yes
636 // #9 inside-left == < The new is fully inside the old, coincides on the left intersect Yes
639 // Then, to correctly perform XOr, the segment that's switched off
640 // (i.e. the overlapping part of the old and the new segment) must
641 // be extended by one pixel value at each border:
642 // 1 1
643 // 0 4 0 4
644 // 111100000001111
646 // Clearly, the leading band sep now goes from 0 to 3, and the
647 // trailing band sep from 11 to 14. This mimicks the xor look of a
648 // bitmap operation.
651 // band empty? -> add element
652 if ( !mpFirstSep )
654 mpFirstSep = new ImplRegionBandSep;
655 mpFirstSep->mnXLeft = nXLeft;
656 mpFirstSep->mnXRight = nXRight;
657 mpFirstSep->mbRemoved = FALSE;
658 mpFirstSep->mpNextSep = NULL;
659 return;
662 // process real xor
663 ImplRegionBandSep* pNewSep;
664 ImplRegionBandSep* pPrevSep = 0;
665 ImplRegionBandSep* pSep = mpFirstSep;
667 while ( pSep )
669 long nOldLeft( pSep->mnXLeft );
670 long nOldRight( pSep->mnXRight );
672 // did the current segment actually touch the new rect? If
673 // not, skip all comparisons, go on, loop and try to find
674 // intersecting bandSep
675 if( nXLeft <= nOldRight )
677 if( nXRight < nOldLeft )
679 // #2
681 // add _before_ current bandSep
682 pNewSep = new ImplRegionBandSep;
683 pNewSep->mnXLeft = nXLeft;
684 pNewSep->mnXRight = nXRight;
685 pNewSep->mpNextSep = pSep;
686 pNewSep->mbRemoved = FALSE;
688 // connections from the new separation
689 pNewSep->mpNextSep = pSep;
691 // connections to the new separation
692 if ( pSep == mpFirstSep )
693 mpFirstSep = pNewSep;
694 else
695 pPrevSep->mpNextSep = pNewSep;
696 pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
697 break;
699 else if( nXLeft == nOldLeft && nXRight == nOldRight )
701 // #3
702 pSep->mbRemoved = TRUE;
703 pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
704 break;
706 else if( nXLeft != nOldLeft && nXRight == nOldRight )
708 // # 5b, 8
709 if( nXLeft < nOldLeft )
711 nXRight = nOldLeft; // 5b
713 else
715 nXRight = nXLeft; // 8
716 nXLeft = nOldLeft;
719 pSep->mnXLeft = nXLeft;
720 pSep->mnXRight = nXRight-1;
722 pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
723 break;
725 else if( nXLeft == nOldLeft && nXRight != nOldRight )
727 // # 6b, 9
729 if( nXRight > nOldRight )
731 nXLeft = nOldRight+1; // 6b
733 // cannot break here, simply mark segment as removed,
734 // and go on with adapted nXLeft/nXRight
735 pSep->mbRemoved = TRUE;
737 else
739 pSep->mnXLeft = nXRight+1; // 9
741 pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
742 break;
745 else // if( nXLeft != nOldLeft && nXRight != nOldRight ) follows automatically
747 // #4,5,6,7
748 DBG_ASSERT( nXLeft != nOldLeft && nXRight != nOldRight,
749 "ImplRegionBand::XOr(): Case 4,5,6,7 expected all coordinates to be not equal!" );
751 // The plain-jane check would look like this:
753 // if( nXLeft < nOldLeft )
754 // {
755 // // #4,5
756 // if( nXRight > nOldRight )
757 // {
758 // // #4
759 // }
760 // else
761 // {
762 // // #5 done!
763 // }
764 // }
765 // else
766 // {
767 // // #6,7
768 // if( nXRight > nOldRight )
769 // {
770 // // #6
771 // }
772 // else
773 // {
774 // // #7 done!
775 // }
776 // }
778 // but since we generally don't have to care whether
779 // it's 4 or 6 (only that we must not stop processing
780 // here), condensed that in such a way that only the
781 // coordinates get shuffled into correct ordering.
783 if( nXLeft < nOldLeft )
784 ::std::swap( nOldLeft, nXLeft );
786 bool bDone( false );
788 if( nXRight < nOldRight )
790 ::std::swap( nOldRight, nXRight );
791 bDone = true;
794 // now, nOldLeft<nXLeft<=nOldRight<nXRight always
795 // holds. Note that we need the nXLeft<=nOldRight here, as
796 // the intersection part might be only one pixel (original
797 // nXLeft==nXRight)
798 DBG_ASSERT( nOldLeft<nXLeft && nXLeft<=nOldRight && nOldRight<nXRight,
799 "ImplRegionBand::XOr(): Case 4,5,6,7 expected coordinates to be ordered now!" );
801 pSep->mnXLeft = nOldLeft;
802 pSep->mnXRight = nXLeft-1;
804 nXLeft = nOldRight+1;
805 // nxRight is already setup correctly
807 if( bDone )
809 // add behind current bandSep
810 pNewSep = new ImplRegionBandSep;
812 pNewSep->mnXLeft = nXLeft;
813 pNewSep->mnXRight = nXRight;
814 pNewSep->mpNextSep = pSep->mpNextSep;
815 pNewSep->mbRemoved = FALSE;
817 // connections from the new separation
818 pSep->mpNextSep = pNewSep;
820 pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
821 break;
826 pPrevSep = pSep;
827 pSep = pSep->mpNextSep;
830 // new separation completely right of existing bandSeps ?
831 if( pPrevSep && nXLeft >= pPrevSep->mnXRight )
833 pNewSep = new ImplRegionBandSep;
834 pNewSep->mnXLeft = nXLeft;
835 pNewSep->mnXRight = nXRight;
836 pNewSep->mpNextSep = NULL;
837 pNewSep->mbRemoved = FALSE;
839 // connections from the new separation
840 pPrevSep->mpNextSep = pNewSep;
843 OptimizeBand();
846 // -----------------------------------------------------------------------
848 BOOL ImplRegionBand::IsInside( long nX )
850 ImplRegionBandSep* pSep = mpFirstSep;
851 while ( pSep )
853 if ( (pSep->mnXLeft <= nX) && (pSep->mnXRight >= nX) )
854 return TRUE;
856 pSep = pSep->mpNextSep;
859 return FALSE;
862 // -----------------------------------------------------------------------
864 BOOL ImplRegionBand::IsOver( long nLeft, long nRight )
866 ImplRegionBandSep* pSep = mpFirstSep;
867 while ( pSep )
869 if ( (pSep->mnXLeft < nRight) && (pSep->mnXRight > nLeft) )
870 return TRUE;
872 pSep = pSep->mpNextSep;
875 return FALSE;
878 // -----------------------------------------------------------------------
880 BOOL ImplRegionBand::IsInside( long nLeft, long nRight )
882 ImplRegionBandSep* pSep = mpFirstSep;
883 while ( pSep )
885 if ( (pSep->mnXLeft >= nLeft) && (nRight <= pSep->mnXRight) )
886 return TRUE;
888 pSep = pSep->mpNextSep;
891 return FALSE;
894 // -----------------------------------------------------------------------
896 long ImplRegionBand::GetXLeftBoundary() const
898 DBG_ASSERT( mpFirstSep != NULL, "ImplRegionBand::XLeftBoundary -> no separation in band!" );
900 return mpFirstSep->mnXLeft;
903 // -----------------------------------------------------------------------
905 long ImplRegionBand::GetXRightBoundary() const
907 DBG_ASSERT( mpFirstSep != NULL, "ImplRegionBand::XRightBoundary -> no separation in band!" );
909 // search last separation
910 ImplRegionBandSep* pSep = mpFirstSep;
911 while ( pSep->mpNextSep )
912 pSep = pSep->mpNextSep;
913 return pSep->mnXRight;
916 // -----------------------------------------------------------------------
918 BOOL ImplRegionBand::operator==( const ImplRegionBand& rRegionBand ) const
920 ImplRegionBandSep* pOwnRectBandSep = mpFirstSep;
921 ImplRegionBandSep* pSecondRectBandSep = rRegionBand.mpFirstSep;
922 while ( pOwnRectBandSep && pSecondRectBandSep )
924 // get boundaries of current rectangle
925 long nOwnXLeft = pOwnRectBandSep->mnXLeft;
926 long nSecondXLeft = pSecondRectBandSep->mnXLeft;
927 if ( nOwnXLeft != nSecondXLeft )
928 return FALSE;
930 long nOwnXRight = pOwnRectBandSep->mnXRight;
931 long nSecondXRight = pSecondRectBandSep->mnXRight;
932 if ( nOwnXRight != nSecondXRight )
933 return FALSE;
935 // get next separation from current band
936 pOwnRectBandSep = pOwnRectBandSep->mpNextSep;
938 // get next separation from current band
939 pSecondRectBandSep = pSecondRectBandSep->mpNextSep;
942 // differnt number of separations?
943 if ( pOwnRectBandSep || pSecondRectBandSep )
944 return FALSE;
946 return TRUE;
949 // -----------------------------------------------------------------------
951 ImplRegionBand* ImplRegionBand::SplitBand (const sal_Int32 nY)
953 OSL_ASSERT(nY>mnYTop);
954 OSL_ASSERT(nY<=mnYBottom);
956 // Create a copy of the given band (we tell the constructor to copy the points together
957 // with the seps.)
958 ImplRegionBand* pLowerBand = new ImplRegionBand(*this, false);
960 // Adapt vertical coordinates.
961 mnYBottom = nY-1;
962 pLowerBand->mnYTop = nY;
964 // Insert new band into list of bands.
965 pLowerBand->mpNextBand = mpNextBand;
966 mpNextBand = pLowerBand;
967 pLowerBand->mpPrevBand = this;
968 if (pLowerBand->mpNextBand != NULL)
969 pLowerBand->mpNextBand->mpPrevBand = pLowerBand;
971 return pLowerBand;