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