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