xref: /AOO41X/main/vcl/source/gdi/region.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <limits.h>
28 
29 #include <tools/vcompat.hxx>
30 #include <tools/stream.hxx>
31 #include <tools/debug.hxx>
32 
33 #include <vcl/region.hxx>
34 #include <vcl/regband.hxx>
35 #include <vcl/salbtype.hxx>
36 
37 #include <region.h>
38 
39 #include <basegfx/matrix/b2dhommatrix.hxx>
40 #include <basegfx/polygon/b2dpolypolygontools.hxx>
41 #include <basegfx/polygon/b2dpolygontools.hxx>
42 #include <basegfx/polygon/b2dpolygonclipper.hxx>
43 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
44 #include <basegfx/range/b2drange.hxx>
45 #include <basegfx/matrix/b2dhommatrixtools.hxx>
46 
47 // =======================================================================
48 //
49 // ImplRegionBand
50 //
51 // Die Klassen RegionBand/ImplRegionBand speichert Regionen in Form von
52 // Rechtecken ab. Die Region ist in Y-Richtung in Baendern unterteilt, die
53 // wiederum ein oder mehrere Rechtecke mit der Hoehe des Bandes enthalten.
54 //
55 // Leere Baender werden entfernt.
56 //
57 // Polygone und PolyPolygone werden ebenfalls in Rechtecke zerlegt und in
58 // der Baendern abgelegt. Hierzu werden alle Punkte der einzelnen Polygone
59 // mit dem Bresenham-Algorithmus berechnet und in die Baender eingetragen.
60 // Nach der vollstaendigen Berechung aller Kanten werden die entsprechenden
61 // Rechntecke berechnet
62 
63 // =======================================================================
64 
65 static ImplRegionBase aImplNullRegion( 0 );
66 static ImplRegionBase aImplEmptyRegion( 0 );
67 
68 // =======================================================================
69 
70 DBG_NAME( Region )
71 DBG_NAMEEX( Polygon )
72 DBG_NAMEEX( PolyPolygon )
73 
74 namespace {
75 
76 /** Return <TRUE/> when the given polygon is rectiliner and oriented so that
77     all sides are either horizontal or vertical.
78 */
79 bool ImplIsPolygonRectilinear (const PolyPolygon& rPolyPoly)
80 {
81     // Iterate over all polygons.
82     const sal_uInt16 nPolyCount = rPolyPoly.Count();
83     for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
84     {
85         const Polygon&  aPoly = rPolyPoly.GetObject(nPoly);
86 
87         // Iterate over all edges of the current polygon.
88         const sal_uInt16 nSize = aPoly.GetSize();
89 
90         if (nSize < 2)
91             continue;
92         Point aPoint (aPoly.GetPoint(0));
93         const Point aLastPoint (aPoint);
94         for (sal_uInt16 nPoint = 1; nPoint < nSize; ++nPoint)
95         {
96             const Point aNextPoint (aPoly.GetPoint(nPoint));
97             // When there is at least one edge that is neither vertical nor
98             // horizontal then the entire polygon is not rectilinear (and
99             // oriented along primary axes.)
100             if (aPoint.X() != aNextPoint.X() && aPoint.Y() != aNextPoint.Y())
101                 return false;
102 
103             aPoint = aNextPoint;
104         }
105         // Compare closing edge.
106         if (aLastPoint.X() != aPoint.X() && aLastPoint.Y() != aPoint.Y())
107             return false;
108     }
109     return true;
110 }
111 
112 
113 
114 /** This function is similar to the ImplRegion::InsertBands() method.
115     It creates a minimal set of missing bands so that the entire vertical
116     interval from nTop to nBottom is covered by bands.
117 */
118 void ImplAddMissingBands (
119     ImplRegion* pImplRegion,
120     const long nTop,
121     const long nBottom)
122 {
123     // Iterate over already existing bands and add missing bands atop the
124     // first and between two bands.
125     ImplRegionBand* pPreviousBand = NULL;
126     ImplRegionBand* pBand = pImplRegion->ImplGetFirstRegionBand();
127     long nCurrentTop (nTop);
128     while (pBand != NULL && nCurrentTop<nBottom)
129     {
130         if (nCurrentTop < pBand->mnYTop)
131         {
132             // Create new band above the current band.
133             ImplRegionBand* pAboveBand = new ImplRegionBand(
134                 nCurrentTop,
135                 ::std::min(nBottom,pBand->mnYTop-1));
136             pImplRegion->InsertBand(pPreviousBand, pAboveBand);
137         }
138 
139         // Adapt the top of the interval to prevent overlapping bands.
140         nCurrentTop = ::std::max(nTop, pBand->mnYBottom+1);
141 
142         // Advance to next band.
143         pPreviousBand = pBand;
144         pBand = pBand->mpNextBand;
145     }
146 
147     // We still have to cover two cases:
148     // 1. The region does not yet contain any bands.
149     // 2. The intervall nTop->nBottom extends past the bottom most band.
150     if (nCurrentTop <= nBottom
151         && (pBand==NULL || nBottom>pBand->mnYBottom))
152     {
153         // When there is no previous band then the new one will be the
154         // first.  Otherwise the new band is inserted behind the last band.
155         pImplRegion->InsertBand(
156             pPreviousBand,
157             new ImplRegionBand(
158                 nCurrentTop,
159                 nBottom));
160     }
161 }
162 
163 
164 
165 /** Convert a rectilinear polygon (that is oriented along the primary axes)
166     to a list of bands.  For this special form of polygon we can use an
167     optimization that prevents the creation of one band per y value.
168     However, it still is possible that some temporary bands are created that
169     later can be optimized away.
170     @param rPolyPolygon
171         A set of zero, one, or more polygons, nested or not, that are
172         converted into a list of bands.
173     @return
174         A new ImplRegion object is returned that contains the bands that
175         represent the given poly-polygon.
176 */
177 ImplRegion* ImplRectilinearPolygonToBands (const PolyPolygon& rPolyPoly)
178 {
179     OSL_ASSERT(ImplIsPolygonRectilinear (rPolyPoly));
180 
181     // Create a new ImplRegion object as container of the bands.
182     ImplRegion* pImplRegion = new ImplRegion();
183     long nLineId = 0L;
184 
185     // Iterate over all polygons.
186     const sal_uInt16 nPolyCount = rPolyPoly.Count();
187     for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
188     {
189         const Polygon&  aPoly = rPolyPoly.GetObject(nPoly);
190 
191         // Iterate over all edges of the current polygon.
192         const sal_uInt16 nSize = aPoly.GetSize();
193         if (nSize < 2)
194             continue;
195         // Avoid fetching every point twice (each point is the start point
196         // of one and the end point of another edge.)
197         Point aStart (aPoly.GetPoint(0));
198         Point aEnd;
199         for (sal_uInt16 nPoint = 1; nPoint <= nSize; ++nPoint, aStart=aEnd)
200         {
201             // We take the implicit closing edge into account by mapping
202             // index nSize to 0.
203             aEnd = aPoly.GetPoint(nPoint%nSize);
204             if (aStart.Y() == aEnd.Y())
205             {
206                 // Horizontal lines are ignored.
207                 continue;
208             }
209 
210             // At this point the line has to be vertical.
211             OSL_ASSERT(aStart.X() == aEnd.X());
212 
213             // Sort y-coordinates to simplify the algorithm and store the
214             // direction seperately.  The direction is calculated as it is
215             // in other places (but seems to be the wrong way.)
216             const long nTop (::std::min(aStart.Y(), aEnd.Y()));
217             const long nBottom (::std::max(aStart.Y(), aEnd.Y()));
218             const LineType eLineType (aStart.Y() > aEnd.Y() ? LINE_DESCENDING : LINE_ASCENDING);
219 
220             // Make sure that the current line is covered by bands.
221             ImplAddMissingBands(pImplRegion, nTop,nBottom);
222 
223             // Find top-most band that may contain nTop.
224             ImplRegionBand* pBand = pImplRegion->ImplGetFirstRegionBand();
225             while (pBand!=NULL && pBand->mnYBottom < nTop)
226                 pBand = pBand->mpNextBand;
227             ImplRegionBand* pTopBand = pBand;
228             // If necessary split the band at nTop so that nTop is contained
229             // in the lower band.
230             if (pBand!=NULL
231                    // Prevent the current band from becoming 0 pixel high
232                 && pBand->mnYTop<nTop
233                    // this allows the lowest pixel of the band to be split off
234                 && pBand->mnYBottom>=nTop
235                    // do not split a band that is just one pixel high
236                 && pBand->mnYTop<pBand->mnYBottom)
237             {
238                 // Split the top band.
239                 pTopBand = pBand->SplitBand(nTop);
240             }
241 
242             // Advance to band that may contain nBottom.
243             while (pBand!=NULL && pBand->mnYBottom < nBottom)
244                 pBand = pBand->mpNextBand;
245             // The lowest band may have to be split at nBottom so that
246             // nBottom itself remains in the upper band.
247             if (pBand!=NULL
248                    // allow the current band becoming 1 pixel high
249                 && pBand->mnYTop<=nBottom
250                    // prevent splitting off a band that is 0 pixel high
251                 && pBand->mnYBottom>nBottom
252                    // do not split a band that is just one pixel high
253                 && pBand->mnYTop<pBand->mnYBottom)
254             {
255                 // Split the bottom band.
256                 pBand->SplitBand(nBottom+1);
257             }
258 
259             // Note that we remember the top band (in pTopBand) but not the
260             // bottom band.  The later can be determined by comparing y
261             // coordinates.
262 
263             // Add the x-value as point to all bands in the nTop->nBottom range.
264             for (pBand=pTopBand; pBand!=NULL&&pBand->mnYTop<=nBottom; pBand=pBand->mpNextBand)
265                 pBand->InsertPoint(aStart.X(), nLineId++, sal_True, eLineType);
266         }
267     }
268 
269     return pImplRegion;
270 }
271 
272 
273 
274 
275 /** Convert a general polygon (one for which ImplIsPolygonRectilinear()
276     returns <FALSE/>) to bands.
277 */
278 ImplRegion* ImplGeneralPolygonToBands (
279     const PolyPolygon& rPolyPoly,
280     const Rectangle& rPolygonBoundingBox)
281 {
282     long nLineID = 0L;
283 
284     // initialisation and creation of Bands
285     ImplRegion* pImplRegion = new ImplRegion();
286     pImplRegion->CreateBandRange( rPolygonBoundingBox.Top(), rPolygonBoundingBox.Bottom() );
287 
288     // insert polygons
289     const sal_uInt16 nPolyCount = rPolyPoly.Count();
290     for ( sal_uInt16 nPoly = 0; nPoly < nPolyCount; nPoly++ )
291     {
292         // get reference to current polygon
293         const Polygon&  aPoly = rPolyPoly.GetObject( nPoly );
294         const sal_uInt16    nSize = aPoly.GetSize();
295 
296         // not enough points ( <= 2 )? -> nothing to do!
297         if ( nSize <= 2 )
298             continue;
299 
300         // band the polygon
301         for ( sal_uInt16 nPoint = 1; nPoint < nSize; nPoint++ )
302             pImplRegion->InsertLine( aPoly.GetPoint(nPoint-1), aPoly.GetPoint(nPoint), nLineID++ );
303 
304         // close polygon with line from first point to last point, if neccesary
305         const Point rLastPoint = aPoly.GetPoint(nSize-1);
306         const Point rFirstPoint = aPoly.GetPoint(0);
307         if ( rLastPoint != rFirstPoint )
308             pImplRegion->InsertLine( rLastPoint, rFirstPoint, nLineID++ );
309     }
310 
311     return pImplRegion;
312 }
313 
314 
315 } // end of anonymous namespace
316 
317 
318 // -----------------------------------------------------------------------
319 
320 #ifdef DBG_UTIL
321 const char* ImplDbgTestRegion( const void* pObj )
322 {
323     Region*       pRegion = (Region*)pObj;
324     ImplRegion*   pImplRegion = pRegion->ImplGetImplRegion();
325 
326     if ( aImplNullRegion.mnRefCount )
327         return "Null-Region-RefCount modified";
328     if ( aImplNullRegion.mnRectCount )
329         return "Null-Region-RectCount modified";
330     if ( aImplNullRegion.mpPolyPoly )
331         return "Null-Region-PolyPoly modified";
332     if ( aImplEmptyRegion.mnRefCount )
333         return "Emptry-Region-RefCount modified";
334     if ( aImplEmptyRegion.mnRectCount )
335         return "Emptry-Region-RectCount modified";
336     if ( aImplEmptyRegion.mpPolyPoly )
337         return "Emptry-Region-PolyPoly modified";
338 
339     if ( (pImplRegion != &aImplEmptyRegion) && (pImplRegion != &aImplNullRegion) )
340     {
341         sal_uLong                   nCount = 0;
342         const ImplRegionBand*   pBand = pImplRegion->ImplGetFirstRegionBand();
343         while ( pBand )
344         {
345             if ( pBand->mnYBottom < pBand->mnYTop )
346                 return "YBottom < YTop";
347             if ( pBand->mpNextBand )
348             {
349                 if ( pBand->mnYBottom >= pBand->mpNextBand->mnYTop )
350                     return "overlapping bands in region";
351             }
352             if ( pBand->mbTouched > 1 )
353                 return "Band-mbTouched overwrite";
354 
355             ImplRegionBandSep* pSep = pBand->mpFirstSep;
356             while ( pSep )
357             {
358                 if ( pSep->mnXRight < pSep->mnXLeft )
359                     return "XLeft < XRight";
360                 if ( pSep->mpNextSep )
361                 {
362                     if ( pSep->mnXRight >= pSep->mpNextSep->mnXLeft )
363                         return "overlapping separations in region";
364                 }
365                 if ( pSep->mbRemoved > 1 )
366                     return "Sep-mbRemoved overwrite";
367 
368                 nCount++;
369                 pSep = pSep->mpNextSep;
370             }
371 
372             pBand = pBand->mpNextBand;
373         }
374 
375         if ( pImplRegion->mnRectCount != nCount )
376             return "mnRetCount is not valid";
377     }
378 
379     return NULL;
380 }
381 
382 void TraceBands (const ImplRegionBand* pFirstBand)
383 {
384     int nBandIndex  (0);
385     const ImplRegionBand* pBand = pFirstBand;
386     while (pBand != NULL)
387     {
388         OSL_TRACE("            band %d  %d->%d : ", nBandIndex++,
389             pBand->mnYTop, pBand->mnYBottom);
390 
391         ImplRegionBandPoint* pPoint = pBand->mpFirstBandPoint;
392         while (pPoint != NULL)
393         {
394             OSL_TRACE(" %d ", pPoint->mnX);
395             pPoint = pPoint->mpNextBandPoint;
396         }
397         OSL_TRACE("  |  ");
398 
399         ImplRegionBandSep* pSep = pBand->mpFirstSep;
400         while (pSep != NULL)
401         {
402             OSL_TRACE(" %d->%d ", pSep->mnXLeft, pSep->mnXRight);
403             pSep = pSep->mpNextSep;
404         }
405         OSL_TRACE("\n");
406 
407         pBand = pBand->mpNextBand;
408     }
409 }
410 #endif
411 
412 // =======================================================================
413 
414 inline void Region::ImplPolyPolyRegionToBandRegion()
415 {
416     if( mpImplRegion->mpPolyPoly || mpImplRegion->mpB2DPolyPoly )
417         ImplPolyPolyRegionToBandRegionFunc();
418 }
419 
420 // =======================================================================
421 
422 ImplRegionBase::ImplRegionBase( int nRefCount )
423 :   mnRefCount( nRefCount )
424 ,   mnRectCount( 0 )
425 ,   mpPolyPoly( NULL )
426 ,   mpB2DPolyPoly( NULL )
427 {}
428 
429 // ------------------------------------------------------------------------
430 
431 ImplRegion::ImplRegion()
432 {
433     mpFirstBand         = NULL;
434     mpLastCheckedBand   = NULL;
435 }
436 
437 // ------------------------------------------------------------------------
438 
439 ImplRegion::ImplRegion( const PolyPolygon& rPolyPoly )
440 {
441     mpFirstBand         = NULL;
442     mpLastCheckedBand   = NULL;
443     mpPolyPoly          = new PolyPolygon( rPolyPoly );
444 }
445 
446 // ------------------------------------------------------------------------
447 
448 ImplRegion::ImplRegion( const basegfx::B2DPolyPolygon& rPolyPoly )
449 {
450     mpFirstBand = NULL;
451     mpLastCheckedBand = NULL;
452     mpB2DPolyPoly = new basegfx::B2DPolyPolygon( rPolyPoly );
453 }
454 
455 // -----------------------------------------------------------------------
456 
457 ImplRegion::ImplRegion( const ImplRegion& rImplRegion )
458 :   ImplRegionBase()
459 {
460     mpFirstBand = NULL;
461     mpLastCheckedBand = NULL;
462     mnRectCount = rImplRegion.mnRectCount;
463 
464     if ( rImplRegion.mpPolyPoly )
465         mpPolyPoly = new PolyPolygon( *rImplRegion.mpPolyPoly );
466     else if( rImplRegion.mpB2DPolyPoly )
467         mpB2DPolyPoly = new basegfx::B2DPolyPolygon( *rImplRegion.mpB2DPolyPoly );
468 
469     // insert band(s) into the list
470     ImplRegionBand* pNewBand;
471     ImplRegionBand* pPrevBand = 0;
472     ImplRegionBand* pBand = rImplRegion.mpFirstBand;
473     while ( pBand )
474     {
475         pNewBand = new ImplRegionBand( *pBand );
476 
477         // first element? -> set as first into the list
478         if ( pBand == rImplRegion.mpFirstBand )
479             mpFirstBand = pNewBand;
480         else
481             pPrevBand->mpNextBand = pNewBand;
482 
483         pPrevBand = pNewBand;
484         pBand = pBand->mpNextBand;
485     }
486 }
487 
488 // -----------------------------------------------------------------------
489 
490 ImplRegion::~ImplRegion()
491 {
492     DBG_ASSERT( (this != &aImplEmptyRegion) && (this != &aImplNullRegion),
493                 "ImplRegion::~ImplRegion() - Empty oder NULL-Region" );
494 
495     ImplRegionBand* pBand = mpFirstBand;
496     while ( pBand )
497     {
498         ImplRegionBand* pTempBand = pBand->mpNextBand;
499         delete pBand;
500         pBand = pTempBand;
501     }
502 }
503 
504 // -----------------------------------------------------------------------
505 
506 ImplRegionBase::~ImplRegionBase()
507 {
508     delete mpPolyPoly;
509     delete mpB2DPolyPoly;
510 }
511 
512 // -----------------------------------------------------------------------
513 //
514 // create complete range of bands in single steps
515 
516 void ImplRegion::CreateBandRange( long nYTop, long nYBottom )
517 {
518     // add top band
519     mpFirstBand = new ImplRegionBand( nYTop-1, nYTop-1 );
520 
521     // begin first search from the first element
522     mpLastCheckedBand = mpFirstBand;
523 
524     ImplRegionBand* pBand = mpFirstBand;
525     for ( int i = nYTop; i <= nYBottom+1; i++ )
526     {
527         // create new band
528         ImplRegionBand* pNewBand = new ImplRegionBand( i, i );
529         pBand->mpNextBand = pNewBand;
530         if ( pBand != mpFirstBand )
531             pNewBand->mpPrevBand = pBand;
532 
533         pBand = pBand->mpNextBand;
534     }
535 }
536 
537 // -----------------------------------------------------------------------
538 
539 sal_Bool ImplRegion::InsertLine( const Point& rStartPt, const Point& rEndPt,
540                              long nLineId )
541 {
542     long nX, nY;
543 
544     // lines consisting of a single point do not interest here
545     if ( rStartPt == rEndPt )
546         return sal_True;
547 
548     LineType eLineType = (rStartPt.Y() > rEndPt.Y()) ? LINE_DESCENDING : LINE_ASCENDING;
549     if ( rStartPt.X() == rEndPt.X() )
550     {
551         // vertical line
552         const long nEndY = rEndPt.Y();
553 
554         nX = rStartPt.X();
555         nY = rStartPt.Y();
556 
557         if( nEndY > nY )
558         {
559             for ( ; nY <= nEndY; nY++ )
560             {
561                 Point aNewPoint( nX, nY );
562                 InsertPoint( aNewPoint, nLineId,
563                              (aNewPoint == rEndPt) || (aNewPoint == rStartPt),
564                              eLineType );
565             }
566         }
567         else
568         {
569             for ( ; nY >= nEndY; nY-- )
570             {
571                 Point aNewPoint( nX, nY );
572                 InsertPoint( aNewPoint, nLineId,
573                              (aNewPoint == rEndPt) || (aNewPoint == rStartPt),
574                              eLineType );
575             }
576         }
577     }
578     else if ( rStartPt.Y() != rEndPt.Y() )
579     {
580         const long  nDX = labs( rEndPt.X() - rStartPt.X() );
581         const long  nDY = labs( rEndPt.Y() - rStartPt.Y() );
582         const long  nStartX = rStartPt.X();
583         const long  nStartY = rStartPt.Y();
584         const long  nEndX = rEndPt.X();
585         const long  nEndY = rEndPt.Y();
586         const long  nXInc = ( nStartX < nEndX ) ? 1L : -1L;
587         const long  nYInc = ( nStartY < nEndY ) ? 1L : -1L;
588 
589         if ( nDX >= nDY )
590         {
591             const long  nDYX = ( nDY - nDX ) << 1;
592             const long  nDY2 = nDY << 1;
593             long        nD = nDY2 - nDX;
594 
595             for ( nX = nStartX, nY = nStartY; nX != nEndX; nX += nXInc )
596             {
597                 InsertPoint( Point( nX, nY ), nLineId, nStartX == nX, eLineType );
598 
599                 if ( nD < 0L )
600                     nD += nDY2;
601                 else
602                     nD += nDYX, nY += nYInc;
603             }
604         }
605         else
606         {
607             const long  nDYX = ( nDX - nDY ) << 1;
608             const long  nDY2 = nDX << 1;
609             long        nD = nDY2 - nDY;
610 
611             for ( nX = nStartX, nY = nStartY; nY != nEndY; nY += nYInc )
612             {
613                 InsertPoint( Point( nX, nY ), nLineId, nStartY == nY, eLineType );
614 
615                 if ( nD < 0L )
616                     nD += nDY2;
617                 else
618                     nD += nDYX, nX += nXInc;
619             }
620         }
621 
622         // last point
623         InsertPoint( Point( nEndX, nEndY ), nLineId, sal_True, eLineType );
624     }
625 
626     return sal_True;
627 }
628 
629 // -----------------------------------------------------------------------
630 //
631 // search for appropriate place for the new point
632 
633 sal_Bool ImplRegion::InsertPoint( const Point &rPoint, long nLineID,
634                               sal_Bool bEndPoint, LineType eLineType )
635 {
636     DBG_ASSERT( mpFirstBand != NULL, "ImplRegion::InsertPoint - no bands available!" );
637 
638     if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
639     {
640         mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
641         return sal_True;
642     }
643 
644     if ( rPoint.Y() > mpLastCheckedBand->mnYTop )
645     {
646         // Search ascending
647         while ( mpLastCheckedBand )
648         {
649             // Insert point if possible
650             if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
651             {
652                 mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
653                 return sal_True;
654             }
655 
656             mpLastCheckedBand = mpLastCheckedBand->mpNextBand;
657         }
658 
659         DBG_ERROR( "ImplRegion::InsertPoint reached the end of the list!" );
660     }
661     else
662     {
663         // Search descending
664         while ( mpLastCheckedBand )
665         {
666             // Insert point if possible
667             if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
668             {
669                 mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
670                 return sal_True;
671             }
672 
673             mpLastCheckedBand = mpLastCheckedBand->mpPrevBand;
674         }
675 
676         DBG_ERROR( "ImplRegion::InsertPoint reached the beginning of the list!" );
677     }
678 
679     DBG_ERROR( "ImplRegion::InsertPoint point not inserted!" );
680 
681     // reinitialize pointer (should never be reached!)
682     mpLastCheckedBand = mpFirstBand;
683 
684     return sal_False;
685 }
686 
687 // -----------------------------------------------------------------------
688 //
689 // search for appropriate places for the new bands
690 
691 void ImplRegion::InsertBands( long nTop, long nBottom )
692 {
693     // region empty? -> set rectagle as first entry!
694     if ( !mpFirstBand )
695     {
696         // add band with boundaries of the rectangle
697         mpFirstBand = new ImplRegionBand( nTop, nBottom );
698         return;
699     }
700 
701     // find/insert bands for the boundaries of the rectangle
702     sal_Bool bTopBoundaryInserted = sal_False;
703     sal_Bool bTop2BoundaryInserted = sal_False;
704     sal_Bool bBottomBoundaryInserted = sal_False;
705 
706     // special case: top boundary is above the first band
707     ImplRegionBand* pNewBand;
708     if ( nTop < mpFirstBand->mnYTop )
709     {
710         // create new band above the first in the list
711         pNewBand = new ImplRegionBand( nTop, mpFirstBand->mnYTop );
712         if ( nBottom < mpFirstBand->mnYTop )
713             pNewBand->mnYBottom = nBottom;
714 
715         // insert band into the list
716         pNewBand->mpNextBand = mpFirstBand;
717         mpFirstBand = pNewBand;
718 
719         bTopBoundaryInserted = sal_True;
720     }
721 
722     // insert band(s) into the list
723     ImplRegionBand* pBand = mpFirstBand;
724     while ( pBand )
725     {
726         // Insert Bands if possible
727         if ( !bTopBoundaryInserted )
728             bTopBoundaryInserted = InsertSingleBand( pBand, nTop - 1 );
729 
730         if ( !bTop2BoundaryInserted )
731             bTop2BoundaryInserted = InsertSingleBand( pBand, nTop );
732 
733         if ( !bBottomBoundaryInserted && (nTop != nBottom) )
734             bBottomBoundaryInserted = InsertSingleBand( pBand, nBottom );
735 
736         // both boundaries inserted? -> nothing more to do
737         if ( bTopBoundaryInserted && bTop2BoundaryInserted && bBottomBoundaryInserted )
738             break;
739 
740         // insert bands between two bands if neccessary
741         if ( pBand->mpNextBand )
742         {
743             if ( (pBand->mnYBottom + 1) < pBand->mpNextBand->mnYTop )
744             {
745                 // copy band with list and set new boundary
746                 pNewBand = new ImplRegionBand( pBand->mnYBottom+1,
747                                                pBand->mpNextBand->mnYTop-1 );
748 
749                 // insert band into the list
750                 pNewBand->mpNextBand = pBand->mpNextBand;
751                 pBand->mpNextBand = pNewBand;
752             }
753         }
754 
755         pBand = pBand->mpNextBand;
756     }
757 }
758 
759 // -----------------------------------------------------------------------
760 //
761 // create new band and insert it into the list
762 
763 sal_Bool ImplRegion::InsertSingleBand( ImplRegionBand* pBand,
764                                    long nYBandPosition )
765 {
766     // boundary already included in band with height 1? -> nothing to do!
767     if ( (pBand->mnYTop == pBand->mnYBottom) &&
768          (nYBandPosition == pBand->mnYTop) )
769         return sal_True;
770 
771     // insert single height band on top?
772     ImplRegionBand* pNewBand;
773     if ( nYBandPosition == pBand->mnYTop )
774     {
775         // copy band with list and set new boundary
776         pNewBand = new ImplRegionBand( *pBand );
777         pNewBand->mnYTop = nYBandPosition+1;
778 
779         // insert band into the list
780         pNewBand->mpNextBand = pBand->mpNextBand;
781         pBand->mnYBottom = nYBandPosition;
782         pBand->mpNextBand = pNewBand;
783 
784         return sal_True;
785     }
786 
787     // top of new rectangle within the current band? -> insert new band and copy data
788     if ( (nYBandPosition > pBand->mnYTop) &&
789          (nYBandPosition < pBand->mnYBottom) )
790     {
791         // copy band with list and set new boundary
792         pNewBand = new ImplRegionBand( *pBand );
793         pNewBand->mnYTop = nYBandPosition;
794 
795         // insert band into the list
796         pNewBand->mpNextBand = pBand->mpNextBand;
797         pBand->mnYBottom = nYBandPosition;
798         pBand->mpNextBand = pNewBand;
799 
800         // copy band with list and set new boundary
801         pNewBand = new ImplRegionBand( *pBand );
802         pNewBand->mnYTop = nYBandPosition;
803 
804         // insert band into the list
805         pBand->mpNextBand->mnYTop = nYBandPosition+1;
806 
807         pNewBand->mpNextBand = pBand->mpNextBand;
808         pBand->mnYBottom = nYBandPosition - 1;
809         pBand->mpNextBand = pNewBand;
810 
811         return sal_True;
812     }
813 
814     // create new band behind the current in the list
815     if ( !pBand->mpNextBand )
816     {
817         if ( nYBandPosition == pBand->mnYBottom )
818         {
819             // copy band with list and set new boundary
820             pNewBand = new ImplRegionBand( *pBand );
821             pNewBand->mnYTop = pBand->mnYBottom;
822             pNewBand->mnYBottom = nYBandPosition;
823 
824             pBand->mnYBottom = nYBandPosition-1;
825 
826             // append band to the list
827             pBand->mpNextBand = pNewBand;
828             return sal_True;
829         }
830 
831         if ( nYBandPosition > pBand->mnYBottom )
832         {
833             // create new band
834             pNewBand = new ImplRegionBand( pBand->mnYBottom + 1, nYBandPosition );
835 
836             // append band to the list
837             pBand->mpNextBand = pNewBand;
838             return sal_True;
839         }
840     }
841 
842     return sal_False;
843 }
844 
845 // ------------------------------------------------------------------------
846 
847 void ImplRegion::InsertBand (ImplRegionBand* pPreviousBand, ImplRegionBand* pBandToInsert)
848 {
849     OSL_ASSERT(pBandToInsert!=NULL);
850 
851     if (pPreviousBand == NULL)
852     {
853         // Insert band before all others.
854         if (mpFirstBand != NULL)
855             mpFirstBand->mpPrevBand = pBandToInsert;
856         pBandToInsert->mpNextBand = mpFirstBand;
857         mpFirstBand = pBandToInsert;
858     }
859     else
860     {
861         // Insert band directly after pPreviousBand.
862         pBandToInsert->mpNextBand = pPreviousBand->mpNextBand;
863         pPreviousBand->mpNextBand = pBandToInsert;
864         pBandToInsert->mpPrevBand = pPreviousBand;
865     }
866 }
867 
868 // ------------------------------------------------------------------------
869 
870 void ImplRegion::Union( long nLeft, long nTop, long nRight, long nBottom )
871 {
872     DBG_ASSERT( nLeft <= nRight, "ImplRegion::Union() - nLeft > nRight" );
873     DBG_ASSERT( nTop <= nBottom, "ImplRegion::Union() - nTop > nBottom" );
874 
875     // process union
876     ImplRegionBand* pBand = mpFirstBand;
877     while ( pBand )
878     {
879         if ( pBand->mnYTop >= nTop )
880         {
881             if ( pBand->mnYBottom <= nBottom )
882                 pBand->Union( nLeft, nRight );
883             else
884             {
885 #ifdef DBG_UTIL
886                 long nCurY = pBand->mnYBottom;
887                 pBand = pBand->mpNextBand;
888                 while ( pBand )
889                 {
890                     if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) )
891                     {
892                         DBG_ERROR( "ImplRegion::Union() - Bands not sorted!" );
893                     }
894                     pBand = pBand->mpNextBand;
895                 }
896 #endif
897                 break;
898             }
899         }
900 
901         pBand = pBand->mpNextBand;
902     }
903 }
904 
905 // -----------------------------------------------------------------------
906 
907 void ImplRegion::Exclude( long nLeft, long nTop, long nRight, long nBottom )
908 {
909     DBG_ASSERT( nLeft <= nRight, "ImplRegion::Exclude() - nLeft > nRight" );
910     DBG_ASSERT( nTop <= nBottom, "ImplRegion::Exclude() - nTop > nBottom" );
911 
912     // process exclude
913     ImplRegionBand* pBand = mpFirstBand;
914     while ( pBand )
915     {
916         if ( pBand->mnYTop >= nTop )
917         {
918             if ( pBand->mnYBottom <= nBottom )
919                 pBand->Exclude( nLeft, nRight );
920             else
921             {
922 #ifdef DBG_UTIL
923                 long nCurY = pBand->mnYBottom;
924                 pBand = pBand->mpNextBand;
925                 while ( pBand )
926                 {
927                     if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) )
928                     {
929                         DBG_ERROR( "ImplRegion::Exclude() - Bands not sorted!" );
930                     }
931                     pBand = pBand->mpNextBand;
932                 }
933 #endif
934                 break;
935             }
936         }
937 
938         pBand = pBand->mpNextBand;
939     }
940 }
941 
942 // -----------------------------------------------------------------------
943 
944 void ImplRegion::XOr( long nLeft, long nTop, long nRight, long nBottom )
945 {
946     DBG_ASSERT( nLeft <= nRight, "ImplRegion::Exclude() - nLeft > nRight" );
947     DBG_ASSERT( nTop <= nBottom, "ImplRegion::Exclude() - nTop > nBottom" );
948 
949     // process xor
950     ImplRegionBand* pBand = mpFirstBand;
951     while ( pBand )
952     {
953         if ( pBand->mnYTop >= nTop )
954         {
955             if ( pBand->mnYBottom <= nBottom )
956                 pBand->XOr( nLeft, nRight );
957             else
958             {
959 #ifdef DBG_UTIL
960                 long nCurY = pBand->mnYBottom;
961                 pBand = pBand->mpNextBand;
962                 while ( pBand )
963                 {
964                     if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) )
965                     {
966                         DBG_ERROR( "ImplRegion::XOr() - Bands not sorted!" );
967                     }
968                     pBand = pBand->mpNextBand;
969                 }
970 #endif
971                 break;
972             }
973         }
974 
975         pBand = pBand->mpNextBand;
976     }
977 }
978 
979 // -----------------------------------------------------------------------
980 //
981 // remove empty bands
982 
983 sal_Bool ImplRegion::OptimizeBandList()
984 {
985     DBG_ASSERT( (this != &aImplNullRegion) && (this != &aImplEmptyRegion),
986                 "ImplRegion::OptimizeBandList() - Empty oder NULL-Region" );
987 
988     mnRectCount = 0;
989 
990     ImplRegionBand* pPrevBand = 0;
991     ImplRegionBand* pBand = mpFirstBand;
992     while ( pBand )
993     {
994         const sal_Bool bBTEqual = pBand->mpNextBand &&
995                               (pBand->mnYBottom == pBand->mpNextBand->mnYTop);
996 
997         // no separation? -> remove!
998         if ( pBand->IsEmpty() || (bBTEqual && (pBand->mnYBottom == pBand->mnYTop)) )
999         {
1000             // save pointer
1001             ImplRegionBand* pOldBand = pBand;
1002 
1003             // previous element of the list
1004             if ( pBand == mpFirstBand )
1005                 mpFirstBand = pBand->mpNextBand;
1006             else
1007                 pPrevBand->mpNextBand = pBand->mpNextBand;
1008 
1009             pBand = pBand->mpNextBand;
1010             delete pOldBand;
1011         }
1012         else
1013         {
1014             // fixup
1015             if ( bBTEqual )
1016                 pBand->mnYBottom = pBand->mpNextBand->mnYTop-1;
1017 
1018             // this and next band with equal separations? -> combine!
1019             if ( pBand->mpNextBand &&
1020                  ((pBand->mnYBottom+1) == pBand->mpNextBand->mnYTop) &&
1021                  (*pBand == *pBand->mpNextBand) )
1022             {
1023                 // expand current height
1024                 pBand->mnYBottom = pBand->mpNextBand->mnYBottom;
1025 
1026                 // remove next band from list
1027                 ImplRegionBand* pDeletedBand = pBand->mpNextBand;
1028                 pBand->mpNextBand = pDeletedBand->mpNextBand;
1029                 delete pDeletedBand;
1030 
1031                 // check band again!
1032             }
1033             else
1034             {
1035                 // count rectangles within band
1036                 ImplRegionBandSep* pSep = pBand->mpFirstSep;
1037                 while ( pSep )
1038                 {
1039                     mnRectCount++;
1040                     pSep = pSep->mpNextSep;
1041                 }
1042 
1043                 pPrevBand = pBand;
1044                 pBand = pBand->mpNextBand;
1045             }
1046         }
1047     }
1048 
1049 #ifdef DBG_UTIL
1050     pBand = mpFirstBand;
1051     while ( pBand )
1052     {
1053         DBG_ASSERT( pBand->mpFirstSep != NULL,
1054                     "Exiting ImplRegion::OptimizeBandList(): empty band in region!" );
1055 
1056         if ( pBand->mnYBottom < pBand->mnYTop )
1057             DBG_ERROR( "ImplRegion::OptimizeBandList(): YBottomBoundary < YTopBoundary" );
1058 
1059         if ( pBand->mpNextBand )
1060         {
1061             if ( pBand->mnYBottom >= pBand->mpNextBand->mnYTop )
1062                 DBG_ERROR( "ImplRegion::OptimizeBandList(): overlapping bands in region!" );
1063         }
1064 
1065         pBand = pBand->mpNextBand;
1066     }
1067 #endif
1068 
1069     return (mnRectCount != 0);
1070 }
1071 
1072 // =======================================================================
1073 
1074 void Region::ImplCopyData()
1075 {
1076     mpImplRegion->mnRefCount--;
1077     mpImplRegion = new ImplRegion( *mpImplRegion );
1078 }
1079 
1080 // =======================================================================
1081 
1082 Region::Region()
1083 {
1084     DBG_CTOR( Region, ImplDbgTestRegion );
1085 
1086     mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1087 }
1088 
1089 // -----------------------------------------------------------------------
1090 
1091 Region::Region( RegionType eType )
1092 {
1093     DBG_CTOR( Region, ImplDbgTestRegion );
1094     DBG_ASSERT( (eType == REGION_NULL) || (eType == REGION_EMPTY),
1095                 "Region( RegionType ) - RegionType != EMPTY/NULL" );
1096 
1097     if ( eType == REGION_NULL )
1098         mpImplRegion = (ImplRegion*)(&aImplNullRegion);
1099     else
1100         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1101 }
1102 
1103 // -----------------------------------------------------------------------
1104 
1105 Region::Region( const Rectangle& rRect )
1106 {
1107     DBG_CTOR( Region, ImplDbgTestRegion );
1108 
1109     ImplCreateRectRegion( rRect );
1110 }
1111 
1112 // -----------------------------------------------------------------------
1113 
1114 Region::Region( const Polygon& rPolygon )
1115 {
1116     DBG_CTOR( Region, ImplDbgTestRegion );
1117     DBG_CHKOBJ( &rPolygon, Polygon, NULL );
1118 
1119     ImplCreatePolyPolyRegion( rPolygon );
1120 }
1121 
1122 // -----------------------------------------------------------------------
1123 
1124 Region::Region( const PolyPolygon& rPolyPoly )
1125 {
1126     DBG_CTOR( Region, ImplDbgTestRegion );
1127     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
1128 
1129     ImplCreatePolyPolyRegion( rPolyPoly );
1130 }
1131 
1132 // -----------------------------------------------------------------------
1133 
1134 Region::Region( const basegfx::B2DPolyPolygon& rPolyPoly )
1135 {
1136     DBG_CTOR( Region, ImplDbgTestRegion );
1137     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
1138 
1139     mpImplRegion = new ImplRegion( rPolyPoly );
1140 }
1141 
1142 // -----------------------------------------------------------------------
1143 
1144 Region::Region( const Region& rRegion )
1145 {
1146     DBG_CTOR( Region, ImplDbgTestRegion );
1147     DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
1148     DBG_ASSERT( rRegion.mpImplRegion->mnRefCount < 0xFFFFFFFE, "Region: RefCount overflow" );
1149 
1150     // copy pointer to instance of implementation
1151     mpImplRegion = rRegion.mpImplRegion;
1152     if ( mpImplRegion->mnRefCount )
1153         mpImplRegion->mnRefCount++;
1154 }
1155 
1156 // -----------------------------------------------------------------------
1157 
1158 Region::~Region()
1159 {
1160     DBG_DTOR( Region, ImplDbgTestRegion );
1161 
1162     // statische Object haben RefCount von 0
1163     if ( mpImplRegion->mnRefCount )
1164     {
1165         if ( mpImplRegion->mnRefCount > 1 )
1166             mpImplRegion->mnRefCount--;
1167         else
1168             delete mpImplRegion;
1169     }
1170 }
1171 
1172 // -----------------------------------------------------------------------
1173 
1174 void Region::ImplCreateRectRegion( const Rectangle& rRect )
1175 {
1176     if ( rRect.IsEmpty() )
1177         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1178     else
1179     {
1180         // get justified rectangle
1181         long nTop       = Min( rRect.Top(), rRect.Bottom() );
1182         long nBottom    = Max( rRect.Top(), rRect.Bottom() );
1183         long nLeft      = Min( rRect.Left(), rRect.Right() );
1184         long nRight     = Max( rRect.Left(), rRect.Right() );
1185 
1186         // create instance of implementation class
1187         mpImplRegion = new ImplRegion();
1188 
1189         // add band with boundaries of the rectangle
1190         mpImplRegion->mpFirstBand = new ImplRegionBand( nTop, nBottom );
1191 
1192         // Set left and right boundaries of the band
1193         mpImplRegion->mpFirstBand->Union( nLeft, nRight );
1194         mpImplRegion->mnRectCount = 1;
1195     }
1196 }
1197 
1198 // -----------------------------------------------------------------------
1199 
1200 void Region::ImplCreatePolyPolyRegion( const PolyPolygon& rPolyPoly )
1201 {
1202     const sal_uInt16 nPolyCount = rPolyPoly.Count();
1203     if ( nPolyCount )
1204     {
1205         // polypolygon empty? -> empty region
1206         const Rectangle aRect( rPolyPoly.GetBoundRect() );
1207 
1208         if ( !aRect.IsEmpty() )
1209         {
1210             // width OR height == 1 ? => Rectangular region
1211             if ( (aRect.GetWidth() == 1)
1212                 || (aRect.GetHeight() == 1)
1213                 || rPolyPoly.IsRect() )
1214             {
1215                 ImplCreateRectRegion( aRect );
1216             }
1217             else
1218                 mpImplRegion = new ImplRegion( rPolyPoly );
1219         }
1220         else
1221             mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1222     }
1223     else
1224         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1225 }
1226 
1227 // -----------------------------------------------------------------------
1228 
1229 void Region::ImplPolyPolyRegionToBandRegionFunc()
1230 {
1231     // ensure to subdivide when bezier segemnts are used, it's going to
1232     // be expanded to rectangles
1233     PolyPolygon aPolyPoly;
1234     GetPolyPolygon().AdaptiveSubdivide(aPolyPoly);
1235 
1236     if ( mpImplRegion->mnRefCount > 1 )
1237         mpImplRegion->mnRefCount--;
1238     else
1239         delete mpImplRegion;
1240 
1241     if ( aPolyPoly.Count() )
1242     {
1243         // polypolygon empty? -> empty region
1244         const Rectangle aRect( aPolyPoly.GetBoundRect() );
1245 
1246         if ( !aRect.IsEmpty() )
1247         {
1248             if (ImplIsPolygonRectilinear(aPolyPoly))
1249             {
1250                 // For rectilinear polygons there is an optimized band conversion.
1251                 mpImplRegion = ImplRectilinearPolygonToBands(aPolyPoly);
1252             }
1253             else
1254             {
1255                 mpImplRegion = ImplGeneralPolygonToBands(aPolyPoly, aRect);
1256             }
1257 
1258             // Convert points into seps.
1259             ImplRegionBand* pRegionBand = mpImplRegion->mpFirstBand;
1260             while ( pRegionBand )
1261             {
1262                 // generate separations from the lines and process union
1263                 pRegionBand->ProcessPoints();
1264                 pRegionBand = pRegionBand->mpNextBand;
1265             }
1266 
1267             // Optimize list of bands.  Adjacent bands with identical lists
1268             // of seps are joined.
1269             if ( !mpImplRegion->OptimizeBandList() )
1270             {
1271                 delete mpImplRegion;
1272                 mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1273             }
1274         }
1275         else
1276             mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1277     }
1278     else
1279         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1280 }
1281 
1282 // -----------------------------------------------------------------------
1283 
1284 void Region::Move( long nHorzMove, long nVertMove )
1285 {
1286     DBG_CHKTHIS( Region, ImplDbgTestRegion );
1287 
1288     // no region data? -> nothing to do
1289     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
1290         return;
1291 
1292     // no own instance data? -> make own copy!
1293     if ( mpImplRegion->mnRefCount > 1 )
1294         ImplCopyData();
1295 
1296     if ( mpImplRegion->mpPolyPoly )
1297         mpImplRegion->mpPolyPoly->Move( nHorzMove, nVertMove );
1298     else if( mpImplRegion->mpB2DPolyPoly )
1299     {
1300         mpImplRegion->mpB2DPolyPoly->transform(basegfx::tools::createTranslateB2DHomMatrix(nHorzMove, nVertMove));
1301     }
1302     else
1303     {
1304         ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
1305         while ( pBand )
1306         {
1307             // process the vertical move
1308             if ( nVertMove != 0)
1309             {
1310                 pBand->mnYTop = pBand->mnYTop + nVertMove;
1311                 pBand->mnYBottom = pBand->mnYBottom + nVertMove;
1312             }
1313 
1314             // process the horizontal move
1315             if ( nHorzMove != 0)
1316                 pBand->MoveX( nHorzMove );
1317 
1318             pBand = pBand->mpNextBand;
1319         }
1320     }
1321 }
1322 
1323 // -----------------------------------------------------------------------
1324 
1325 void Region::Scale( double fScaleX, double fScaleY )
1326 {
1327     DBG_CHKTHIS( Region, ImplDbgTestRegion );
1328 
1329     // no region data? -> nothing to do
1330     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
1331         return;
1332 
1333     // no own instance data? -> make own copy!
1334     if ( mpImplRegion->mnRefCount > 1 )
1335         ImplCopyData();
1336 
1337     if ( mpImplRegion->mpPolyPoly )
1338         mpImplRegion->mpPolyPoly->Scale( fScaleX, fScaleY );
1339     else if( mpImplRegion->mpB2DPolyPoly )
1340     {
1341         mpImplRegion->mpB2DPolyPoly->transform(basegfx::tools::createScaleB2DHomMatrix(fScaleX, fScaleY));
1342     }
1343     else
1344     {
1345         ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
1346         while ( pBand )
1347         {
1348             // process the vertical move
1349             if ( fScaleY != 0.0 )
1350             {
1351                 pBand->mnYTop = FRound( pBand->mnYTop * fScaleY );
1352                 pBand->mnYBottom = FRound( pBand->mnYBottom * fScaleY );
1353             }
1354 
1355             // process the horizontal move
1356             if ( fScaleX != 0.0 )
1357                 pBand->ScaleX( fScaleX );
1358 
1359             pBand = pBand->mpNextBand;
1360         }
1361     }
1362 }
1363 
1364 // -----------------------------------------------------------------------
1365 
1366 sal_Bool Region::Union( const Rectangle& rRect )
1367 {
1368     DBG_CHKTHIS( Region, ImplDbgTestRegion );
1369 
1370     // is rectangle empty? -> nothing to do
1371     if ( rRect.IsEmpty() )
1372         return sal_True;
1373 
1374     if( HasPolyPolygon() )
1375     {
1376         // get this B2DPolyPolygon
1377         basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
1378         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
1379 
1380         if( aThisPolyPoly.count() == 0 )
1381         {
1382             *this = rRect;
1383             return true;
1384         }
1385 
1386         // get the other B2DPolyPolygon
1387         basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) );
1388         basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly );
1389 
1390         basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationOr( aThisPolyPoly, aOtherPolyPoly );
1391         *this = Region( aClip );
1392 
1393         return sal_True;
1394     }
1395 
1396     ImplPolyPolyRegionToBandRegion();
1397 
1398     // no instance data? -> create!
1399     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
1400         mpImplRegion = new ImplRegion();
1401 
1402     // no own instance data? -> make own copy!
1403     if ( mpImplRegion->mnRefCount > 1 )
1404         ImplCopyData();
1405 
1406     // get justified rectangle
1407     long nLeft      = Min( rRect.Left(), rRect.Right() );
1408     long nTop       = Min( rRect.Top(), rRect.Bottom() );
1409     long nRight     = Max( rRect.Left(), rRect.Right() );
1410     long nBottom    = Max( rRect.Top(), rRect.Bottom() );
1411 
1412     // insert bands if the boundaries are not allready in the list
1413     mpImplRegion->InsertBands( nTop, nBottom );
1414 
1415     // process union
1416     mpImplRegion->Union( nLeft, nTop, nRight, nBottom );
1417 
1418     // cleanup
1419     if ( !mpImplRegion->OptimizeBandList() )
1420     {
1421         delete mpImplRegion;
1422         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1423     }
1424 
1425     return sal_True;
1426 }
1427 
1428 // -----------------------------------------------------------------------
1429 
1430 sal_Bool Region::Intersect( const Rectangle& rRect )
1431 {
1432     DBG_CHKTHIS( Region, ImplDbgTestRegion );
1433 
1434     // is rectangle empty? -> nothing to do
1435     if ( rRect.IsEmpty() )
1436     {
1437         // statische Object haben RefCount von 0
1438         if ( mpImplRegion->mnRefCount )
1439         {
1440             if ( mpImplRegion->mnRefCount > 1 )
1441                 mpImplRegion->mnRefCount--;
1442             else
1443                 delete mpImplRegion;
1444         }
1445         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1446         return sal_True;
1447     }
1448 
1449     // #103137# Avoid banding for special cases
1450     if ( mpImplRegion->mpPolyPoly )
1451     {
1452         // #127431# make ImplRegion unique, if not already.
1453         if( mpImplRegion->mnRefCount > 1 )
1454         {
1455             mpImplRegion->mnRefCount--;
1456             mpImplRegion = new ImplRegion( *mpImplRegion->mpPolyPoly );
1457         }
1458 
1459         // use the PolyPolygon::Clip method for rectangles, this is
1460         // fairly simple (does not even use GPC) and saves us from
1461         // unnecessary banding
1462         mpImplRegion->mpPolyPoly->Clip( rRect );
1463 
1464         // The clipping above may lead to empty ClipRegion
1465         if(!mpImplRegion->mpPolyPoly->Count())
1466         {
1467             // react on empty ClipRegion; ImplRegion already is unique (see above)
1468             delete mpImplRegion;
1469             mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1470         }
1471 
1472         return sal_True;
1473     }
1474     else if( mpImplRegion->mpB2DPolyPoly )
1475     {
1476         // #127431# make ImplRegion unique, if not already.
1477         if( mpImplRegion->mnRefCount > 1 )
1478         {
1479             mpImplRegion->mnRefCount--;
1480             mpImplRegion = new ImplRegion( *mpImplRegion->mpB2DPolyPoly );
1481         }
1482 
1483         *mpImplRegion->mpB2DPolyPoly =
1484             basegfx::tools::clipPolyPolygonOnRange(
1485                 *mpImplRegion->mpB2DPolyPoly,
1486                 basegfx::B2DRange(
1487                     rRect.Left(),
1488                     rRect.Top(),
1489                     rRect.Right() + 1,
1490                     rRect.Bottom() + 1),
1491                 true,
1492                 false);
1493 
1494         // The clipping above may lead to empty ClipRegion
1495         if(!mpImplRegion->mpB2DPolyPoly->count())
1496         {
1497             // react on empty ClipRegion; ImplRegion already is unique (see above)
1498             delete mpImplRegion;
1499             mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1500         }
1501 
1502         return sal_True;
1503     }
1504     else
1505         ImplPolyPolyRegionToBandRegion();
1506 
1507     // is region empty? -> nothing to do!
1508     if ( mpImplRegion == &aImplEmptyRegion )
1509         return sal_True;
1510 
1511     // get justified rectangle
1512     long nLeft      = Min( rRect.Left(), rRect.Right() );
1513     long nTop       = Min( rRect.Top(), rRect.Bottom() );
1514     long nRight     = Max( rRect.Left(), rRect.Right() );
1515     long nBottom    = Max( rRect.Top(), rRect.Bottom() );
1516 
1517     // is own region NULL-region? -> copy data!
1518     if ( mpImplRegion == &aImplNullRegion )
1519     {
1520         // create instance of implementation class
1521         mpImplRegion = new ImplRegion();
1522 
1523         // add band with boundaries of the rectangle
1524         mpImplRegion->mpFirstBand = new ImplRegionBand( nTop, nBottom );
1525 
1526         // Set left and right boundaries of the band
1527         mpImplRegion->mpFirstBand->Union( nLeft, nRight );
1528         mpImplRegion->mnRectCount = 1;
1529 
1530         return sal_True;
1531     }
1532 
1533     // no own instance data? -> make own copy!
1534     if ( mpImplRegion->mnRefCount > 1 )
1535         ImplCopyData();
1536 
1537     // insert bands if the boundaries are not allready in the list
1538     mpImplRegion->InsertBands( nTop, nBottom );
1539 
1540     // process intersections
1541     ImplRegionBand* pPrevBand = 0;
1542     ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
1543     while ( pBand )
1544     {
1545         // band within intersection boundary? -> process. otherwise remove
1546         if ( (pBand->mnYTop >= nTop) &&
1547              (pBand->mnYBottom <= nBottom) )
1548         {
1549             // process intersection
1550             pBand->Intersect( nLeft, nRight );
1551 
1552             pPrevBand = pBand;
1553             pBand = pBand->mpNextBand;
1554         }
1555         else
1556         {
1557             ImplRegionBand* pOldBand = pBand;
1558             if ( pBand == mpImplRegion->mpFirstBand )
1559                 mpImplRegion->mpFirstBand = pBand->mpNextBand;
1560             else
1561                 pPrevBand->mpNextBand = pBand->mpNextBand;
1562             pBand = pBand->mpNextBand;
1563             delete pOldBand;
1564         }
1565     }
1566 
1567     // cleanup
1568     if ( !mpImplRegion->OptimizeBandList() )
1569     {
1570         delete mpImplRegion;
1571         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1572     }
1573 
1574     return sal_True;
1575 }
1576 
1577 // -----------------------------------------------------------------------
1578 
1579 sal_Bool Region::Exclude( const Rectangle& rRect )
1580 {
1581     DBG_CHKTHIS( Region, ImplDbgTestRegion );
1582 
1583     // is rectangle empty? -> nothing to do
1584     if ( rRect.IsEmpty() )
1585         return sal_True;
1586 
1587     if( HasPolyPolygon() )
1588     {
1589         // get this B2DPolyPolygon
1590         basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
1591         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
1592 
1593         if( aThisPolyPoly.count() == 0 )
1594             return sal_True;
1595 
1596         // get the other B2DPolyPolygon
1597         basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) );
1598         basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly );
1599 
1600         basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly );
1601         *this = Region( aClip );
1602 
1603         return sal_True;
1604     }
1605 
1606     ImplPolyPolyRegionToBandRegion();
1607 
1608     // no instance data? -> create!
1609     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
1610         return sal_True;
1611 
1612     // no own instance data? -> make own copy!
1613     if ( mpImplRegion->mnRefCount > 1 )
1614         ImplCopyData();
1615 
1616     // get justified rectangle
1617     long nLeft      = Min( rRect.Left(), rRect.Right() );
1618     long nTop       = Min( rRect.Top(), rRect.Bottom() );
1619     long nRight     = Max( rRect.Left(), rRect.Right() );
1620     long nBottom    = Max( rRect.Top(), rRect.Bottom() );
1621 
1622     // insert bands if the boundaries are not allready in the list
1623     mpImplRegion->InsertBands( nTop, nBottom );
1624 
1625     // process exclude
1626     mpImplRegion->Exclude( nLeft, nTop, nRight, nBottom );
1627 
1628     // cleanup
1629     if ( !mpImplRegion->OptimizeBandList() )
1630     {
1631         delete mpImplRegion;
1632         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1633     }
1634 
1635     return sal_True;
1636 }
1637 
1638 // -----------------------------------------------------------------------
1639 
1640 sal_Bool Region::XOr( const Rectangle& rRect )
1641 {
1642     DBG_CHKTHIS( Region, ImplDbgTestRegion );
1643 
1644     // is rectangle empty? -> nothing to do
1645     if ( rRect.IsEmpty() )
1646         return sal_True;
1647 
1648     if( HasPolyPolygon() )
1649     {
1650         // get this B2DPolyPolygon
1651         basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
1652         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
1653 
1654         if( aThisPolyPoly.count() == 0 )
1655         {
1656             *this = rRect;
1657             return sal_True;
1658         }
1659 
1660         // get the other B2DPolyPolygon
1661         basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) );
1662         basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly );
1663 
1664         basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly );
1665         *this = Region( aClip );
1666 
1667         return sal_True;
1668     }
1669 
1670     ImplPolyPolyRegionToBandRegion();
1671 
1672     // no instance data? -> create!
1673     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
1674         mpImplRegion = new ImplRegion();
1675 
1676     // no own instance data? -> make own copy!
1677     if ( mpImplRegion->mnRefCount > 1 )
1678         ImplCopyData();
1679 
1680     // get justified rectangle
1681     long nLeft      = Min( rRect.Left(), rRect.Right() );
1682     long nTop       = Min( rRect.Top(), rRect.Bottom() );
1683     long nRight     = Max( rRect.Left(), rRect.Right() );
1684     long nBottom    = Max( rRect.Top(), rRect.Bottom() );
1685 
1686     // insert bands if the boundaries are not allready in the list
1687     mpImplRegion->InsertBands( nTop, nBottom );
1688 
1689     // process xor
1690     mpImplRegion->XOr( nLeft, nTop, nRight, nBottom );
1691 
1692     // cleanup
1693     if ( !mpImplRegion->OptimizeBandList() )
1694     {
1695         delete mpImplRegion;
1696         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1697     }
1698 
1699     return sal_True;
1700 }
1701 
1702 // -----------------------------------------------------------------------
1703 void Region::ImplUnionPolyPolygon( const Region& i_rRegion )
1704 {
1705     // get this B2DPolyPolygon
1706     basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
1707     aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
1708 
1709     if( aThisPolyPoly.count() == 0 )
1710     {
1711         *this = i_rRegion;
1712         return;
1713     }
1714 
1715     // get the other B2DPolyPolygon
1716     basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() );
1717     aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
1718 
1719 
1720     basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationOr( aThisPolyPoly, aOtherPolyPoly );
1721 
1722     *this = Region( aClip );
1723 }
1724 
1725 sal_Bool Region::Union( const Region& rRegion )
1726 {
1727     DBG_CHKTHIS( Region, ImplDbgTestRegion );
1728 
1729     if( rRegion.HasPolyPolygon() || HasPolyPolygon() )
1730     {
1731         ImplUnionPolyPolygon( rRegion );
1732         return sal_True;
1733     }
1734 
1735     ImplPolyPolyRegionToBandRegion();
1736     ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();
1737 
1738     // is region empty or null? -> nothing to do
1739     if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
1740         return sal_True;
1741 
1742     // no instance data? -> create!
1743     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
1744         mpImplRegion = new ImplRegion();
1745 
1746     // no own instance data? -> make own copy!
1747     if ( mpImplRegion->mnRefCount > 1 )
1748         ImplCopyData();
1749 
1750     // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
1751     ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand;
1752     while ( pBand )
1753     {
1754         // insert bands if the boundaries are not allready in the list
1755         mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );
1756 
1757         // process all elements of the list
1758         ImplRegionBandSep* pSep = pBand->mpFirstSep;
1759         while ( pSep )
1760         {
1761             mpImplRegion->Union( pSep->mnXLeft, pBand->mnYTop,
1762                                  pSep->mnXRight, pBand->mnYBottom );
1763             pSep = pSep->mpNextSep;
1764         }
1765 
1766         pBand = pBand->mpNextBand;
1767     }
1768 
1769     // cleanup
1770     if ( !mpImplRegion->OptimizeBandList() )
1771     {
1772         delete mpImplRegion;
1773         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1774     }
1775 
1776     return sal_True;
1777 }
1778 
1779 // -----------------------------------------------------------------------
1780 void Region::ImplIntersectWithPolyPolygon( const Region& i_rRegion )
1781 {
1782     // get this B2DPolyPolygon
1783     basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
1784     if( aThisPolyPoly.count() == 0 )
1785     {
1786         *this = i_rRegion;
1787         return;
1788     }
1789 
1790     // get the other B2DPolyPolygon
1791     basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() );
1792 
1793     basegfx::B2DPolyPolygon aClip = basegfx::tools::clipPolyPolygonOnPolyPolygon( aOtherPolyPoly, aThisPolyPoly, true, false );
1794     *this = Region( aClip );
1795 }
1796 
1797 sal_Bool Region::Intersect( const Region& rRegion )
1798 {
1799     DBG_CHKTHIS( Region, ImplDbgTestRegion );
1800 
1801     // same instance data? -> nothing to do!
1802     if ( mpImplRegion == rRegion.mpImplRegion )
1803         return sal_True;
1804 
1805     if( rRegion.HasPolyPolygon() || HasPolyPolygon() )
1806     {
1807         ImplIntersectWithPolyPolygon( rRegion );
1808         return sal_True;
1809     }
1810 
1811     ImplPolyPolyRegionToBandRegion();
1812     ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();
1813 
1814     if ( mpImplRegion == &aImplEmptyRegion )
1815         return sal_True;
1816 
1817     // is region null? -> nothing to do
1818     if ( rRegion.mpImplRegion == &aImplNullRegion )
1819         return sal_True;
1820 
1821     // is rectangle empty? -> nothing to do
1822     if ( rRegion.mpImplRegion == &aImplEmptyRegion )
1823     {
1824         // statische Object haben RefCount von 0
1825         if ( mpImplRegion->mnRefCount )
1826         {
1827             if ( mpImplRegion->mnRefCount > 1 )
1828                 mpImplRegion->mnRefCount--;
1829             else
1830                 delete mpImplRegion;
1831         }
1832         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1833         return sal_True;
1834     }
1835 
1836     // is own region NULL-region? -> copy data!
1837     if ( mpImplRegion == &aImplNullRegion)
1838     {
1839         mpImplRegion = rRegion.mpImplRegion;
1840         rRegion.mpImplRegion->mnRefCount++;
1841         return sal_True;
1842     }
1843 
1844     // Wenn wir weniger Rechtecke haben, drehen wir den Intersect-Aufruf um
1845     if ( mpImplRegion->mnRectCount+2 < rRegion.mpImplRegion->mnRectCount )
1846     {
1847         Region aTempRegion = rRegion;
1848         aTempRegion.Intersect( *this );
1849         *this = aTempRegion;
1850     }
1851     else
1852     {
1853         // no own instance data? -> make own copy!
1854         if ( mpImplRegion->mnRefCount > 1 )
1855             ImplCopyData();
1856 
1857         // mark all bands as untouched
1858         ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
1859         while ( pBand )
1860         {
1861             pBand->mbTouched = sal_False;
1862             pBand = pBand->mpNextBand;
1863         }
1864 
1865         pBand = rRegion.mpImplRegion->mpFirstBand;
1866         while ( pBand )
1867         {
1868             // insert bands if the boundaries are not allready in the list
1869             mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );
1870 
1871             // process all elements of the list
1872             ImplRegionBandSep* pSep = pBand->mpFirstSep;
1873             while ( pSep )
1874             {
1875                 // left boundary?
1876                 if ( pSep == pBand->mpFirstSep )
1877                 {
1878                     // process intersection and do not remove untouched bands
1879                     mpImplRegion->Exclude( LONG_MIN+1, pBand->mnYTop,
1880                                            pSep->mnXLeft-1, pBand->mnYBottom );
1881                 }
1882 
1883                 // right boundary?
1884                 if ( pSep->mpNextSep == NULL )
1885                 {
1886                     // process intersection and do not remove untouched bands
1887                     mpImplRegion->Exclude( pSep->mnXRight+1, pBand->mnYTop,
1888                                            LONG_MAX-1, pBand->mnYBottom );
1889                 }
1890                 else
1891                 {
1892                     // process intersection and do not remove untouched bands
1893                     mpImplRegion->Exclude( pSep->mnXRight+1, pBand->mnYTop,
1894                                            pSep->mpNextSep->mnXLeft-1, pBand->mnYBottom );
1895                 }
1896 
1897                 pSep = pSep->mpNextSep;
1898             }
1899 
1900             pBand = pBand->mpNextBand;
1901         }
1902 
1903         // remove all untouched bands if bands allready left
1904         ImplRegionBand* pPrevBand = 0;
1905         pBand = mpImplRegion->mpFirstBand;
1906         while ( pBand )
1907         {
1908             if ( !pBand->mbTouched )
1909             {
1910                 // save pointer
1911                 ImplRegionBand* pOldBand = pBand;
1912 
1913                 // previous element of the list
1914                 if ( pBand == mpImplRegion->mpFirstBand )
1915                     mpImplRegion->mpFirstBand = pBand->mpNextBand;
1916                 else
1917                     pPrevBand->mpNextBand = pBand->mpNextBand;
1918 
1919                 pBand = pBand->mpNextBand;
1920                 delete pOldBand;
1921             }
1922             else
1923             {
1924                 pPrevBand = pBand;
1925                 pBand = pBand->mpNextBand;
1926             }
1927         }
1928 
1929         // cleanup
1930         if ( !mpImplRegion->OptimizeBandList() )
1931         {
1932             delete mpImplRegion;
1933             mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
1934         }
1935     }
1936 
1937     return sal_True;
1938 }
1939 
1940 // -----------------------------------------------------------------------
1941 void Region::ImplExcludePolyPolygon( const Region& i_rRegion )
1942 {
1943     // get this B2DPolyPolygon
1944     basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
1945     if( aThisPolyPoly.count() == 0 )
1946         return;
1947     aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
1948 
1949     // get the other B2DPolyPolygon
1950     basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() );
1951     aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
1952 
1953     basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly );
1954     *this = Region( aClip );
1955 }
1956 
1957 sal_Bool Region::Exclude( const Region& rRegion )
1958 {
1959     DBG_CHKTHIS( Region, ImplDbgTestRegion );
1960 
1961     if( rRegion.HasPolyPolygon() || HasPolyPolygon() )
1962     {
1963         ImplExcludePolyPolygon( rRegion );
1964         return sal_True;
1965     }
1966 
1967     ImplPolyPolyRegionToBandRegion();
1968     ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();
1969 
1970     // is region empty or null? -> nothing to do
1971     if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
1972         return sal_True;
1973 
1974     // no instance data? -> nothing to do
1975     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
1976         return sal_True;
1977 
1978     // no own instance data? -> make own copy!
1979     if ( mpImplRegion->mnRefCount > 1 )
1980         ImplCopyData();
1981 
1982     // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
1983     ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand;
1984     while ( pBand )
1985     {
1986         // insert bands if the boundaries are not allready in the list
1987         mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );
1988 
1989         // process all elements of the list
1990         ImplRegionBandSep* pSep = pBand->mpFirstSep;
1991         while ( pSep )
1992         {
1993             mpImplRegion->Exclude( pSep->mnXLeft, pBand->mnYTop,
1994                                    pSep->mnXRight, pBand->mnYBottom );
1995             pSep = pSep->mpNextSep;
1996         }
1997 
1998         // Wir optimieren schon in der Schleife, da wir davon
1999         // ausgehen, das wir insgesammt weniger Baender ueberpruefen
2000         // muessen
2001         if ( !mpImplRegion->OptimizeBandList() )
2002         {
2003             delete mpImplRegion;
2004             mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
2005             break;
2006         }
2007 
2008         pBand = pBand->mpNextBand;
2009     }
2010 
2011     return sal_True;
2012 }
2013 
2014 // -----------------------------------------------------------------------
2015 void Region::ImplXOrPolyPolygon( const Region& i_rRegion )
2016 {
2017     // get this B2DPolyPolygon
2018     basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
2019     if( aThisPolyPoly.count() == 0 )
2020     {
2021         *this = i_rRegion;
2022         return;
2023     }
2024     aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
2025 
2026     // get the other B2DPolyPolygon
2027     basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() );
2028     aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
2029 
2030     basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly );
2031     *this = Region( aClip );
2032 }
2033 
2034 sal_Bool Region::XOr( const Region& rRegion )
2035 {
2036     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2037 
2038     if( rRegion.HasPolyPolygon() || HasPolyPolygon() )
2039     {
2040         ImplXOrPolyPolygon( rRegion );
2041         return sal_True;
2042     }
2043 
2044     ImplPolyPolyRegionToBandRegion();
2045     ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();
2046 
2047     // is region empty or null? -> nothing to do
2048     if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
2049         return sal_True;
2050 
2051     // no own instance data? -> XOr = copy
2052     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
2053     {
2054         *this = rRegion;
2055         return sal_True;
2056     }
2057 
2058     // no own instance data? -> make own copy!
2059     if ( mpImplRegion->mnRefCount > 1 )
2060         ImplCopyData();
2061 
2062     // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
2063     ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand;
2064     while ( pBand )
2065     {
2066         // insert bands if the boundaries are not allready in the list
2067         mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );
2068 
2069         // process all elements of the list
2070         ImplRegionBandSep* pSep = pBand->mpFirstSep;
2071         while ( pSep )
2072         {
2073             mpImplRegion->XOr( pSep->mnXLeft, pBand->mnYTop,
2074                                pSep->mnXRight, pBand->mnYBottom );
2075             pSep = pSep->mpNextSep;
2076         }
2077 
2078         pBand = pBand->mpNextBand;
2079     }
2080 
2081     // cleanup
2082     if ( !mpImplRegion->OptimizeBandList() )
2083     {
2084         delete mpImplRegion;
2085         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
2086     }
2087 
2088     return sal_True;
2089 }
2090 
2091 // -----------------------------------------------------------------------
2092 
2093 Rectangle Region::GetBoundRect() const
2094 {
2095     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2096 
2097     Rectangle aRect;
2098 
2099     // no internal data? -> region is empty!
2100     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
2101         return aRect;
2102 
2103     // PolyPolygon data im Imp structure?
2104     if ( mpImplRegion->mpPolyPoly )
2105         return mpImplRegion->mpPolyPoly->GetBoundRect();
2106     if( mpImplRegion->mpB2DPolyPoly )
2107     {
2108         const basegfx::B2DRange aRange(basegfx::tools::getRange(*mpImplRegion->mpB2DPolyPoly));
2109 
2110         if(aRange.isEmpty())
2111         {
2112             // emulate PolyPolygon::GetBoundRect() when empty polygon
2113             return Rectangle();
2114         }
2115         else
2116         {
2117             return Rectangle(
2118                 static_cast<sal_Int32>(floor(aRange.getMinX())), static_cast<sal_Int32>(floor(aRange.getMinY())),
2119                 static_cast<sal_Int32>(ceil(aRange.getMaxX())), static_cast<sal_Int32>(ceil(aRange.getMaxY())));
2120         }
2121     }
2122 
2123     // no band in the list? -> region is empty!
2124     if ( !mpImplRegion->mpFirstBand )
2125         return aRect;
2126 
2127     // get the boundaries of the first band
2128     long nYTop    = mpImplRegion->mpFirstBand->mnYTop;
2129     long nYBottom = mpImplRegion->mpFirstBand->mnYBottom;
2130     long nXLeft   = mpImplRegion->mpFirstBand->GetXLeftBoundary();
2131     long nXRight  = mpImplRegion->mpFirstBand->GetXRightBoundary();
2132 
2133     // look in the band list (don't test first band again!)
2134     ImplRegionBand* pBand = mpImplRegion->mpFirstBand->mpNextBand;
2135     while ( pBand )
2136     {
2137         nYBottom    = pBand->mnYBottom;
2138         nXLeft      = Min( nXLeft, pBand->GetXLeftBoundary() );
2139         nXRight     = Max( nXRight, pBand->GetXRightBoundary() );
2140 
2141         pBand = pBand->mpNextBand;
2142     }
2143 
2144     // set rectangle
2145     aRect = Rectangle( nXLeft, nYTop, nXRight, nYBottom );
2146     return aRect;
2147 }
2148 
2149 // -----------------------------------------------------------------------
2150 
2151 sal_Bool Region::HasPolyPolygon() const
2152 {
2153     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2154     if( !mpImplRegion )
2155         return false;
2156     if( mpImplRegion->mpPolyPoly )
2157         return true;
2158     if( mpImplRegion->mpB2DPolyPoly )
2159         return true;
2160     return false;
2161 }
2162 
2163 // -----------------------------------------------------------------------
2164 
2165 PolyPolygon Region::GetPolyPolygon() const
2166 {
2167     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2168 
2169     PolyPolygon aRet;
2170 
2171     if( mpImplRegion->mpPolyPoly )
2172         aRet = *mpImplRegion->mpPolyPoly;
2173     else if( mpImplRegion->mpB2DPolyPoly )
2174     {
2175         // the polygon needs to be converted
2176         aRet = PolyPolygon( *mpImplRegion->mpB2DPolyPoly );
2177         // TODO: cache the converted polygon?
2178         // mpImplRegion->mpB2DPolyPoly = aRet;
2179     }
2180 
2181     return aRet;
2182 }
2183 
2184 // -----------------------------------------------------------------------
2185 
2186 const basegfx::B2DPolyPolygon Region::GetB2DPolyPolygon() const
2187 {
2188     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2189 
2190     basegfx::B2DPolyPolygon aRet;
2191 
2192     if( mpImplRegion->mpB2DPolyPoly )
2193         aRet = *mpImplRegion->mpB2DPolyPoly;
2194     else if( mpImplRegion->mpPolyPoly )
2195     {
2196         // the polygon needs to be converted
2197         aRet = mpImplRegion->mpPolyPoly->getB2DPolyPolygon();
2198         // TODO: cache the converted polygon?
2199         // mpImplRegion->mpB2DPolyPoly = aRet;
2200     }
2201 
2202     return aRet;
2203 }
2204 
2205 // -----------------------------------------------------------------------
2206 
2207 basegfx::B2DPolyPolygon Region::ConvertToB2DPolyPolygon()
2208 {
2209     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2210 
2211     basegfx::B2DPolyPolygon aRet;
2212 
2213     if( HasPolyPolygon() )
2214         aRet = GetB2DPolyPolygon();
2215     else
2216     {
2217         RegionHandle aHdl = BeginEnumRects();
2218         Rectangle aSubRect;
2219         while( GetNextEnumRect( aHdl, aSubRect ) )
2220         {
2221             basegfx::B2DPolygon aPoly( basegfx::tools::createPolygonFromRect(
2222                  basegfx::B2DRectangle( aSubRect.Left(), aSubRect.Top(), aSubRect.Right(), aSubRect.Bottom() ) ) );
2223             aRet.append( aPoly );
2224         }
2225         EndEnumRects( aHdl );
2226     }
2227 
2228     return aRet;
2229 }
2230 
2231 // -----------------------------------------------------------------------
2232 
2233 bool Region::ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo,
2234                                long& rX, long& rY,
2235                                long& rWidth, long& rHeight ) const
2236 {
2237     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2238 
2239     ((Region*)this)->ImplPolyPolyRegionToBandRegion();
2240 
2241     // no internal data? -> region is empty!
2242     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
2243         return false;
2244 
2245     // no band in the list? -> region is empty!
2246     if ( mpImplRegion->mpFirstBand == NULL )
2247         return false;
2248 
2249     // initialise pointer for first access
2250     ImplRegionBand*     pCurrRectBand = mpImplRegion->mpFirstBand;
2251     ImplRegionBandSep*  pCurrRectBandSep = pCurrRectBand->mpFirstSep;
2252 
2253     DBG_ASSERT( pCurrRectBandSep != NULL, "Erstes Band wurde nicht optimiert." );
2254     if ( !pCurrRectBandSep )
2255         return false;
2256 
2257     // get boundaries of current rectangle
2258     rX      = pCurrRectBandSep->mnXLeft;
2259     rY      = pCurrRectBand->mnYTop;
2260     rWidth  = pCurrRectBandSep->mnXRight - pCurrRectBandSep->mnXLeft + 1;
2261     rHeight = pCurrRectBand->mnYBottom - pCurrRectBand->mnYTop + 1;
2262 
2263     // save pointers
2264     rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand;
2265     rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep;
2266 
2267     return true;
2268 }
2269 
2270 // -----------------------------------------------------------------------
2271 
2272 bool Region::ImplGetNextRect( ImplRegionInfo& rImplRegionInfo,
2273                               long& rX, long& rY,
2274                               long& rWidth, long& rHeight ) const
2275 {
2276     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2277 
2278     // no internal data? -> region is empty!
2279     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
2280         return false;
2281 
2282     // get last pointers
2283     ImplRegionBand*     pCurrRectBand = (ImplRegionBand*)rImplRegionInfo.mpVoidCurrRectBand;
2284     ImplRegionBandSep*  pCurrRectBandSep = (ImplRegionBandSep*)rImplRegionInfo.mpVoidCurrRectBandSep;
2285 
2286     // get next separation from current band
2287     pCurrRectBandSep = pCurrRectBandSep->mpNextSep;
2288 
2289     // no separation found? -> go to next band!
2290     if ( !pCurrRectBandSep )
2291     {
2292         // get next band
2293         pCurrRectBand = pCurrRectBand->mpNextBand;
2294 
2295         // no band found? -> not further rectangles!
2296         if( !pCurrRectBand )
2297             return false;
2298 
2299         // get first separation in current band
2300         pCurrRectBandSep = pCurrRectBand->mpFirstSep;
2301     }
2302 
2303     // get boundaries of current rectangle
2304     rX      = pCurrRectBandSep->mnXLeft;
2305     rY      = pCurrRectBand->mnYTop;
2306     rWidth  = pCurrRectBandSep->mnXRight - pCurrRectBandSep->mnXLeft + 1;
2307     rHeight = pCurrRectBand->mnYBottom - pCurrRectBand->mnYTop + 1;
2308 
2309     // save new pointers
2310     rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand;
2311     rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep;
2312 
2313     return true;
2314 }
2315 
2316 // -----------------------------------------------------------------------
2317 
2318 RegionType Region::GetType() const
2319 {
2320     if ( mpImplRegion == &aImplEmptyRegion )
2321         return REGION_EMPTY;
2322     else if ( mpImplRegion == &aImplNullRegion )
2323         return REGION_NULL;
2324     else if ( mpImplRegion->mnRectCount == 1 )
2325         return REGION_RECTANGLE;
2326     else
2327         return REGION_COMPLEX;
2328 }
2329 
2330 // -----------------------------------------------------------------------
2331 
2332 sal_Bool Region::IsInside( const Point& rPoint ) const
2333 {
2334     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2335 
2336     // PolyPolygon data im Imp structure?
2337     ((Region*)this)->ImplPolyPolyRegionToBandRegion();
2338 /*
2339     if ( mpImplRegion->mpPolyPoly )
2340         return mpImplRegion->mpPolyPoly->IsInside( rPoint );
2341 */
2342 
2343     // no instance data? -> not inside
2344     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
2345         return sal_False;
2346 
2347     // search band list
2348     ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
2349     while ( pBand )
2350     {
2351         // is point within band?
2352         if ( (pBand->mnYTop <= rPoint.Y()) &&
2353              (pBand->mnYBottom >= rPoint.Y()) )
2354         {
2355             // is point within separation of the band?
2356             if ( pBand->IsInside( rPoint.X() ) )
2357                 return sal_True;
2358             else
2359                 return sal_False;
2360         }
2361 
2362         pBand = pBand->mpNextBand;
2363     }
2364 
2365     return sal_False;
2366 }
2367 
2368 // -----------------------------------------------------------------------
2369 
2370 sal_Bool Region::IsInside( const Rectangle& rRect ) const
2371 {
2372     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2373 
2374     // is rectangle empty? -> not inside
2375     if ( rRect.IsEmpty() )
2376         return sal_False;
2377 
2378     // no instance data? -> not inside
2379     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
2380         return sal_False;
2381 
2382     // create region from rectangle and intersect own region
2383     Region aRegion = rRect;
2384     aRegion.Exclude( *this );
2385 
2386     // rectangle is inside if exclusion is empty
2387     return aRegion.IsEmpty();
2388 }
2389 
2390 // -----------------------------------------------------------------------
2391 
2392 sal_Bool Region::IsOver( const Rectangle& rRect ) const
2393 {
2394     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2395 
2396     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
2397         return sal_False;
2398 
2399     // Can we optimize this ??? - is used in StarDraw for brushes pointers
2400     // Why we have no IsOver for Regions ???
2401     // create region from rectangle and intersect own region
2402     Region aRegion = rRect;
2403     aRegion.Intersect( *this );
2404 
2405     // rectangle is over if include is not empty
2406     return !aRegion.IsEmpty();
2407 }
2408 
2409 // -----------------------------------------------------------------------
2410 
2411 void Region::SetNull()
2412 {
2413     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2414 
2415     // statische Object haben RefCount von 0
2416     if ( mpImplRegion->mnRefCount )
2417     {
2418         if ( mpImplRegion->mnRefCount > 1 )
2419             mpImplRegion->mnRefCount--;
2420         else
2421             delete mpImplRegion;
2422     }
2423 
2424     // set new type
2425     mpImplRegion = (ImplRegion*)(&aImplNullRegion);
2426 }
2427 
2428 // -----------------------------------------------------------------------
2429 
2430 void Region::SetEmpty()
2431 {
2432     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2433 
2434     // statische Object haben RefCount von 0
2435     if ( mpImplRegion->mnRefCount )
2436     {
2437         if ( mpImplRegion->mnRefCount > 1 )
2438             mpImplRegion->mnRefCount--;
2439         else
2440             delete mpImplRegion;
2441     }
2442 
2443     // set new type
2444     mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
2445 }
2446 
2447 // -----------------------------------------------------------------------
2448 
2449 Region& Region::operator=( const Region& rRegion )
2450 {
2451     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2452     DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
2453     DBG_ASSERT( rRegion.mpImplRegion->mnRefCount < 0xFFFFFFFE, "Region: RefCount overflow" );
2454 
2455     // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
2456     // RefCount == 0 fuer statische Objekte
2457     if ( rRegion.mpImplRegion->mnRefCount )
2458         rRegion.mpImplRegion->mnRefCount++;
2459 
2460     // statische Object haben RefCount von 0
2461     if ( mpImplRegion->mnRefCount )
2462     {
2463         if ( mpImplRegion->mnRefCount > 1 )
2464             mpImplRegion->mnRefCount--;
2465         else
2466             delete mpImplRegion;
2467     }
2468 
2469     mpImplRegion = rRegion.mpImplRegion;
2470     return *this;
2471 }
2472 
2473 // -----------------------------------------------------------------------
2474 
2475 Region& Region::operator=( const Rectangle& rRect )
2476 {
2477     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2478 
2479     // statische Object haben RefCount von 0
2480     if ( mpImplRegion->mnRefCount )
2481     {
2482         if ( mpImplRegion->mnRefCount > 1 )
2483             mpImplRegion->mnRefCount--;
2484         else
2485             delete mpImplRegion;
2486     }
2487 
2488     ImplCreateRectRegion( rRect );
2489     return *this;
2490 }
2491 
2492 // -----------------------------------------------------------------------
2493 
2494 sal_Bool Region::operator==( const Region& rRegion ) const
2495 {
2496     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2497     DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
2498 
2499     // reference to same object? -> equal!
2500     if ( mpImplRegion == rRegion.mpImplRegion )
2501         return sal_True;
2502 
2503     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
2504         return sal_False;
2505 
2506     if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
2507         return sal_False;
2508 
2509     if ( rRegion.mpImplRegion->mpPolyPoly && mpImplRegion->mpPolyPoly )
2510         return *rRegion.mpImplRegion->mpPolyPoly == *mpImplRegion->mpPolyPoly;
2511     else
2512     {
2513         ((Region*)this)->ImplPolyPolyRegionToBandRegion();
2514         ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();
2515 
2516         // Eine der beiden Regions kann jetzt Empty sein
2517         if ( mpImplRegion == rRegion.mpImplRegion )
2518             return sal_True;
2519 
2520         if ( mpImplRegion == &aImplEmptyRegion )
2521             return sal_False;
2522 
2523         if ( rRegion.mpImplRegion == &aImplEmptyRegion )
2524             return sal_False;
2525     }
2526 
2527     // initialise pointers
2528     ImplRegionBand*      pOwnRectBand = mpImplRegion->mpFirstBand;
2529     ImplRegionBandSep*   pOwnRectBandSep = pOwnRectBand->mpFirstSep;
2530     ImplRegionBand*      pSecondRectBand = rRegion.mpImplRegion->mpFirstBand;
2531     ImplRegionBandSep*   pSecondRectBandSep = pSecondRectBand->mpFirstSep;
2532     while ( pOwnRectBandSep && pSecondRectBandSep )
2533     {
2534         // get boundaries of current rectangle
2535         long nOwnXLeft = pOwnRectBandSep->mnXLeft;
2536         long nSecondXLeft = pSecondRectBandSep->mnXLeft;
2537         if ( nOwnXLeft != nSecondXLeft )
2538             return sal_False;
2539 
2540         long nOwnYTop = pOwnRectBand->mnYTop;
2541         long nSecondYTop = pSecondRectBand->mnYTop;
2542         if ( nOwnYTop != nSecondYTop )
2543             return sal_False;
2544 
2545         long nOwnXRight = pOwnRectBandSep->mnXRight;
2546         long nSecondXRight = pSecondRectBandSep->mnXRight;
2547         if ( nOwnXRight != nSecondXRight )
2548             return sal_False;
2549 
2550         long nOwnYBottom = pOwnRectBand->mnYBottom;
2551         long nSecondYBottom = pSecondRectBand->mnYBottom;
2552         if ( nOwnYBottom != nSecondYBottom )
2553             return sal_False;
2554 
2555         // get next separation from current band
2556         pOwnRectBandSep = pOwnRectBandSep->mpNextSep;
2557 
2558         // no separation found? -> go to next band!
2559         if ( !pOwnRectBandSep )
2560         {
2561             // get next band
2562             pOwnRectBand = pOwnRectBand->mpNextBand;
2563 
2564             // get first separation in current band
2565             if( pOwnRectBand )
2566                 pOwnRectBandSep = pOwnRectBand->mpFirstSep;
2567         }
2568 
2569         // get next separation from current band
2570         pSecondRectBandSep = pSecondRectBandSep->mpNextSep;
2571 
2572         // no separation found? -> go to next band!
2573         if ( !pSecondRectBandSep )
2574         {
2575             // get next band
2576             pSecondRectBand = pSecondRectBand->mpNextBand;
2577 
2578             // get first separation in current band
2579             if( pSecondRectBand )
2580                 pSecondRectBandSep = pSecondRectBand->mpFirstSep;
2581         }
2582 
2583         if ( pOwnRectBandSep && !pSecondRectBandSep )
2584             return sal_False;
2585 
2586         if ( !pOwnRectBandSep && pSecondRectBandSep )
2587             return sal_False;
2588     }
2589 
2590     return sal_True;
2591 }
2592 
2593 // -----------------------------------------------------------------------
2594 
2595 enum StreamEntryType { STREAMENTRY_BANDHEADER, STREAMENTRY_SEPARATION, STREAMENTRY_END };
2596 
2597 SvStream& operator>>( SvStream& rIStrm, Region& rRegion )
2598 {
2599     DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
2600 
2601     VersionCompat   aCompat( rIStrm, STREAM_READ );
2602     sal_uInt16          nVersion;
2603     sal_uInt16          nTmp16;
2604 
2605     // statische Object haben RefCount von 0
2606     if ( rRegion.mpImplRegion->mnRefCount )
2607     {
2608         if ( rRegion.mpImplRegion->mnRefCount > 1 )
2609             rRegion.mpImplRegion->mnRefCount--;
2610         else
2611             delete rRegion.mpImplRegion;
2612     }
2613 
2614     // get version of streamed region
2615     rIStrm >> nVersion;
2616 
2617     // get type of region
2618     rIStrm >> nTmp16;
2619 
2620     RegionType meStreamedType = (RegionType)nTmp16;
2621 
2622     switch( meStreamedType )
2623     {
2624         case REGION_NULL:
2625             rRegion.mpImplRegion = (ImplRegion*)&aImplNullRegion;
2626         break;
2627 
2628         case REGION_EMPTY:
2629             rRegion.mpImplRegion = (ImplRegion*)&aImplEmptyRegion;
2630         break;
2631 
2632         default:
2633         {
2634             // create instance of implementation class
2635             rRegion.mpImplRegion = new ImplRegion();
2636 
2637             // get header from first element
2638             rIStrm >> nTmp16;
2639 
2640             // get all bands
2641             rRegion.mpImplRegion->mnRectCount = 0;
2642             ImplRegionBand* pCurrBand = NULL;
2643             while ( (StreamEntryType)nTmp16 != STREAMENTRY_END )
2644             {
2645                 // insert new band or new separation?
2646                 if ( (StreamEntryType)nTmp16 == STREAMENTRY_BANDHEADER )
2647                 {
2648                     long nYTop;
2649                     long nYBottom;
2650 
2651                     rIStrm >> nYTop;
2652                     rIStrm >> nYBottom;
2653 
2654                     // create band
2655                     ImplRegionBand* pNewBand = new ImplRegionBand( nYTop, nYBottom );
2656 
2657                     // first element? -> set as first into the list
2658                     if ( !pCurrBand )
2659                         rRegion.mpImplRegion->mpFirstBand = pNewBand;
2660                     else
2661                         pCurrBand->mpNextBand = pNewBand;
2662 
2663                     // save pointer for next creation
2664                     pCurrBand = pNewBand;
2665                 }
2666                 else
2667                 {
2668                     long nXLeft;
2669                     long nXRight;
2670 
2671                     rIStrm >> nXLeft;
2672                     rIStrm >> nXRight;
2673 
2674                     // add separation
2675                     if ( pCurrBand )
2676                     {
2677                         pCurrBand->Union( nXLeft, nXRight );
2678                         rRegion.mpImplRegion->mnRectCount++;
2679                     }
2680                 }
2681 
2682                 if( rIStrm.IsEof() )
2683                 {
2684                     DBG_ERROR( "premature end of region stream" );
2685                     delete rRegion.mpImplRegion;
2686                     rRegion.mpImplRegion = (ImplRegion*)&aImplEmptyRegion;
2687                     return rIStrm;
2688                 }
2689 
2690                 // get next header
2691                 rIStrm >> nTmp16;
2692             }
2693 
2694             if( aCompat.GetVersion() >= 2 )
2695             {
2696                 sal_Bool bHasPolyPolygon;
2697 
2698                 rIStrm >> bHasPolyPolygon;
2699 
2700                 if( bHasPolyPolygon )
2701                 {
2702                     delete rRegion.mpImplRegion->mpPolyPoly;
2703                     rRegion.mpImplRegion->mpPolyPoly = new PolyPolygon;
2704                     rIStrm >> *( rRegion.mpImplRegion->mpPolyPoly );
2705                 }
2706             }
2707         }
2708         break;
2709     }
2710 
2711     return rIStrm;
2712 }
2713 
2714 // -----------------------------------------------------------------------
2715 
2716 SvStream& operator<<( SvStream& rOStrm, const Region& rRegion )
2717 {
2718     DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
2719 
2720     sal_uInt16          nVersion = 2;
2721     VersionCompat   aCompat( rOStrm, STREAM_WRITE, nVersion );
2722     Region          aTmpRegion( rRegion );
2723 
2724     // use tmp region to avoid destruction of internal region (polypolygon) of rRegion
2725     aTmpRegion.ImplPolyPolyRegionToBandRegion();
2726 
2727     // put version
2728     rOStrm << nVersion;
2729 
2730     // put type
2731     rOStrm << (sal_uInt16)aTmpRegion.GetType();
2732 
2733     // put all bands if not null or empty
2734     if ( (aTmpRegion.mpImplRegion != &aImplEmptyRegion) && (aTmpRegion.mpImplRegion != &aImplNullRegion) )
2735     {
2736         ImplRegionBand* pBand = aTmpRegion.mpImplRegion->mpFirstBand;
2737         while ( pBand )
2738         {
2739             // put boundaries
2740             rOStrm << (sal_uInt16) STREAMENTRY_BANDHEADER;
2741             rOStrm << pBand->mnYTop;
2742             rOStrm << pBand->mnYBottom;
2743 
2744             // put separations of current band
2745             ImplRegionBandSep* pSep = pBand->mpFirstSep;
2746             while ( pSep )
2747             {
2748                 // put separation
2749                 rOStrm << (sal_uInt16) STREAMENTRY_SEPARATION;
2750                 rOStrm << pSep->mnXLeft;
2751                 rOStrm << pSep->mnXRight;
2752 
2753                 // next separation from current band
2754                 pSep = pSep->mpNextSep;
2755             }
2756 
2757             pBand = pBand->mpNextBand;
2758         }
2759 
2760         // put endmarker
2761         rOStrm << (sal_uInt16) STREAMENTRY_END;
2762 
2763         // write polypolygon if available
2764         const sal_Bool bHasPolyPolygon = rRegion.HasPolyPolygon();
2765         rOStrm << bHasPolyPolygon;
2766 
2767         if( bHasPolyPolygon )
2768         {
2769             // #i105373#
2770             PolyPolygon aNoCurvePolyPolygon;
2771             rRegion.GetPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon);
2772 
2773             rOStrm << aNoCurvePolyPolygon;
2774         }
2775     }
2776 
2777     return rOStrm;
2778 }
2779 
2780 // -----------------------------------------------------------------------
2781 
2782 void Region::ImplBeginAddRect()
2783 {
2784     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2785 
2786     // statische Object haben RefCount von 0
2787     if ( mpImplRegion->mnRefCount )
2788     {
2789         if ( mpImplRegion->mnRefCount > 1 )
2790             mpImplRegion->mnRefCount--;
2791         else
2792             delete mpImplRegion;
2793     }
2794 
2795     // create fresh region
2796     mpImplRegion = new ImplRegion();
2797 }
2798 
2799 // -----------------------------------------------------------------------
2800 
2801 sal_Bool Region::ImplAddRect( const Rectangle& rRect )
2802 {
2803     // Hier kein CheckThis, da nicht alle Daten auf Stand
2804 
2805     if ( rRect.IsEmpty() )
2806         return sal_True;
2807 
2808     // get justified rectangle
2809     long nTop;
2810     long nBottom;
2811     long nLeft;
2812     long nRight;
2813     if ( rRect.Top() <= rRect.Bottom() )
2814     {
2815         nTop = rRect.Top();
2816         nBottom = rRect.Bottom();
2817     }
2818     else
2819     {
2820         nTop = rRect.Bottom();
2821         nBottom = rRect.Top();
2822     }
2823     if ( rRect.Left() <= rRect.Right() )
2824     {
2825         nLeft = rRect.Left();
2826         nRight = rRect.Right();
2827     }
2828     else
2829     {
2830         nLeft = rRect.Right();
2831         nRight = rRect.Left();
2832     }
2833 
2834     if ( !mpImplRegion->mpLastCheckedBand )
2835     {
2836         // create new band
2837         mpImplRegion->mpLastCheckedBand = new ImplRegionBand( nTop, nBottom );
2838 
2839         // set band as current
2840         mpImplRegion->mpFirstBand = mpImplRegion->mpLastCheckedBand;
2841         mpImplRegion->mpLastCheckedBand->Union( nLeft, nRight );
2842     }
2843     else
2844     {
2845         DBG_ASSERT( nTop >= mpImplRegion->mpLastCheckedBand->mnYTop,
2846                     "Region::ImplAddRect() - nTopY < nLastTopY" );
2847 
2848         // new band? create it!
2849         if ( (nTop != mpImplRegion->mpLastCheckedBand->mnYTop) ||
2850              (nBottom != mpImplRegion->mpLastCheckedBand->mnYBottom) )
2851         {
2852             // create new band
2853             ImplRegionBand* pNewRegionBand = new ImplRegionBand( nTop, nBottom );
2854 
2855             // append band to the end
2856             mpImplRegion->mpLastCheckedBand->mpNextBand = pNewRegionBand;
2857 
2858             // skip to the new band
2859             mpImplRegion->mpLastCheckedBand = mpImplRegion->mpLastCheckedBand->mpNextBand;
2860         }
2861 
2862         // Insert Sep
2863         mpImplRegion->mpLastCheckedBand->Union( nLeft, nRight );
2864     }
2865 
2866     return sal_True;
2867 }
2868 
2869 // -----------------------------------------------------------------------
2870 
2871 void Region::ImplEndAddRect()
2872 {
2873     // check if we are empty
2874     if ( !mpImplRegion->mpFirstBand )
2875     {
2876         delete mpImplRegion;
2877         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
2878         return;
2879     }
2880 
2881     // check if we have somthing to optimize
2882     if ( !mpImplRegion->mpFirstBand->mpNextBand )
2883     {
2884         // update mpImplRegion->mnRectCount, because no OptimizeBandList is called
2885         ImplRegionBandSep* pSep = mpImplRegion->mpFirstBand->mpFirstSep;
2886         mpImplRegion->mnRectCount = 0;
2887         while( pSep )
2888         {
2889             mpImplRegion->mnRectCount++;
2890             pSep = pSep->mpNextSep;
2891         }
2892 
2893         // Erst hier testen, da hier die Daten wieder stimmen
2894         DBG_CHKTHIS( Region, ImplDbgTestRegion );
2895         return;
2896     }
2897 
2898     // have to revert list? -> do it now!
2899     if ( mpImplRegion->mpFirstBand->mnYTop >
2900          mpImplRegion->mpFirstBand->mpNextBand->mnYTop )
2901     {
2902         ImplRegionBand * pNewFirstRegionBand;
2903 
2904         // initialize temp list with first element
2905         pNewFirstRegionBand = mpImplRegion->mpFirstBand;
2906         mpImplRegion->mpFirstBand = mpImplRegion->mpFirstBand->mpNextBand;
2907         pNewFirstRegionBand->mpNextBand = NULL;
2908 
2909         // insert elements to the temp list
2910         while ( mpImplRegion->mpFirstBand )
2911         {
2912             ImplRegionBand * pSavedRegionBand = pNewFirstRegionBand;
2913             pNewFirstRegionBand = mpImplRegion->mpFirstBand;
2914             mpImplRegion->mpFirstBand = mpImplRegion->mpFirstBand->mpNextBand;
2915             pNewFirstRegionBand->mpNextBand = pSavedRegionBand;
2916         }
2917 
2918         // set temp list as new list
2919         mpImplRegion->mpFirstBand = pNewFirstRegionBand;
2920     }
2921 
2922     // cleanup
2923     if ( !mpImplRegion->OptimizeBandList() )
2924     {
2925         delete mpImplRegion;
2926         mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
2927     }
2928 
2929     // Erst hier testen, da hier die Daten wieder stimmen
2930     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2931 }
2932 
2933 // -----------------------------------------------------------------------
2934 
2935 sal_uLong Region::GetRectCount() const
2936 {
2937     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2938 
2939     ((Region*)this)->ImplPolyPolyRegionToBandRegion();
2940 
2941 #ifdef DBG_UTIL
2942     sal_uLong nCount = 0;
2943 
2944     // all bands if not null or empty
2945     if ( (mpImplRegion != &aImplEmptyRegion) && (mpImplRegion != &aImplNullRegion) )
2946     {
2947         ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
2948         while ( pBand )
2949         {
2950             ImplRegionBandSep* pSep = pBand->mpFirstSep;
2951             while( pSep )
2952             {
2953                 nCount++;
2954                 pSep = pSep->mpNextSep;
2955             }
2956 
2957             pBand = pBand->mpNextBand;
2958         }
2959     }
2960 
2961     DBG_ASSERT( mpImplRegion->mnRectCount == nCount, "Region: invalid mnRectCount!" );
2962 #endif
2963 
2964     return mpImplRegion->mnRectCount;
2965 }
2966 
2967 // -----------------------------------------------------------------------
2968 
2969 RegionHandle Region::BeginEnumRects()
2970 {
2971     DBG_CHKTHIS( Region, ImplDbgTestRegion );
2972 
2973     ImplPolyPolyRegionToBandRegion();
2974 
2975     // no internal data? -> region is empty!
2976     if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
2977         return 0;
2978 
2979     // no band in the list? -> region is empty!
2980     if ( mpImplRegion->mpFirstBand == NULL )
2981     {
2982         DBG_ASSERT( mpImplRegion->mpFirstBand, "Region::BeginEnumRects() First Band is Empty!" );
2983         return 0;
2984     }
2985 
2986     ImplRegionHandle* pData = new ImplRegionHandle;
2987     pData->mpRegion = new Region( *this );
2988     pData->mbFirst  = sal_True;
2989 
2990     // save pointers
2991     pData->mpCurrRectBand = pData->mpRegion->mpImplRegion->mpFirstBand;
2992     pData->mpCurrRectBandSep = pData->mpCurrRectBand->mpFirstSep;
2993 
2994     return (RegionHandle)pData;
2995 }
2996 
2997 // -----------------------------------------------------------------------
2998 
2999 sal_Bool Region::GetEnumRects( RegionHandle pVoidData, Rectangle& rRect )
3000 {
3001     DBG_CHKTHIS( Region, ImplDbgTestRegion );
3002 
3003     ImplRegionHandle* pData = (ImplRegionHandle*)pVoidData;
3004     if ( !pData )
3005         return sal_False;
3006 
3007     if ( pData->mbFirst )
3008         pData->mbFirst = sal_False;
3009     else
3010     {
3011         // get next separation from current band
3012         pData->mpCurrRectBandSep = pData->mpCurrRectBandSep->mpNextSep;
3013 
3014         // no separation found? -> go to next band!
3015         if ( !pData->mpCurrRectBandSep )
3016         {
3017             // get next band
3018             pData->mpCurrRectBand = pData->mpCurrRectBand->mpNextBand;
3019 
3020             // no band found? -> not further rectangles!
3021             if ( !pData->mpCurrRectBand )
3022                 return sal_False;
3023 
3024             // get first separation in current band
3025             pData->mpCurrRectBandSep = pData->mpCurrRectBand->mpFirstSep;
3026         }
3027     }
3028 
3029     // get boundaries of current rectangle
3030     rRect.Top()     = pData->mpCurrRectBand->mnYTop;
3031     rRect.Bottom()  = pData->mpCurrRectBand->mnYBottom;
3032     rRect.Left()    = pData->mpCurrRectBandSep->mnXLeft;
3033     rRect.Right()   = pData->mpCurrRectBandSep->mnXRight;
3034     return sal_True;
3035 }
3036 
3037 // -----------------------------------------------------------------------
3038 
3039 void Region::EndEnumRects( RegionHandle pVoidData )
3040 {
3041     DBG_CHKTHIS( Region, ImplDbgTestRegion );
3042 
3043     ImplRegionHandle* pData = (ImplRegionHandle*)pVoidData;
3044     if ( !pData )
3045         return;
3046 
3047     // cleanup
3048     delete pData->mpRegion;
3049     delete pData;
3050 }
3051 
3052 // -----------------------------------------------------------------------
3053 
3054 static inline bool ImplPolygonRectTest( const Polygon& rPoly, Rectangle* pRectOut = NULL )
3055 {
3056     bool bIsRect = false;
3057     const Point* pPoints = rPoly.GetConstPointAry();
3058     sal_uInt16 nPoints = rPoly.GetSize();
3059     if( nPoints == 4 || (nPoints == 5 && pPoints[0] == pPoints[4]) )
3060     {
3061         long nX1 = pPoints[0].X(), nX2 = pPoints[2].X(),
3062         nY1 = pPoints[0].Y(), nY2 = pPoints[2].Y();
3063         if( ( (pPoints[1].X() == nX1 && pPoints[3].X() == nX2) &&
3064             (pPoints[1].Y() == nY2 && pPoints[3].Y() == nY1) )
3065         ||
3066         ( (pPoints[1].X() == nX2 && pPoints[3].X() == nX1) &&
3067         (pPoints[1].Y() == nY1 && pPoints[3].Y() == nY2) ) )
3068         {
3069             bIsRect = true;
3070             if( pRectOut )
3071             {
3072                 long nSwap;
3073                 if( nX2 < nX1 )
3074                 {
3075                     nSwap = nX2;
3076                     nX2 = nX1;
3077                     nX1 = nSwap;
3078                 }
3079                 if( nY2 < nY1 )
3080                 {
3081                     nSwap = nY2;
3082                     nY2 = nY1;
3083                     nY1 = nSwap;
3084                 }
3085                 if( nX2 != nX1 )
3086                     nX2--;
3087                 if( nY2 != nY1 )
3088                     nY2--;
3089                 pRectOut->Left()    = nX1;
3090                 pRectOut->Right()   = nX2;
3091                 pRectOut->Top()     = nY1;
3092                 pRectOut->Bottom()  = nY2;
3093             }
3094         }
3095     }
3096     return bIsRect;
3097 }
3098 
3099 Region Region::GetRegionFromPolyPolygon( const PolyPolygon& rPolyPoly )
3100 {
3101     //return Region( rPolyPoly );
3102 
3103     // check if it's worth extracting the XOr'ing the Rectangles
3104     // empiricism shows that break even between XOr'ing rectangles separately
3105     // and ImplPolyPolyRegionToBandRegion is at half rectangles/half polygons
3106     int nPolygonRects = 0, nPolygonPolygons = 0;
3107     int nPolygons = rPolyPoly.Count();
3108 
3109     for( sal_uInt16 i = 0; i < nPolygons; i++ )
3110     {
3111         const Polygon& rPoly = rPolyPoly[i];
3112         if( ImplPolygonRectTest( rPoly ) )
3113             nPolygonRects++;
3114         else
3115             nPolygonPolygons++;
3116     }
3117     if( nPolygonPolygons > nPolygonRects )
3118         return Region( rPolyPoly );
3119 
3120     Region aResult;
3121     Rectangle aRect;
3122     for( sal_uInt16 i = 0; i < nPolygons; i++ )
3123     {
3124         const Polygon& rPoly = rPolyPoly[i];
3125         if( ImplPolygonRectTest( rPoly, &aRect ) )
3126             aResult.XOr( aRect );
3127         else
3128             aResult.XOr( Region(rPoly) );
3129     }
3130     return aResult;
3131 }
3132