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