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