Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / source / gdi / regband.cxx
blobc4772110737ebbc60f35c4b664bad612cb67cdce
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/helpers.hxx>
21 #include <osl/diagnose.h>
22 #include <sal/log.hxx>
24 #include <regband.hxx>
26 // ImplRegionBand
28 // Each band contains all rectangles between upper and lower border.
29 // For Union, Intersect, Xor and Exclude operations rectangles of
30 // equal height are evaluated. The borders of the bands should always
31 // be chosen such that this is possible.
33 // If possible, rectangles within the bands are condensed.
35 // When converting polygons all points of the polygon are registered
36 // in the individual bands (for each band they are stored as
37 // points in a list). After registration of these points they are
38 // converted to rectangles and the points in the list are deleted.
40 ImplRegionBand::ImplRegionBand( long nTop, long nBottom )
42 // save boundaries
43 mnYTop = nTop;
44 mnYBottom = nBottom;
46 // initialize lists
47 mpNextBand = nullptr;
48 mpPrevBand = nullptr;
49 mpFirstSep = nullptr;
50 mpFirstBandPoint = nullptr;
51 mbTouched = false;
54 ImplRegionBand::ImplRegionBand(
55 const ImplRegionBand& rRegionBand,
56 const bool bIgnorePoints)
58 // copy boundaries
59 mnYTop = rRegionBand.mnYTop;
60 mnYBottom = rRegionBand.mnYBottom;
61 mbTouched = rRegionBand.mbTouched;
63 // initialisation
64 mpNextBand = nullptr;
65 mpPrevBand = nullptr;
66 mpFirstSep = nullptr;
67 mpFirstBandPoint = nullptr;
69 // copy all elements of the list with separations
70 ImplRegionBandSep* pNewSep;
71 ImplRegionBandSep* pPrevSep = nullptr;
72 ImplRegionBandSep* pSep = rRegionBand.mpFirstSep;
73 while ( pSep )
75 // create new and copy data
76 pNewSep = new ImplRegionBandSep;
77 pNewSep->mnXLeft = pSep->mnXLeft;
78 pNewSep->mnXRight = pSep->mnXRight;
79 pNewSep->mbRemoved = pSep->mbRemoved;
80 pNewSep->mpNextSep = nullptr;
81 if ( pSep == rRegionBand.mpFirstSep )
82 mpFirstSep = pNewSep;
83 else
84 pPrevSep->mpNextSep = pNewSep;
86 pPrevSep = pNewSep;
87 pSep = pSep->mpNextSep;
90 if ( ! bIgnorePoints)
92 // Copy points.
93 ImplRegionBandPoint* pPoint = rRegionBand.mpFirstBandPoint;
94 ImplRegionBandPoint* pPrevPointCopy = nullptr;
95 while (pPoint != nullptr)
97 ImplRegionBandPoint* pPointCopy = new ImplRegionBandPoint;
98 pPointCopy->mpNextBandPoint = nullptr;
99 pPointCopy->mnX = pPoint->mnX;
100 pPointCopy->mnLineId = pPoint->mnLineId;
101 pPointCopy->mbEndPoint = pPoint->mbEndPoint;
102 pPointCopy->meLineType = pPoint->meLineType;
104 if (pPrevPointCopy != nullptr)
105 pPrevPointCopy->mpNextBandPoint = pPointCopy;
106 else
107 mpFirstBandPoint = pPointCopy;
109 pPrevPointCopy = pPointCopy;
110 pPoint = pPoint->mpNextBandPoint;
115 ImplRegionBand::~ImplRegionBand()
117 SAL_WARN_IF( mpFirstBandPoint != nullptr, "vcl", "ImplRegionBand::~ImplRegionBand -> pointlist not empty" );
119 // delete elements of the list
120 ImplRegionBandSep* pSep = mpFirstSep;
121 while ( pSep )
123 ImplRegionBandSep* pTempSep = pSep->mpNextSep;
124 delete pSep;
125 pSep = pTempSep;
128 // delete elements of the list
129 ImplRegionBandPoint* pPoint = mpFirstBandPoint;
130 while ( pPoint )
132 ImplRegionBandPoint* pTempPoint = pPoint->mpNextBandPoint;
133 delete pPoint;
134 pPoint = pTempPoint;
138 // generate separations from lines and process union with existing
139 // separations
141 void ImplRegionBand::ProcessPoints()
143 // check Pointlist
144 ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint;
145 while ( pRegionBandPoint )
147 // within list?
148 if ( pRegionBandPoint->mpNextBandPoint )
150 // start/stop?
151 if ( pRegionBandPoint->mbEndPoint && pRegionBandPoint->mpNextBandPoint->mbEndPoint )
153 // same direction? -> remove next point!
154 if ( pRegionBandPoint->meLineType == pRegionBandPoint->mpNextBandPoint->meLineType )
156 ImplRegionBandPoint* pSaveRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
157 pRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint;
158 delete pSaveRegionBandPoint;
163 // continue with next element in the list
164 pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
167 pRegionBandPoint = mpFirstBandPoint;
168 while ( pRegionBandPoint && pRegionBandPoint->mpNextBandPoint )
170 Union( pRegionBandPoint->mnX, pRegionBandPoint->mpNextBandPoint->mnX );
172 ImplRegionBandPoint* pNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint;
174 // remove already processed points
175 delete pRegionBandPoint->mpNextBandPoint;
176 delete pRegionBandPoint;
178 // continue with next element in the list
179 pRegionBandPoint = pNextBandPoint;
182 // remove last element if necessary
183 delete pRegionBandPoint;
185 // list is now empty
186 mpFirstBandPoint = nullptr;
189 // generate separations from lines and process union with existing
190 // separations
192 bool ImplRegionBand::InsertPoint( long nX, long nLineId,
193 bool bEndPoint, LineType eLineType )
195 if ( !mpFirstBandPoint )
197 mpFirstBandPoint = new ImplRegionBandPoint;
198 mpFirstBandPoint->mnX = nX;
199 mpFirstBandPoint->mnLineId = nLineId;
200 mpFirstBandPoint->mbEndPoint = bEndPoint;
201 mpFirstBandPoint->meLineType = eLineType;
202 mpFirstBandPoint->mpNextBandPoint = nullptr;
203 return true;
206 // look if line already touched the band
207 ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint;
208 ImplRegionBandPoint* pLastTestedRegionBandPoint = nullptr;
209 while( pRegionBandPoint )
211 if ( pRegionBandPoint->mnLineId == nLineId )
213 if ( bEndPoint )
215 if( !pRegionBandPoint->mbEndPoint )
217 // remove old band point
218 if( !mpFirstBandPoint->mpNextBandPoint )
220 // if we've only got one point => replace first point
221 pRegionBandPoint->mnX = nX;
222 pRegionBandPoint->mbEndPoint = true;
223 return true;
225 else
227 // remove current point
228 if( !pLastTestedRegionBandPoint )
230 // remove and delete old first point
231 ImplRegionBandPoint* pSaveBandPoint = mpFirstBandPoint;
232 mpFirstBandPoint = mpFirstBandPoint->mpNextBandPoint;
233 delete pSaveBandPoint;
235 else
237 // remove and delete current band point
238 pLastTestedRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint;
239 delete pRegionBandPoint;
242 break;
246 else
247 return false;
250 // use next element
251 pLastTestedRegionBandPoint = pRegionBandPoint;
252 pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
255 // search appropriate position and insert point into the list
256 ImplRegionBandPoint* pNewRegionBandPoint;
258 pRegionBandPoint = mpFirstBandPoint;
259 pLastTestedRegionBandPoint = nullptr;
260 while ( pRegionBandPoint )
262 // new point completely left? -> insert as first point
263 if ( nX <= pRegionBandPoint->mnX )
265 pNewRegionBandPoint = new ImplRegionBandPoint;
266 pNewRegionBandPoint->mnX = nX;
267 pNewRegionBandPoint->mnLineId = nLineId;
268 pNewRegionBandPoint->mbEndPoint = bEndPoint;
269 pNewRegionBandPoint->meLineType = eLineType;
270 pNewRegionBandPoint->mpNextBandPoint = pRegionBandPoint;
272 // connections to the new point
273 if ( !pLastTestedRegionBandPoint )
274 mpFirstBandPoint = pNewRegionBandPoint;
275 else
276 pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
278 return true;
281 // use next element
282 pLastTestedRegionBandPoint = pRegionBandPoint;
283 pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
286 // not inserted -> add to the end of the list
287 pNewRegionBandPoint = new ImplRegionBandPoint;
288 pNewRegionBandPoint->mnX = nX;
289 pNewRegionBandPoint->mnLineId = nLineId;
290 pNewRegionBandPoint->mbEndPoint = bEndPoint;
291 pNewRegionBandPoint->meLineType = eLineType;
292 pNewRegionBandPoint->mpNextBandPoint = nullptr;
294 // connections to the new point
295 pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
297 return true;
300 void ImplRegionBand::MoveX( long nHorzMove )
302 // move all x-separations
303 ImplRegionBandSep* pSep = mpFirstSep;
304 while ( pSep )
306 pSep->mnXLeft += nHorzMove;
307 pSep->mnXRight += nHorzMove;
308 pSep = pSep->mpNextSep;
312 void ImplRegionBand::ScaleX( double fHorzScale )
314 ImplRegionBandSep* pSep = mpFirstSep;
315 while ( pSep )
317 pSep->mnXLeft = FRound( pSep->mnXLeft * fHorzScale );
318 pSep->mnXRight = FRound( pSep->mnXRight * fHorzScale );
319 pSep = pSep->mpNextSep;
323 // combine overlapping separations
325 void ImplRegionBand::OptimizeBand()
327 ImplRegionBandSep* pPrevSep = nullptr;
328 ImplRegionBandSep* pSep = mpFirstSep;
329 while ( pSep )
331 // remove?
332 if ( pSep->mbRemoved || (pSep->mnXRight < pSep->mnXLeft) )
334 ImplRegionBandSep* pOldSep = pSep;
335 if ( pSep == mpFirstSep )
336 mpFirstSep = pSep->mpNextSep;
337 else
338 pPrevSep->mpNextSep = pSep->mpNextSep;
339 pSep = pSep->mpNextSep;
340 delete pOldSep;
341 continue;
344 // overlapping separations? -> combine!
345 if ( pSep->mpNextSep )
347 if ( (pSep->mnXRight+1) >= pSep->mpNextSep->mnXLeft )
349 if ( pSep->mpNextSep->mnXRight > pSep->mnXRight )
350 pSep->mnXRight = pSep->mpNextSep->mnXRight;
352 ImplRegionBandSep* pOldSep = pSep->mpNextSep;
353 pSep->mpNextSep = pOldSep->mpNextSep;
354 delete pOldSep;
355 continue;
359 pPrevSep = pSep;
360 pSep = pSep->mpNextSep;
364 void ImplRegionBand::Union( long nXLeft, long nXRight )
366 SAL_WARN_IF( nXLeft > nXRight, "vcl", "ImplRegionBand::Union(): nxLeft > nXRight" );
368 // band empty? -> add element
369 if ( !mpFirstSep )
371 mpFirstSep = new ImplRegionBandSep;
372 mpFirstSep->mnXLeft = nXLeft;
373 mpFirstSep->mnXRight = nXRight;
374 mpFirstSep->mbRemoved = false;
375 mpFirstSep->mpNextSep = nullptr;
376 return;
379 // process real union
380 ImplRegionBandSep* pNewSep;
381 ImplRegionBandSep* pPrevSep = nullptr;
382 ImplRegionBandSep* pSep = mpFirstSep;
383 while ( pSep )
385 // new separation completely inside? nothing to do!
386 if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
387 return;
389 // new separation completely left? -> new separation!
390 if ( nXRight < pSep->mnXLeft )
392 pNewSep = new ImplRegionBandSep;
393 pNewSep->mnXLeft = nXLeft;
394 pNewSep->mnXRight = nXRight;
395 pNewSep->mbRemoved = false;
397 pNewSep->mpNextSep = pSep;
398 if ( pSep == mpFirstSep )
399 mpFirstSep = pNewSep;
400 else
401 pPrevSep->mpNextSep = pNewSep;
402 break;
405 // new separation overlapping from left? -> extend boundary
406 if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
407 pSep->mnXLeft = nXLeft;
409 // new separation overlapping from right? -> extend boundary
410 if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
412 pSep->mnXRight = nXRight;
413 break;
416 // not inserted, but last element? -> add to the end of the list
417 if ( !pSep->mpNextSep && (nXLeft > pSep->mnXRight) )
419 pNewSep = new ImplRegionBandSep;
420 pNewSep->mnXLeft = nXLeft;
421 pNewSep->mnXRight = nXRight;
422 pNewSep->mbRemoved = false;
424 pSep->mpNextSep = pNewSep;
425 pNewSep->mpNextSep = nullptr;
426 break;
429 pPrevSep = pSep;
430 pSep = pSep->mpNextSep;
433 OptimizeBand();
436 void ImplRegionBand::Intersect( long nXLeft, long nXRight )
438 SAL_WARN_IF( nXLeft > nXRight, "vcl", "ImplRegionBand::Intersect(): nxLeft > nXRight" );
440 // band has been touched
441 mbTouched = true;
443 // band empty? -> nothing to do
444 if ( !mpFirstSep )
445 return;
447 // process real intersection
448 ImplRegionBandSep* pSep = mpFirstSep;
449 while ( pSep )
451 // new separation completely outside? -> remove separation
452 if ( (nXRight < pSep->mnXLeft) || (nXLeft > pSep->mnXRight) )
453 // will be removed from the optimizer
454 pSep->mbRemoved = true;
456 // new separation overlapping from left? -> reduce right boundary
457 if ( (nXLeft <= pSep->mnXLeft) &&
458 (nXRight <= pSep->mnXRight) &&
459 (nXRight >= pSep->mnXLeft) )
460 pSep->mnXRight = nXRight;
462 // new separation overlapping from right? -> reduce right boundary
463 if ( (nXLeft >= pSep->mnXLeft) &&
464 (nXLeft <= pSep->mnXRight) &&
465 (nXRight >= pSep->mnXRight) )
466 pSep->mnXLeft = nXLeft;
468 // new separation within the actual one? -> reduce both boundaries
469 if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
471 pSep->mnXRight = nXRight;
472 pSep->mnXLeft = nXLeft;
475 pSep = pSep->mpNextSep;
478 OptimizeBand();
481 void ImplRegionBand::Exclude( long nXLeft, long nXRight )
483 SAL_WARN_IF( nXLeft > nXRight, "vcl", "ImplRegionBand::Exclude(): nxLeft > nXRight" );
485 // band has been touched
486 mbTouched = true;
488 // band empty? -> nothing to do
489 if ( !mpFirstSep )
490 return;
492 // process real exclusion
493 ImplRegionBandSep* pNewSep;
494 ImplRegionBandSep* pPrevSep = nullptr;
495 ImplRegionBandSep* pSep = mpFirstSep;
496 while ( pSep )
498 bool bSepProcessed = false;
500 // new separation completely overlapping? -> remove separation
501 if ( (nXLeft <= pSep->mnXLeft) && (nXRight >= pSep->mnXRight) )
503 // will be removed from the optimizer
504 pSep->mbRemoved = true;
505 bSepProcessed = true;
508 // new separation overlapping from left? -> reduce boundary
509 if ( !bSepProcessed )
511 if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
513 pSep->mnXLeft = nXRight+1;
514 bSepProcessed = true;
518 // new separation overlapping from right? -> reduce boundary
519 if ( !bSepProcessed )
521 if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
523 pSep->mnXRight = nXLeft-1;
524 bSepProcessed = true;
528 // new separation within the actual one? -> reduce boundary
529 // and add new entry for reminder
530 if ( !bSepProcessed )
532 if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
534 pNewSep = new ImplRegionBandSep;
535 pNewSep->mnXLeft = pSep->mnXLeft;
536 pNewSep->mnXRight = nXLeft-1;
537 pNewSep->mbRemoved = false;
539 pSep->mnXLeft = nXRight+1;
541 // connections from the new separation
542 pNewSep->mpNextSep = pSep;
544 // connections to the new separation
545 if ( pSep == mpFirstSep )
546 mpFirstSep = pNewSep;
547 else
548 pPrevSep->mpNextSep = pNewSep;
552 pPrevSep = pSep;
553 pSep = pSep->mpNextSep;
556 OptimizeBand();
559 void ImplRegionBand::XOr( long nXLeft, long nXRight )
561 SAL_WARN_IF( nXLeft > nXRight, "vcl", "ImplRegionBand::XOr(): nxLeft > nXRight" );
563 // #i46602# Reworked rectangle Xor
565 // In general, we can distinguish 11 cases of intersection
566 // (details below). The old implementation explicitly handled 7
567 // cases (numbered in the order of appearance, use CVS to get your
568 // hands on the old version), therefore, I've sticked to that
569 // order, and added four more cases. The code below references
570 // those numbers via #1, #2, etc.
572 // Num Mnem newX:oldX newY:oldY Description Result Can quit?
574 // #1 Empty band - - The band is empty, thus, simply add new bandSep just add Yes
576 // #2 apart - - The rectangles are disjunct, add new one as is just add Yes
578 // #3 atop == == The rectangles are _exactly_ the same, remove existing just remove Yes
580 // #4 around < > The new rectangle extends the old to both sides intersect No
582 // #5 left < < The new rectangle is left of the old (but intersects) intersect Yes
584 // #5b left-atop < == The new is left of the old, and coincides on the right intersect Yes
586 // #6 right > > The new is right of the old (but intersects) intersect No
588 // #6b right-atop == > The new is right of the old, and coincides on the left intersect No
590 // #7 inside > < The new is fully inside the old intersect Yes
592 // #8 inside-right > == The new is fully inside the old, coincides on the right intersect Yes
594 // #9 inside-left == < The new is fully inside the old, coincides on the left intersect Yes
596 // Then, to correctly perform XOr, the segment that's switched off
597 // (i.e. the overlapping part of the old and the new segment) must
598 // be extended by one pixel value at each border:
599 // 1 1
600 // 0 4 0 4
601 // 111100000001111
603 // Clearly, the leading band sep now goes from 0 to 3, and the
604 // trailing band sep from 11 to 14. This mimics the xor look of a
605 // bitmap operation.
607 // band empty? -> add element
608 if ( !mpFirstSep )
610 mpFirstSep = new ImplRegionBandSep;
611 mpFirstSep->mnXLeft = nXLeft;
612 mpFirstSep->mnXRight = nXRight;
613 mpFirstSep->mbRemoved = false;
614 mpFirstSep->mpNextSep = nullptr;
615 return;
618 // process real xor
619 ImplRegionBandSep* pNewSep;
620 ImplRegionBandSep* pPrevSep = nullptr;
621 ImplRegionBandSep* pSep = mpFirstSep;
623 while ( pSep )
625 long nOldLeft( pSep->mnXLeft );
626 long nOldRight( pSep->mnXRight );
628 // did the current segment actually touch the new rect? If
629 // not, skip all comparisons, go on, loop and try to find
630 // intersecting bandSep
631 if( nXLeft <= nOldRight )
633 if( nXRight < nOldLeft )
635 // #2
637 // add _before_ current bandSep
638 pNewSep = new ImplRegionBandSep;
639 pNewSep->mnXLeft = nXLeft;
640 pNewSep->mnXRight = nXRight;
641 pNewSep->mpNextSep = pSep;
642 pNewSep->mbRemoved = false;
644 // connections from the new separation
645 pNewSep->mpNextSep = pSep;
647 // connections to the new separation
648 if ( pSep == mpFirstSep )
649 mpFirstSep = pNewSep;
650 else
651 pPrevSep->mpNextSep = pNewSep;
652 pPrevSep = nullptr; // do not run accidentally into the "right" case when breaking the loop
653 break;
655 else if( nXLeft == nOldLeft && nXRight == nOldRight )
657 // #3
658 pSep->mbRemoved = true;
659 pPrevSep = nullptr; // do not run accidentally into the "right" case when breaking the loop
660 break;
662 else if( nXLeft != nOldLeft && nXRight == nOldRight )
664 // # 5b, 8
665 if( nXLeft < nOldLeft )
667 nXRight = nOldLeft; // 5b
669 else
671 nXRight = nXLeft; // 8
672 nXLeft = nOldLeft;
675 pSep->mnXLeft = nXLeft;
676 pSep->mnXRight = nXRight-1;
678 pPrevSep = nullptr; // do not run accidentally into the "right" case when breaking the loop
679 break;
681 else if( nXLeft == nOldLeft && nXRight != nOldRight )
683 // # 6b, 9
685 if( nXRight > nOldRight )
687 nXLeft = nOldRight+1; // 6b
689 // cannot break here, simply mark segment as removed,
690 // and go on with adapted nXLeft/nXRight
691 pSep->mbRemoved = true;
693 else
695 pSep->mnXLeft = nXRight+1; // 9
697 pPrevSep = nullptr; // do not run accidentally into the "right" case when breaking the loop
698 break;
701 else // if( nXLeft != nOldLeft && nXRight != nOldRight ) follows automatically
703 // #4,5,6,7
704 SAL_WARN_IF( nXLeft == nOldLeft || nXRight == nOldRight, "vcl",
705 "ImplRegionBand::XOr(): Case 4,5,6,7 expected all coordinates to be not equal!" );
707 // The plain-jane check would look like this:
709 // if( nXLeft < nOldLeft )
710 // {
711 // // #4,5
712 // if( nXRight > nOldRight )
713 // {
714 // // #4
715 // }
716 // else
717 // {
718 // // #5 done!
719 // }
720 // }
721 // else
722 // {
723 // // #6,7
724 // if( nXRight > nOldRight )
725 // {
726 // // #6
727 // }
728 // else
729 // {
730 // // #7 done!
731 // }
732 // }
734 // but since we generally don't have to care whether
735 // it's 4 or 6 (only that we must not stop processing
736 // here), condensed that in such a way that only the
737 // coordinates get shuffled into correct ordering.
739 if( nXLeft < nOldLeft )
740 ::std::swap( nOldLeft, nXLeft );
742 bool bDone( false );
744 if( nXRight < nOldRight )
746 ::std::swap( nOldRight, nXRight );
747 bDone = true;
750 // now, nOldLeft<nXLeft<=nOldRight<nXRight always
751 // holds. Note that we need the nXLeft<=nOldRight here, as
752 // the intersection part might be only one pixel (original
753 // nXLeft==nXRight)
754 SAL_WARN_IF( nOldLeft==nXLeft || nXLeft>nOldRight || nOldRight>=nXRight, "vcl",
755 "ImplRegionBand::XOr(): Case 4,5,6,7 expected coordinates to be ordered now!" );
757 pSep->mnXLeft = nOldLeft;
758 pSep->mnXRight = nXLeft-1;
760 nXLeft = nOldRight+1;
761 // nxRight is already setup correctly
763 if( bDone )
765 // add behind current bandSep
766 pNewSep = new ImplRegionBandSep;
768 pNewSep->mnXLeft = nXLeft;
769 pNewSep->mnXRight = nXRight;
770 pNewSep->mpNextSep = pSep->mpNextSep;
771 pNewSep->mbRemoved = false;
773 // connections from the new separation
774 pSep->mpNextSep = pNewSep;
776 pPrevSep = nullptr; // do not run accidentally into the "right" case when breaking the loop
777 break;
782 pPrevSep = pSep;
783 pSep = pSep->mpNextSep;
786 // new separation completely right of existing bandSeps ?
787 if( pPrevSep && nXLeft >= pPrevSep->mnXRight )
789 pNewSep = new ImplRegionBandSep;
790 pNewSep->mnXLeft = nXLeft;
791 pNewSep->mnXRight = nXRight;
792 pNewSep->mpNextSep = nullptr;
793 pNewSep->mbRemoved = false;
795 // connections from the new separation
796 pPrevSep->mpNextSep = pNewSep;
799 OptimizeBand();
802 bool ImplRegionBand::IsInside( long nX )
804 ImplRegionBandSep* pSep = mpFirstSep;
805 while ( pSep )
807 if ( (pSep->mnXLeft <= nX) && (pSep->mnXRight >= nX) )
808 return true;
810 pSep = pSep->mpNextSep;
813 return false;
816 long ImplRegionBand::GetXLeftBoundary() const
818 assert(mpFirstSep && "ImplRegionBand::XLeftBoundary -> no separation in band!");
820 return mpFirstSep->mnXLeft;
823 long ImplRegionBand::GetXRightBoundary() const
825 SAL_WARN_IF( mpFirstSep == nullptr, "vcl", "ImplRegionBand::XRightBoundary -> no separation in band!" );
827 // search last separation
828 ImplRegionBandSep* pSep = mpFirstSep;
829 while ( pSep->mpNextSep )
830 pSep = pSep->mpNextSep;
831 return pSep->mnXRight;
834 bool ImplRegionBand::operator==( const ImplRegionBand& rRegionBand ) const
836 ImplRegionBandSep* pOwnRectBandSep = mpFirstSep;
837 ImplRegionBandSep* pSecondRectBandSep = rRegionBand.mpFirstSep;
838 while ( pOwnRectBandSep && pSecondRectBandSep )
840 // get boundaries of current rectangle
841 long nOwnXLeft = pOwnRectBandSep->mnXLeft;
842 long nSecondXLeft = pSecondRectBandSep->mnXLeft;
843 if ( nOwnXLeft != nSecondXLeft )
844 return false;
846 long nOwnXRight = pOwnRectBandSep->mnXRight;
847 long nSecondXRight = pSecondRectBandSep->mnXRight;
848 if ( nOwnXRight != nSecondXRight )
849 return false;
851 // get next separation from current band
852 pOwnRectBandSep = pOwnRectBandSep->mpNextSep;
854 // get next separation from current band
855 pSecondRectBandSep = pSecondRectBandSep->mpNextSep;
858 // different number of separations?
859 return !(pOwnRectBandSep || pSecondRectBandSep);
862 ImplRegionBand* ImplRegionBand::SplitBand (const sal_Int32 nY)
864 OSL_ASSERT(nY>mnYTop);
865 OSL_ASSERT(nY<=mnYBottom);
867 // Create a copy of the given band (we tell the constructor to copy the points together
868 // with the seps.)
869 ImplRegionBand* pLowerBand = new ImplRegionBand(*this, false);
871 // Adapt vertical coordinates.
872 mnYBottom = nY-1;
873 pLowerBand->mnYTop = nY;
875 // Insert new band into list of bands.
876 pLowerBand->mpNextBand = mpNextBand;
877 mpNextBand = pLowerBand;
878 pLowerBand->mpPrevBand = this;
879 if (pLowerBand->mpNextBand != nullptr)
880 pLowerBand->mpNextBand->mpPrevBand = pLowerBand;
882 return pLowerBand;
885 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */