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