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