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