/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include <limits.h>

#include <tools/vcompat.hxx>
#include <tools/stream.hxx>
#include <tools/debug.hxx>

#include <vcl/region.hxx>
#include <vcl/regband.hxx>
#include <vcl/salbtype.hxx>

#include <region.h>

#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolygonclipper.hxx>
#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
#include <basegfx/range/b2drange.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>

// =======================================================================
//
// ImplRegionBand
//
// Die Klassen RegionBand/ImplRegionBand speichert Regionen in Form von
// Rechtecken ab. Die Region ist in Y-Richtung in Baendern unterteilt, die
// wiederum ein oder mehrere Rechtecke mit der Hoehe des Bandes enthalten.
//
// Leere Baender werden entfernt.
//
// Polygone und PolyPolygone werden ebenfalls in Rechtecke zerlegt und in
// der Baendern abgelegt. Hierzu werden alle Punkte der einzelnen Polygone
// mit dem Bresenham-Algorithmus berechnet und in die Baender eingetragen.
// Nach der vollstaendigen Berechung aller Kanten werden die entsprechenden
// Rechntecke berechnet

// =======================================================================

static ImplRegionBase aImplNullRegion( 0 );
static ImplRegionBase aImplEmptyRegion( 0 );

// =======================================================================

DBG_NAME( Region )
DBG_NAMEEX( Polygon )
DBG_NAMEEX( PolyPolygon )

namespace {

/** Return <TRUE/> when the given polygon is rectiliner and oriented so that
    all sides are either horizontal or vertical.
*/
bool ImplIsPolygonRectilinear (const PolyPolygon& rPolyPoly)
{
    // Iterate over all polygons.
	const sal_uInt16 nPolyCount = rPolyPoly.Count();
    for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
    {
        const Polygon&	aPoly = rPolyPoly.GetObject(nPoly);

        // Iterate over all edges of the current polygon.
        const sal_uInt16 nSize = aPoly.GetSize();

        if (nSize < 2)
            continue;
        Point aPoint (aPoly.GetPoint(0));
        const Point aLastPoint (aPoint);
        for (sal_uInt16 nPoint = 1; nPoint < nSize; ++nPoint)
        {
            const Point aNextPoint (aPoly.GetPoint(nPoint));
            // When there is at least one edge that is neither vertical nor
            // horizontal then the entire polygon is not rectilinear (and
            // oriented along primary axes.)
            if (aPoint.X() != aNextPoint.X() && aPoint.Y() != aNextPoint.Y())
                return false;

            aPoint = aNextPoint;
        }
        // Compare closing edge.
        if (aLastPoint.X() != aPoint.X() && aLastPoint.Y() != aPoint.Y())
            return false;
    }
    return true;
}



/** This function is similar to the ImplRegion::InsertBands() method.
    It creates a minimal set of missing bands so that the entire vertical
    interval from nTop to nBottom is covered by bands.
*/
void ImplAddMissingBands (
    ImplRegion* pImplRegion,
    const long nTop,
    const long nBottom)
{
    // Iterate over already existing bands and add missing bands atop the
    // first and between two bands.
    ImplRegionBand* pPreviousBand = NULL;
    ImplRegionBand* pBand = pImplRegion->ImplGetFirstRegionBand();
    long nCurrentTop (nTop);
    while (pBand != NULL && nCurrentTop<nBottom)
    {
        if (nCurrentTop < pBand->mnYTop)
        {
            // Create new band above the current band.
            ImplRegionBand* pAboveBand = new ImplRegionBand(
                nCurrentTop,
                ::std::min(nBottom,pBand->mnYTop-1));
            pImplRegion->InsertBand(pPreviousBand, pAboveBand);
        }

        // Adapt the top of the interval to prevent overlapping bands.
        nCurrentTop = ::std::max(nTop, pBand->mnYBottom+1);

        // Advance to next band.
        pPreviousBand = pBand;
        pBand = pBand->mpNextBand;
    }

    // We still have to cover two cases:
    // 1. The region does not yet contain any bands.
    // 2. The intervall nTop->nBottom extends past the bottom most band.
    if (nCurrentTop <= nBottom
        && (pBand==NULL || nBottom>pBand->mnYBottom))
    {
        // When there is no previous band then the new one will be the
        // first.  Otherwise the new band is inserted behind the last band.
        pImplRegion->InsertBand(
            pPreviousBand,
            new ImplRegionBand(
                nCurrentTop,
                nBottom));
    }
}



/** Convert a rectilinear polygon (that is oriented along the primary axes)
    to a list of bands.  For this special form of polygon we can use an
    optimization that prevents the creation of one band per y value.
    However, it still is possible that some temporary bands are created that
    later can be optimized away.
    @param rPolyPolygon
        A set of zero, one, or more polygons, nested or not, that are
        converted into a list of bands.
    @return
        A new ImplRegion object is returned that contains the bands that
        represent the given poly-polygon.
*/
ImplRegion* ImplRectilinearPolygonToBands (const PolyPolygon& rPolyPoly)
{
    OSL_ASSERT(ImplIsPolygonRectilinear (rPolyPoly));

    // Create a new ImplRegion object as container of the bands.
    ImplRegion* pImplRegion = new ImplRegion();
    long nLineId = 0L;

    // Iterate over all polygons.
	const sal_uInt16 nPolyCount = rPolyPoly.Count();
    for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
    {
        const Polygon&	aPoly = rPolyPoly.GetObject(nPoly);

        // Iterate over all edges of the current polygon.
        const sal_uInt16 nSize = aPoly.GetSize();
        if (nSize < 2)
            continue;
        // Avoid fetching every point twice (each point is the start point
        // of one and the end point of another edge.)
        Point aStart (aPoly.GetPoint(0));
        Point aEnd;
        for (sal_uInt16 nPoint = 1; nPoint <= nSize; ++nPoint, aStart=aEnd)
        {
            // We take the implicit closing edge into account by mapping
            // index nSize to 0.
            aEnd = aPoly.GetPoint(nPoint%nSize);
            if (aStart.Y() == aEnd.Y())
            {
                // Horizontal lines are ignored.
                continue;
            }

            // At this point the line has to be vertical.
            OSL_ASSERT(aStart.X() == aEnd.X());

            // Sort y-coordinates to simplify the algorithm and store the
            // direction seperately.  The direction is calculated as it is
            // in other places (but seems to be the wrong way.)
            const long nTop (::std::min(aStart.Y(), aEnd.Y()));
            const long nBottom (::std::max(aStart.Y(), aEnd.Y()));
            const LineType eLineType (aStart.Y() > aEnd.Y() ? LINE_DESCENDING : LINE_ASCENDING);
        
            // Make sure that the current line is covered by bands.
            ImplAddMissingBands(pImplRegion, nTop,nBottom);

            // Find top-most band that may contain nTop.
            ImplRegionBand* pBand = pImplRegion->ImplGetFirstRegionBand();
            while (pBand!=NULL && pBand->mnYBottom < nTop)
                pBand = pBand->mpNextBand;
            ImplRegionBand* pTopBand = pBand;
            // If necessary split the band at nTop so that nTop is contained
            // in the lower band.
            if (pBand!=NULL
                   // Prevent the current band from becoming 0 pixel high
                && pBand->mnYTop<nTop
                   // this allows the lowest pixel of the band to be split off
                && pBand->mnYBottom>=nTop
                   // do not split a band that is just one pixel high
                && pBand->mnYTop<pBand->mnYBottom)
            {
                // Split the top band.
                pTopBand = pBand->SplitBand(nTop);
            }

            // Advance to band that may contain nBottom.
            while (pBand!=NULL && pBand->mnYBottom < nBottom)
                pBand = pBand->mpNextBand;
            // The lowest band may have to be split at nBottom so that
            // nBottom itself remains in the upper band.
            if (pBand!=NULL
                   // allow the current band becoming 1 pixel high
                && pBand->mnYTop<=nBottom
                   // prevent splitting off a band that is 0 pixel high
                && pBand->mnYBottom>nBottom
                   // do not split a band that is just one pixel high
                && pBand->mnYTop<pBand->mnYBottom)
            {
                // Split the bottom band.
                pBand->SplitBand(nBottom+1);
            }

            // Note that we remember the top band (in pTopBand) but not the
            // bottom band.  The later can be determined by comparing y
            // coordinates.

            // Add the x-value as point to all bands in the nTop->nBottom range.
            for (pBand=pTopBand; pBand!=NULL&&pBand->mnYTop<=nBottom; pBand=pBand->mpNextBand)
                pBand->InsertPoint(aStart.X(), nLineId++, sal_True, eLineType);
        }
    }

    return pImplRegion;
}




/** Convert a general polygon (one for which ImplIsPolygonRectilinear()
    returns <FALSE/>) to bands.
*/
ImplRegion* ImplGeneralPolygonToBands (
    const PolyPolygon& rPolyPoly,
    const Rectangle& rPolygonBoundingBox)
{
    long nLineID = 0L;

    // initialisation and creation of Bands
    ImplRegion* pImplRegion = new ImplRegion();
    pImplRegion->CreateBandRange( rPolygonBoundingBox.Top(), rPolygonBoundingBox.Bottom() );
            
    // insert polygons
	const sal_uInt16 nPolyCount = rPolyPoly.Count();
    for ( sal_uInt16 nPoly = 0; nPoly < nPolyCount; nPoly++ )
    {
        // get reference to current polygon
        const Polygon&	aPoly = rPolyPoly.GetObject( nPoly );
        const sal_uInt16	nSize = aPoly.GetSize();

        // not enough points ( <= 2 )? -> nothing to do!
        if ( nSize <= 2 )
            continue;

        // band the polygon
        for ( sal_uInt16 nPoint = 1; nPoint < nSize; nPoint++ )
            pImplRegion->InsertLine( aPoly.GetPoint(nPoint-1), aPoly.GetPoint(nPoint), nLineID++ );

        // close polygon with line from first point to last point, if neccesary
        const Point rLastPoint = aPoly.GetPoint(nSize-1);
        const Point rFirstPoint = aPoly.GetPoint(0);
        if ( rLastPoint != rFirstPoint )
            pImplRegion->InsertLine( rLastPoint, rFirstPoint, nLineID++ );
    }

    return pImplRegion;
}


} // end of anonymous namespace


// -----------------------------------------------------------------------

#ifdef DBG_UTIL
const char* ImplDbgTestRegion( const void* pObj )
{
	Region* 	  pRegion = (Region*)pObj;
	ImplRegion*   pImplRegion = pRegion->ImplGetImplRegion();

	if ( aImplNullRegion.mnRefCount )
		return "Null-Region-RefCount modified";
	if ( aImplNullRegion.mnRectCount )
		return "Null-Region-RectCount modified";
	if ( aImplNullRegion.mpPolyPoly )
		return "Null-Region-PolyPoly modified";
	if ( aImplEmptyRegion.mnRefCount )
		return "Emptry-Region-RefCount modified";
	if ( aImplEmptyRegion.mnRectCount )
		return "Emptry-Region-RectCount modified";
	if ( aImplEmptyRegion.mpPolyPoly )
		return "Emptry-Region-PolyPoly modified";

	if ( (pImplRegion != &aImplEmptyRegion) && (pImplRegion != &aImplNullRegion) )
	{
		sal_uLong					nCount = 0;
		const ImplRegionBand*	pBand = pImplRegion->ImplGetFirstRegionBand();
		while ( pBand )
		{
			if ( pBand->mnYBottom < pBand->mnYTop )
				return "YBottom < YTop";
			if ( pBand->mpNextBand )
			{
				if ( pBand->mnYBottom >= pBand->mpNextBand->mnYTop )
					return "overlapping bands in region";
			}
			if ( pBand->mbTouched > 1 )
				return "Band-mbTouched overwrite";

			ImplRegionBandSep* pSep = pBand->mpFirstSep;
			while ( pSep )
			{
				if ( pSep->mnXRight < pSep->mnXLeft )
					return "XLeft < XRight";
				if ( pSep->mpNextSep )
				{
					if ( pSep->mnXRight >= pSep->mpNextSep->mnXLeft )
						return "overlapping separations in region";
				}
				if ( pSep->mbRemoved > 1 )
					return "Sep-mbRemoved overwrite";

				nCount++;
				pSep = pSep->mpNextSep;
			}

			pBand = pBand->mpNextBand;
		}

		if ( pImplRegion->mnRectCount != nCount )
			return "mnRetCount is not valid";
	}

	return NULL;
}

void TraceBands (const ImplRegionBand* pFirstBand)
{
    int nBandIndex  (0);
    const ImplRegionBand* pBand = pFirstBand;
    while (pBand != NULL)
    {
        OSL_TRACE("            band %d  %d->%d : ", nBandIndex++,
            pBand->mnYTop, pBand->mnYBottom);

        ImplRegionBandPoint* pPoint = pBand->mpFirstBandPoint;
        while (pPoint != NULL)
        {
            OSL_TRACE(" %d ", pPoint->mnX);
            pPoint = pPoint->mpNextBandPoint;
        }
        OSL_TRACE("  |  ");

        ImplRegionBandSep* pSep = pBand->mpFirstSep;
        while (pSep != NULL)
        {
            OSL_TRACE(" %d->%d ", pSep->mnXLeft, pSep->mnXRight);
            pSep = pSep->mpNextSep;
        }
        OSL_TRACE("\n");

        pBand = pBand->mpNextBand;
    }
}
#endif

// =======================================================================

inline void Region::ImplPolyPolyRegionToBandRegion()
{
	if( mpImplRegion->mpPolyPoly || mpImplRegion->mpB2DPolyPoly )
		ImplPolyPolyRegionToBandRegionFunc();
}

// =======================================================================

ImplRegionBase::ImplRegionBase( int nRefCount )
:	mnRefCount( nRefCount )
,	mnRectCount( 0 )
,	mpPolyPoly( NULL )
,	mpB2DPolyPoly( NULL )
{}

// ------------------------------------------------------------------------

ImplRegion::ImplRegion()
{
	mpFirstBand 		= NULL;
	mpLastCheckedBand	= NULL;
}

// ------------------------------------------------------------------------

ImplRegion::ImplRegion( const PolyPolygon& rPolyPoly )
{
	mpFirstBand 		= NULL;
	mpLastCheckedBand	= NULL;
	mpPolyPoly			= new PolyPolygon( rPolyPoly );
}

// ------------------------------------------------------------------------

ImplRegion::ImplRegion( const basegfx::B2DPolyPolygon& rPolyPoly )
{
	mpFirstBand = NULL;
	mpLastCheckedBand = NULL;
	mpB2DPolyPoly = new basegfx::B2DPolyPolygon( rPolyPoly );
}

// -----------------------------------------------------------------------

ImplRegion::ImplRegion( const ImplRegion& rImplRegion )
:	ImplRegionBase()
{
	mpFirstBand = NULL;
	mpLastCheckedBand = NULL;
	mnRectCount = rImplRegion.mnRectCount;

	if ( rImplRegion.mpPolyPoly )
		mpPolyPoly = new PolyPolygon( *rImplRegion.mpPolyPoly );
	else if( rImplRegion.mpB2DPolyPoly )
		mpB2DPolyPoly = new basegfx::B2DPolyPolygon( *rImplRegion.mpB2DPolyPoly );

	// insert band(s) into the list
	ImplRegionBand* pNewBand;
	ImplRegionBand* pPrevBand = 0;
	ImplRegionBand* pBand = rImplRegion.mpFirstBand;
	while ( pBand )
	{
		pNewBand = new ImplRegionBand( *pBand );

		// first element? -> set as first into the list
		if ( pBand == rImplRegion.mpFirstBand )
			mpFirstBand = pNewBand;
		else
			pPrevBand->mpNextBand = pNewBand;

		pPrevBand = pNewBand;
		pBand = pBand->mpNextBand;
	}
}

// -----------------------------------------------------------------------

ImplRegion::~ImplRegion()
{
	DBG_ASSERT( (this != &aImplEmptyRegion) && (this != &aImplNullRegion),
				"ImplRegion::~ImplRegion() - Empty oder NULL-Region" );

	ImplRegionBand* pBand = mpFirstBand;
	while ( pBand )
	{
		ImplRegionBand* pTempBand = pBand->mpNextBand;
		delete pBand;
		pBand = pTempBand;
	}
}

// -----------------------------------------------------------------------

ImplRegionBase::~ImplRegionBase()
{
	delete mpPolyPoly;
	delete mpB2DPolyPoly;
}

// -----------------------------------------------------------------------
//
// create complete range of bands in single steps

void ImplRegion::CreateBandRange( long nYTop, long nYBottom )
{
	// add top band
	mpFirstBand = new ImplRegionBand( nYTop-1, nYTop-1 );

	// begin first search from the first element
	mpLastCheckedBand = mpFirstBand;

	ImplRegionBand* pBand = mpFirstBand;
	for ( int i = nYTop; i <= nYBottom+1; i++ )
	{
		// create new band
		ImplRegionBand* pNewBand = new ImplRegionBand( i, i );
		pBand->mpNextBand = pNewBand;
		if ( pBand != mpFirstBand )
			pNewBand->mpPrevBand = pBand;

		pBand = pBand->mpNextBand;
	}
}

// -----------------------------------------------------------------------

sal_Bool ImplRegion::InsertLine( const Point& rStartPt, const Point& rEndPt,
							 long nLineId )
{
	long nX, nY;

	// lines consisting of a single point do not interest here
	if ( rStartPt == rEndPt )
		return sal_True;

	LineType eLineType = (rStartPt.Y() > rEndPt.Y()) ? LINE_DESCENDING : LINE_ASCENDING;
	if ( rStartPt.X() == rEndPt.X() )
	{
		// vertical line
		const long nEndY = rEndPt.Y();

		nX = rStartPt.X();
		nY = rStartPt.Y();

		if( nEndY > nY )
		{
			for ( ; nY <= nEndY; nY++ )
			{
				Point aNewPoint( nX, nY );
				InsertPoint( aNewPoint, nLineId,
							 (aNewPoint == rEndPt) || (aNewPoint == rStartPt),
							 eLineType );
			}
		}
		else
		{
			for ( ; nY >= nEndY; nY-- )
			{
				Point aNewPoint( nX, nY );
				InsertPoint( aNewPoint, nLineId,
							 (aNewPoint == rEndPt) || (aNewPoint == rStartPt),
							 eLineType );
			}
		}
	}
	else if ( rStartPt.Y() != rEndPt.Y() )
	{
		const long	nDX = labs( rEndPt.X() - rStartPt.X() );
		const long	nDY = labs( rEndPt.Y() - rStartPt.Y() );
		const long	nStartX = rStartPt.X();
		const long	nStartY = rStartPt.Y();
		const long	nEndX = rEndPt.X();
		const long	nEndY = rEndPt.Y();
		const long	nXInc = ( nStartX < nEndX ) ? 1L : -1L;
		const long	nYInc = ( nStartY < nEndY ) ? 1L : -1L;

		if ( nDX >= nDY )
		{
			const long	nDYX = ( nDY - nDX ) << 1;
			const long	nDY2 = nDY << 1;
			long		nD = nDY2 - nDX;

			for ( nX = nStartX, nY = nStartY; nX != nEndX; nX += nXInc )
			{
				InsertPoint( Point( nX, nY ), nLineId, nStartX == nX, eLineType );

				if ( nD < 0L )
					nD += nDY2;
				else
					nD += nDYX, nY += nYInc;
			}
		}
		else
		{
			const long	nDYX = ( nDX - nDY ) << 1;
			const long	nDY2 = nDX << 1;
			long		nD = nDY2 - nDY;

			for ( nX = nStartX, nY = nStartY; nY != nEndY; nY += nYInc )
			{
				InsertPoint( Point( nX, nY ), nLineId, nStartY == nY, eLineType );

				if ( nD < 0L )
					nD += nDY2;
				else
					nD += nDYX, nX += nXInc;
			}
		}

		// last point
		InsertPoint( Point( nEndX, nEndY ), nLineId, sal_True, eLineType );
	}

	return sal_True;
}

// -----------------------------------------------------------------------
//
// search for appropriate place for the new point

sal_Bool ImplRegion::InsertPoint( const Point &rPoint, long nLineID,
							  sal_Bool bEndPoint, LineType eLineType )
{
	DBG_ASSERT( mpFirstBand != NULL, "ImplRegion::InsertPoint - no bands available!" );

	if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
	{
		mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
		return sal_True;
	}

	if ( rPoint.Y() > mpLastCheckedBand->mnYTop )
	{
		// Search ascending
		while ( mpLastCheckedBand )
		{
			// Insert point if possible
			if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
			{
				mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
				return sal_True;
			}

			mpLastCheckedBand = mpLastCheckedBand->mpNextBand;
		}

		DBG_ERROR( "ImplRegion::InsertPoint reached the end of the list!" );
	}
	else
	{
		// Search descending
		while ( mpLastCheckedBand )
		{
			// Insert point if possible
			if ( rPoint.Y() == mpLastCheckedBand->mnYTop )
			{
				mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType );
				return sal_True;
			}

			mpLastCheckedBand = mpLastCheckedBand->mpPrevBand;
		}

		DBG_ERROR( "ImplRegion::InsertPoint reached the beginning of the list!" );
	}

	DBG_ERROR( "ImplRegion::InsertPoint point not inserted!" );

	// reinitialize pointer (should never be reached!)
	mpLastCheckedBand = mpFirstBand;

	return sal_False;
}

// -----------------------------------------------------------------------
//
// search for appropriate places for the new bands

void ImplRegion::InsertBands( long nTop, long nBottom )
{
	// region empty? -> set rectagle as first entry!
	if ( !mpFirstBand )
	{
		// add band with boundaries of the rectangle
		mpFirstBand = new ImplRegionBand( nTop, nBottom );
		return;
	}

	// find/insert bands for the boundaries of the rectangle
	sal_Bool bTopBoundaryInserted = sal_False;
	sal_Bool bTop2BoundaryInserted = sal_False;
	sal_Bool bBottomBoundaryInserted = sal_False;

	// special case: top boundary is above the first band
	ImplRegionBand* pNewBand;
	if ( nTop < mpFirstBand->mnYTop )
	{
		// create new band above the first in the list
		pNewBand = new ImplRegionBand( nTop, mpFirstBand->mnYTop );
		if ( nBottom < mpFirstBand->mnYTop )
			pNewBand->mnYBottom = nBottom;

		// insert band into the list
		pNewBand->mpNextBand = mpFirstBand;
		mpFirstBand = pNewBand;

		bTopBoundaryInserted = sal_True;
	}

	// insert band(s) into the list
	ImplRegionBand* pBand = mpFirstBand;
	while ( pBand )
	{
		// Insert Bands if possible
		if ( !bTopBoundaryInserted )
			bTopBoundaryInserted = InsertSingleBand( pBand, nTop - 1 );

		if ( !bTop2BoundaryInserted )
			bTop2BoundaryInserted = InsertSingleBand( pBand, nTop );

		if ( !bBottomBoundaryInserted && (nTop != nBottom) )
			bBottomBoundaryInserted = InsertSingleBand( pBand, nBottom );

		// both boundaries inserted? -> nothing more to do
		if ( bTopBoundaryInserted && bTop2BoundaryInserted && bBottomBoundaryInserted )
			break;

		// insert bands between two bands if neccessary
		if ( pBand->mpNextBand )
		{
			if ( (pBand->mnYBottom + 1) < pBand->mpNextBand->mnYTop )
			{
				// copy band with list and set new boundary
				pNewBand = new ImplRegionBand( pBand->mnYBottom+1,
											   pBand->mpNextBand->mnYTop-1 );

				// insert band into the list
				pNewBand->mpNextBand = pBand->mpNextBand;
				pBand->mpNextBand = pNewBand;
			}
		}

		pBand = pBand->mpNextBand;
	}
}

// -----------------------------------------------------------------------
//
// create new band and insert it into the list

sal_Bool ImplRegion::InsertSingleBand( ImplRegionBand* pBand,
								   long nYBandPosition )
{
	// boundary already included in band with height 1? -> nothing to do!
	if ( (pBand->mnYTop == pBand->mnYBottom) &&
		 (nYBandPosition == pBand->mnYTop) )
		return sal_True;

	// insert single height band on top?
	ImplRegionBand* pNewBand;
	if ( nYBandPosition == pBand->mnYTop )
	{
		// copy band with list and set new boundary
		pNewBand = new ImplRegionBand( *pBand );
		pNewBand->mnYTop = nYBandPosition+1;

		// insert band into the list
		pNewBand->mpNextBand = pBand->mpNextBand;
		pBand->mnYBottom = nYBandPosition;
		pBand->mpNextBand = pNewBand;

		return sal_True;
	}

	// top of new rectangle within the current band? -> insert new band and copy data
	if ( (nYBandPosition > pBand->mnYTop) &&
		 (nYBandPosition < pBand->mnYBottom) )
	{
		// copy band with list and set new boundary
		pNewBand = new ImplRegionBand( *pBand );
		pNewBand->mnYTop = nYBandPosition;

		// insert band into the list
		pNewBand->mpNextBand = pBand->mpNextBand;
		pBand->mnYBottom = nYBandPosition;
		pBand->mpNextBand = pNewBand;

		// copy band with list and set new boundary
		pNewBand = new ImplRegionBand( *pBand );
		pNewBand->mnYTop = nYBandPosition;

		// insert band into the list
		pBand->mpNextBand->mnYTop = nYBandPosition+1;

		pNewBand->mpNextBand = pBand->mpNextBand;
		pBand->mnYBottom = nYBandPosition - 1;
		pBand->mpNextBand = pNewBand;

		return sal_True;
	}

	// create new band behind the current in the list
	if ( !pBand->mpNextBand )
	{
		if ( nYBandPosition == pBand->mnYBottom )
		{
			// copy band with list and set new boundary
			pNewBand = new ImplRegionBand( *pBand );
			pNewBand->mnYTop = pBand->mnYBottom;
			pNewBand->mnYBottom = nYBandPosition;

			pBand->mnYBottom = nYBandPosition-1;

			// append band to the list
			pBand->mpNextBand = pNewBand;
			return sal_True;
		}

		if ( nYBandPosition > pBand->mnYBottom )
		{
			// create new band
			pNewBand = new ImplRegionBand( pBand->mnYBottom + 1, nYBandPosition );

			// append band to the list
			pBand->mpNextBand = pNewBand;
			return sal_True;
		}
	}

	return sal_False;
}

// ------------------------------------------------------------------------

void ImplRegion::InsertBand (ImplRegionBand* pPreviousBand, ImplRegionBand* pBandToInsert)
{
    OSL_ASSERT(pBandToInsert!=NULL);

    if (pPreviousBand == NULL)
    {
        // Insert band before all others.
        if (mpFirstBand != NULL)
            mpFirstBand->mpPrevBand = pBandToInsert;
        pBandToInsert->mpNextBand = mpFirstBand;
        mpFirstBand = pBandToInsert;
    }
    else
    {
        // Insert band directly after pPreviousBand.
        pBandToInsert->mpNextBand = pPreviousBand->mpNextBand;
        pPreviousBand->mpNextBand = pBandToInsert;
        pBandToInsert->mpPrevBand = pPreviousBand;
    }
}

// ------------------------------------------------------------------------

void ImplRegion::Union( long nLeft, long nTop, long nRight, long nBottom )
{
	DBG_ASSERT( nLeft <= nRight, "ImplRegion::Union() - nLeft > nRight" );
	DBG_ASSERT( nTop <= nBottom, "ImplRegion::Union() - nTop > nBottom" );

	// process union
	ImplRegionBand* pBand = mpFirstBand;
	while ( pBand )
	{
		if ( pBand->mnYTop >= nTop )
		{
			if ( pBand->mnYBottom <= nBottom )
				pBand->Union( nLeft, nRight );
			else
			{
#ifdef DBG_UTIL
				long nCurY = pBand->mnYBottom;
				pBand = pBand->mpNextBand;
				while ( pBand )
				{
					if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) )
					{
						DBG_ERROR( "ImplRegion::Union() - Bands not sorted!" );
					}
					pBand = pBand->mpNextBand;
				}
#endif
				break;
			}
		}

		pBand = pBand->mpNextBand;
	}
}

// -----------------------------------------------------------------------

void ImplRegion::Exclude( long nLeft, long nTop, long nRight, long nBottom )
{
	DBG_ASSERT( nLeft <= nRight, "ImplRegion::Exclude() - nLeft > nRight" );
	DBG_ASSERT( nTop <= nBottom, "ImplRegion::Exclude() - nTop > nBottom" );

	// process exclude
	ImplRegionBand* pBand = mpFirstBand;
	while ( pBand )
	{
		if ( pBand->mnYTop >= nTop )
		{
			if ( pBand->mnYBottom <= nBottom )
				pBand->Exclude( nLeft, nRight );
			else
			{
#ifdef DBG_UTIL
				long nCurY = pBand->mnYBottom;
				pBand = pBand->mpNextBand;
				while ( pBand )
				{
					if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) )
					{
						DBG_ERROR( "ImplRegion::Exclude() - Bands not sorted!" );
					}
					pBand = pBand->mpNextBand;
				}
#endif
				break;
			}
		}

		pBand = pBand->mpNextBand;
	}
}

// -----------------------------------------------------------------------

void ImplRegion::XOr( long nLeft, long nTop, long nRight, long nBottom )
{
	DBG_ASSERT( nLeft <= nRight, "ImplRegion::Exclude() - nLeft > nRight" );
	DBG_ASSERT( nTop <= nBottom, "ImplRegion::Exclude() - nTop > nBottom" );

	// process xor
	ImplRegionBand* pBand = mpFirstBand;
	while ( pBand )
	{
		if ( pBand->mnYTop >= nTop )
		{
			if ( pBand->mnYBottom <= nBottom )
				pBand->XOr( nLeft, nRight );
			else
			{
#ifdef DBG_UTIL
				long nCurY = pBand->mnYBottom;
				pBand = pBand->mpNextBand;
				while ( pBand )
				{
					if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) )
					{
						DBG_ERROR( "ImplRegion::XOr() - Bands not sorted!" );
					}
					pBand = pBand->mpNextBand;
				}
#endif
				break;
			}
		}

		pBand = pBand->mpNextBand;
	}
}

// -----------------------------------------------------------------------
//
// remove empty bands

sal_Bool ImplRegion::OptimizeBandList()
{
	DBG_ASSERT( (this != &aImplNullRegion) && (this != &aImplEmptyRegion),
				"ImplRegion::OptimizeBandList() - Empty oder NULL-Region" );

	mnRectCount = 0;

	ImplRegionBand* pPrevBand = 0;
	ImplRegionBand* pBand = mpFirstBand;
	while ( pBand )
	{
		const sal_Bool bBTEqual = pBand->mpNextBand &&
							  (pBand->mnYBottom == pBand->mpNextBand->mnYTop);

		// no separation? -> remove!
		if ( pBand->IsEmpty() || (bBTEqual && (pBand->mnYBottom == pBand->mnYTop)) )
		{
			// save pointer
			ImplRegionBand* pOldBand = pBand;

			// previous element of the list
			if ( pBand == mpFirstBand )
				mpFirstBand = pBand->mpNextBand;
			else
				pPrevBand->mpNextBand = pBand->mpNextBand;

			pBand = pBand->mpNextBand;
			delete pOldBand;
		}
		else
		{
			// fixup
			if ( bBTEqual )
				pBand->mnYBottom = pBand->mpNextBand->mnYTop-1;

			// this and next band with equal separations? -> combine!
			if ( pBand->mpNextBand &&
				 ((pBand->mnYBottom+1) == pBand->mpNextBand->mnYTop) &&
				 (*pBand == *pBand->mpNextBand) )
			{
				// expand current height
				pBand->mnYBottom = pBand->mpNextBand->mnYBottom;

				// remove next band from list
				ImplRegionBand* pDeletedBand = pBand->mpNextBand;
				pBand->mpNextBand = pDeletedBand->mpNextBand;
				delete pDeletedBand;

				// check band again!
			}
			else
			{
				// count rectangles within band
				ImplRegionBandSep* pSep = pBand->mpFirstSep;
				while ( pSep )
				{
					mnRectCount++;
					pSep = pSep->mpNextSep;
				}

				pPrevBand = pBand;
				pBand = pBand->mpNextBand;
			}
		}
	}

#ifdef DBG_UTIL
	pBand = mpFirstBand;
	while ( pBand )
	{
		DBG_ASSERT( pBand->mpFirstSep != NULL,
					"Exiting ImplRegion::OptimizeBandList(): empty band in region!" );

		if ( pBand->mnYBottom < pBand->mnYTop )
			DBG_ERROR( "ImplRegion::OptimizeBandList(): YBottomBoundary < YTopBoundary" );

		if ( pBand->mpNextBand )
		{
			if ( pBand->mnYBottom >= pBand->mpNextBand->mnYTop )
				DBG_ERROR( "ImplRegion::OptimizeBandList(): overlapping bands in region!" );
		}

		pBand = pBand->mpNextBand;
	}
#endif

	return (mnRectCount != 0);
}

// =======================================================================

void Region::ImplCopyData()
{
	mpImplRegion->mnRefCount--;
	mpImplRegion = new ImplRegion( *mpImplRegion );
}

// =======================================================================

Region::Region()
{
	DBG_CTOR( Region, ImplDbgTestRegion );

	mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
}

// -----------------------------------------------------------------------

Region::Region( RegionType eType )
{
	DBG_CTOR( Region, ImplDbgTestRegion );
	DBG_ASSERT( (eType == REGION_NULL) || (eType == REGION_EMPTY),
				"Region( RegionType ) - RegionType != EMPTY/NULL" );

	if ( eType == REGION_NULL )
		mpImplRegion = (ImplRegion*)(&aImplNullRegion);
	else
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
}

// -----------------------------------------------------------------------

Region::Region( const Rectangle& rRect )
{
	DBG_CTOR( Region, ImplDbgTestRegion );

	ImplCreateRectRegion( rRect );
}

// -----------------------------------------------------------------------

Region::Region( const Polygon& rPolygon )
{
	DBG_CTOR( Region, ImplDbgTestRegion );
	DBG_CHKOBJ( &rPolygon, Polygon, NULL );

	ImplCreatePolyPolyRegion( rPolygon );
}

// -----------------------------------------------------------------------

Region::Region( const PolyPolygon& rPolyPoly )
{
	DBG_CTOR( Region, ImplDbgTestRegion );
	DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );

	ImplCreatePolyPolyRegion( rPolyPoly );
}

// -----------------------------------------------------------------------

Region::Region( const basegfx::B2DPolyPolygon& rPolyPoly )
{
	DBG_CTOR( Region, ImplDbgTestRegion );
	DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );

	mpImplRegion = new ImplRegion( rPolyPoly );
}

// -----------------------------------------------------------------------

Region::Region( const Region& rRegion )
{
	DBG_CTOR( Region, ImplDbgTestRegion );
	DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
	DBG_ASSERT( rRegion.mpImplRegion->mnRefCount < 0xFFFFFFFE, "Region: RefCount overflow" );

	// copy pointer to instance of implementation
	mpImplRegion = rRegion.mpImplRegion;
	if ( mpImplRegion->mnRefCount )
		mpImplRegion->mnRefCount++;
}

// -----------------------------------------------------------------------

Region::~Region()
{
	DBG_DTOR( Region, ImplDbgTestRegion );

	// statische Object haben RefCount von 0
	if ( mpImplRegion->mnRefCount )
	{
		if ( mpImplRegion->mnRefCount > 1 )
			mpImplRegion->mnRefCount--;
		else
			delete mpImplRegion;
	}
}

// -----------------------------------------------------------------------

void Region::ImplCreateRectRegion( const Rectangle& rRect )
{
	if ( rRect.IsEmpty() )
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
	else
	{
		// get justified rectangle
		long nTop		= Min( rRect.Top(), rRect.Bottom() );
		long nBottom	= Max( rRect.Top(), rRect.Bottom() );
		long nLeft		= Min( rRect.Left(), rRect.Right() );
		long nRight 	= Max( rRect.Left(), rRect.Right() );

		// create instance of implementation class
		mpImplRegion = new ImplRegion();

		// add band with boundaries of the rectangle
		mpImplRegion->mpFirstBand = new ImplRegionBand( nTop, nBottom );

		// Set left and right boundaries of the band
		mpImplRegion->mpFirstBand->Union( nLeft, nRight );
		mpImplRegion->mnRectCount = 1;
	}
}

// -----------------------------------------------------------------------

void Region::ImplCreatePolyPolyRegion( const PolyPolygon& rPolyPoly )
{
	const sal_uInt16 nPolyCount = rPolyPoly.Count();
	if ( nPolyCount )
	{
		// polypolygon empty? -> empty region
		const Rectangle aRect( rPolyPoly.GetBoundRect() );

		if ( !aRect.IsEmpty() )
		{
			// width OR height == 1 ? => Rectangular region
			if ( (aRect.GetWidth() == 1)
                || (aRect.GetHeight() == 1)
                || rPolyPoly.IsRect() )
            {
				ImplCreateRectRegion( aRect );
            }
			else
				mpImplRegion = new ImplRegion( rPolyPoly );
		}
		else
			mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
	}
	else
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
}

// -----------------------------------------------------------------------

void Region::ImplPolyPolyRegionToBandRegionFunc()
{
    // ensure to subdivide when bezier segemnts are used, it's going to
    // be expanded to rectangles
	PolyPolygon aPolyPoly;
    GetPolyPolygon().AdaptiveSubdivide(aPolyPoly);

	if ( mpImplRegion->mnRefCount > 1 )
		mpImplRegion->mnRefCount--;
	else
		delete mpImplRegion;

	if ( aPolyPoly.Count() )
	{
		// polypolygon empty? -> empty region
		const Rectangle aRect( aPolyPoly.GetBoundRect() );

		if ( !aRect.IsEmpty() )
		{
            if (ImplIsPolygonRectilinear(aPolyPoly))
            {
                // For rectilinear polygons there is an optimized band conversion.
                mpImplRegion = ImplRectilinearPolygonToBands(aPolyPoly);
            }
            else
            {
                mpImplRegion = ImplGeneralPolygonToBands(aPolyPoly, aRect);
            }

            // Convert points into seps.
			ImplRegionBand* pRegionBand = mpImplRegion->mpFirstBand;
			while ( pRegionBand )
			{
				// generate separations from the lines and process union
				pRegionBand->ProcessPoints();
				pRegionBand = pRegionBand->mpNextBand;
			}

            // Optimize list of bands.  Adjacent bands with identical lists
            // of seps are joined.
			if ( !mpImplRegion->OptimizeBandList() )
			{
				delete mpImplRegion;
				mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
			}
		}
		else
			mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
	}
	else
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
}

// -----------------------------------------------------------------------

void Region::Move( long nHorzMove, long nVertMove )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// no region data? -> nothing to do
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return;

	// no own instance data? -> make own copy!
	if ( mpImplRegion->mnRefCount > 1 )
		ImplCopyData();

	if ( mpImplRegion->mpPolyPoly )
		mpImplRegion->mpPolyPoly->Move( nHorzMove, nVertMove );
	else if( mpImplRegion->mpB2DPolyPoly )
	{
        mpImplRegion->mpB2DPolyPoly->transform(basegfx::tools::createTranslateB2DHomMatrix(nHorzMove, nVertMove));
	}
	else
	{
		ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
		while ( pBand )
		{
			// process the vertical move
			if ( nVertMove != 0)
			{
				pBand->mnYTop = pBand->mnYTop + nVertMove;
				pBand->mnYBottom = pBand->mnYBottom + nVertMove;
			}

			// process the horizontal move
			if ( nHorzMove != 0)
				pBand->MoveX( nHorzMove );

			pBand = pBand->mpNextBand;
		}
	}
}

// -----------------------------------------------------------------------

void Region::Scale( double fScaleX, double fScaleY )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// no region data? -> nothing to do
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return;

	// no own instance data? -> make own copy!
	if ( mpImplRegion->mnRefCount > 1 )
		ImplCopyData();

	if ( mpImplRegion->mpPolyPoly )
		mpImplRegion->mpPolyPoly->Scale( fScaleX, fScaleY );
	else if( mpImplRegion->mpB2DPolyPoly )
	{
		mpImplRegion->mpB2DPolyPoly->transform(basegfx::tools::createScaleB2DHomMatrix(fScaleX, fScaleY));
	}
	else
	{
		ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
		while ( pBand )
		{
			// process the vertical move
			if ( fScaleY != 0.0 )
			{
				pBand->mnYTop = FRound( pBand->mnYTop * fScaleY );
				pBand->mnYBottom = FRound( pBand->mnYBottom * fScaleY );
			}

			// process the horizontal move
			if ( fScaleX != 0.0 )
				pBand->ScaleX( fScaleX );

			pBand = pBand->mpNextBand;
		}
	}
}

// -----------------------------------------------------------------------

sal_Bool Region::Union( const Rectangle& rRect )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// is rectangle empty? -> nothing to do
	if ( rRect.IsEmpty() )
		return sal_True;

	if( HasPolyPolygon() )
	{
	    // get this B2DPolyPolygon
	    basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
	    aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
	    
	    if( aThisPolyPoly.count() == 0 )
	    {
	        *this = rRect;
	        return true;
	    }

        // get the other B2DPolyPolygon
        basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) );
        basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly );
        
        basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationOr( aThisPolyPoly, aOtherPolyPoly );        
        *this = Region( aClip );

	    return sal_True;
	}

	ImplPolyPolyRegionToBandRegion();

	// no instance data? -> create!
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		mpImplRegion = new ImplRegion();

	// no own instance data? -> make own copy!
	if ( mpImplRegion->mnRefCount > 1 )
		ImplCopyData();

	// get justified rectangle
	long nLeft		= Min( rRect.Left(), rRect.Right() );
	long nTop		= Min( rRect.Top(), rRect.Bottom() );
	long nRight 	= Max( rRect.Left(), rRect.Right() );
	long nBottom	= Max( rRect.Top(), rRect.Bottom() );

	// insert bands if the boundaries are not allready in the list
	mpImplRegion->InsertBands( nTop, nBottom );

	// process union
	mpImplRegion->Union( nLeft, nTop, nRight, nBottom );

	// cleanup
	if ( !mpImplRegion->OptimizeBandList() )
	{
		delete mpImplRegion;
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
	}

	return sal_True;
}

// -----------------------------------------------------------------------

sal_Bool Region::Intersect( const Rectangle& rRect )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// is rectangle empty? -> nothing to do
	if ( rRect.IsEmpty() )
	{
		// statische Object haben RefCount von 0
		if ( mpImplRegion->mnRefCount )
		{
			if ( mpImplRegion->mnRefCount > 1 )
				mpImplRegion->mnRefCount--;
			else
				delete mpImplRegion;
		}
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
		return sal_True;
	}

    // #103137# Avoid banding for special cases
    if ( mpImplRegion->mpPolyPoly )
    {
        // #127431# make ImplRegion unique, if not already.
		if( mpImplRegion->mnRefCount > 1 )
        {
            mpImplRegion->mnRefCount--;
            mpImplRegion = new ImplRegion( *mpImplRegion->mpPolyPoly );
        }

        // use the PolyPolygon::Clip method for rectangles, this is
        // fairly simple (does not even use GPC) and saves us from
        // unnecessary banding
        mpImplRegion->mpPolyPoly->Clip( rRect );

        // The clipping above may lead to empty ClipRegion
        if(!mpImplRegion->mpPolyPoly->Count())
        {
            // react on empty ClipRegion; ImplRegion already is unique (see above)
            delete mpImplRegion;
            mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
        }

        return sal_True;
    }
    else if( mpImplRegion->mpB2DPolyPoly )
    {
        // #127431# make ImplRegion unique, if not already.
		if( mpImplRegion->mnRefCount > 1 )
        {
            mpImplRegion->mnRefCount--;
            mpImplRegion = new ImplRegion( *mpImplRegion->mpB2DPolyPoly );
        }

        *mpImplRegion->mpB2DPolyPoly =
            basegfx::tools::clipPolyPolygonOnRange(
                *mpImplRegion->mpB2DPolyPoly,
                basegfx::B2DRange( 
                    rRect.Left(), 
                    rRect.Top(),
                    rRect.Right() + 1, 
                    rRect.Bottom() + 1),
                true, 
                false);

        // The clipping above may lead to empty ClipRegion
        if(!mpImplRegion->mpB2DPolyPoly->count())
        {
            // react on empty ClipRegion; ImplRegion already is unique (see above)
            delete mpImplRegion;
            mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
        }

        return sal_True;
    }
    else
        ImplPolyPolyRegionToBandRegion();

	// is region empty? -> nothing to do!
	if ( mpImplRegion == &aImplEmptyRegion )
		return sal_True;

	// get justified rectangle
	long nLeft		= Min( rRect.Left(), rRect.Right() );
	long nTop		= Min( rRect.Top(), rRect.Bottom() );
	long nRight 	= Max( rRect.Left(), rRect.Right() );
	long nBottom	= Max( rRect.Top(), rRect.Bottom() );

	// is own region NULL-region? -> copy data!
	if ( mpImplRegion == &aImplNullRegion )
	{
		// create instance of implementation class
		mpImplRegion = new ImplRegion();

		// add band with boundaries of the rectangle
		mpImplRegion->mpFirstBand = new ImplRegionBand( nTop, nBottom );

		// Set left and right boundaries of the band
		mpImplRegion->mpFirstBand->Union( nLeft, nRight );
		mpImplRegion->mnRectCount = 1;

		return sal_True;
	}

	// no own instance data? -> make own copy!
	if ( mpImplRegion->mnRefCount > 1 )
		ImplCopyData();

	// insert bands if the boundaries are not allready in the list
	mpImplRegion->InsertBands( nTop, nBottom );

	// process intersections
	ImplRegionBand* pPrevBand = 0;
	ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
	while ( pBand )
	{
		// band within intersection boundary? -> process. otherwise remove
		if ( (pBand->mnYTop >= nTop) &&
			 (pBand->mnYBottom <= nBottom) )
		{
			// process intersection
			pBand->Intersect( nLeft, nRight );

			pPrevBand = pBand;
			pBand = pBand->mpNextBand;
		}
		else
		{
			ImplRegionBand* pOldBand = pBand;
			if ( pBand == mpImplRegion->mpFirstBand )
				mpImplRegion->mpFirstBand = pBand->mpNextBand;
			else
				pPrevBand->mpNextBand = pBand->mpNextBand;
			pBand = pBand->mpNextBand;
			delete pOldBand;
		}
	}

	// cleanup
	if ( !mpImplRegion->OptimizeBandList() )
	{
		delete mpImplRegion;
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
	}

	return sal_True;
}

// -----------------------------------------------------------------------

sal_Bool Region::Exclude( const Rectangle& rRect )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// is rectangle empty? -> nothing to do
	if ( rRect.IsEmpty() )
		return sal_True;

	if( HasPolyPolygon() )
	{
	    // get this B2DPolyPolygon
	    basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
	    aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
	    
	    if( aThisPolyPoly.count() == 0 )
	        return sal_True;
	    
	    // get the other B2DPolyPolygon
	    basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) );
	    basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly );
	    
	    basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly );	    
	    *this = Region( aClip );

	    return sal_True;
	}

	ImplPolyPolyRegionToBandRegion();

	// no instance data? -> create!
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return sal_True;

	// no own instance data? -> make own copy!
	if ( mpImplRegion->mnRefCount > 1 )
		ImplCopyData();

	// get justified rectangle
	long nLeft		= Min( rRect.Left(), rRect.Right() );
	long nTop		= Min( rRect.Top(), rRect.Bottom() );
	long nRight 	= Max( rRect.Left(), rRect.Right() );
	long nBottom	= Max( rRect.Top(), rRect.Bottom() );

	// insert bands if the boundaries are not allready in the list
	mpImplRegion->InsertBands( nTop, nBottom );

	// process exclude
	mpImplRegion->Exclude( nLeft, nTop, nRight, nBottom );

	// cleanup
	if ( !mpImplRegion->OptimizeBandList() )
	{
		delete mpImplRegion;
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
	}

	return sal_True;
}

// -----------------------------------------------------------------------

sal_Bool Region::XOr( const Rectangle& rRect )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// is rectangle empty? -> nothing to do
	if ( rRect.IsEmpty() )
		return sal_True;

	if( HasPolyPolygon() )
	{
	    // get this B2DPolyPolygon
	    basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
	    aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
	    
	    if( aThisPolyPoly.count() == 0 )
	    {
	        *this = rRect;
	        return sal_True;
	    }
	    
	    // get the other B2DPolyPolygon
	    basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) );
	    basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly );
	    
	    basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly );	    
	    *this = Region( aClip );

	    return sal_True;
	}

	ImplPolyPolyRegionToBandRegion();

	// no instance data? -> create!
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		mpImplRegion = new ImplRegion();

	// no own instance data? -> make own copy!
	if ( mpImplRegion->mnRefCount > 1 )
		ImplCopyData();

	// get justified rectangle
	long nLeft		= Min( rRect.Left(), rRect.Right() );
	long nTop		= Min( rRect.Top(), rRect.Bottom() );
	long nRight 	= Max( rRect.Left(), rRect.Right() );
	long nBottom	= Max( rRect.Top(), rRect.Bottom() );

	// insert bands if the boundaries are not allready in the list
	mpImplRegion->InsertBands( nTop, nBottom );

	// process xor
	mpImplRegion->XOr( nLeft, nTop, nRight, nBottom );

	// cleanup
	if ( !mpImplRegion->OptimizeBandList() )
	{
		delete mpImplRegion;
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
	}

	return sal_True;
}

// -----------------------------------------------------------------------
void Region::ImplUnionPolyPolygon( const Region& i_rRegion )
{
    // get this B2DPolyPolygon
    basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
    aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
    
    if( aThisPolyPoly.count() == 0 )
    {
        *this = i_rRegion;
        return;
    }

    // get the other B2DPolyPolygon
    basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() );
    aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
    
    
    basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationOr( aThisPolyPoly, aOtherPolyPoly );
    
    *this = Region( aClip );
}

sal_Bool Region::Union( const Region& rRegion )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	if( rRegion.HasPolyPolygon() || HasPolyPolygon() )
	{
	    ImplUnionPolyPolygon( rRegion );
	    return sal_True;
	}

	ImplPolyPolyRegionToBandRegion();
	((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();

	// is region empty or null? -> nothing to do
	if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
		return sal_True;

	// no instance data? -> create!
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		mpImplRegion = new ImplRegion();

	// no own instance data? -> make own copy!
	if ( mpImplRegion->mnRefCount > 1 )
		ImplCopyData();

	// Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
	ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand;
	while ( pBand )
	{
		// insert bands if the boundaries are not allready in the list
		mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );

		// process all elements of the list
		ImplRegionBandSep* pSep = pBand->mpFirstSep;
		while ( pSep )
		{
			mpImplRegion->Union( pSep->mnXLeft, pBand->mnYTop,
								 pSep->mnXRight, pBand->mnYBottom );
			pSep = pSep->mpNextSep;
		}

		pBand = pBand->mpNextBand;
	}

	// cleanup
	if ( !mpImplRegion->OptimizeBandList() )
	{
		delete mpImplRegion;
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
	}

	return sal_True;
}

// -----------------------------------------------------------------------
void Region::ImplIntersectWithPolyPolygon( const Region& i_rRegion )
{
    // get this B2DPolyPolygon
    basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
    if( aThisPolyPoly.count() == 0 )
    {
        *this = i_rRegion;
        return;
    }

    // get the other B2DPolyPolygon
    basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() );
    
    basegfx::B2DPolyPolygon aClip = basegfx::tools::clipPolyPolygonOnPolyPolygon( aOtherPolyPoly, aThisPolyPoly, true, false );
    *this = Region( aClip );
}

sal_Bool Region::Intersect( const Region& rRegion )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// same instance data? -> nothing to do!
	if ( mpImplRegion == rRegion.mpImplRegion )
		return sal_True;
	
	if( rRegion.HasPolyPolygon() || HasPolyPolygon() )
	{
	    ImplIntersectWithPolyPolygon( rRegion );
	    return sal_True;
	}
    
	ImplPolyPolyRegionToBandRegion();
	((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();

	if ( mpImplRegion == &aImplEmptyRegion )
		return sal_True;

	// is region null? -> nothing to do
	if ( rRegion.mpImplRegion == &aImplNullRegion )
		return sal_True;

	// is rectangle empty? -> nothing to do
	if ( rRegion.mpImplRegion == &aImplEmptyRegion )
	{
		// statische Object haben RefCount von 0
		if ( mpImplRegion->mnRefCount )
		{
			if ( mpImplRegion->mnRefCount > 1 )
				mpImplRegion->mnRefCount--;
			else
				delete mpImplRegion;
		}
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
		return sal_True;
	}

	// is own region NULL-region? -> copy data!
	if ( mpImplRegion == &aImplNullRegion)
	{
		mpImplRegion = rRegion.mpImplRegion;
		rRegion.mpImplRegion->mnRefCount++;
		return sal_True;
	}

	// Wenn wir weniger Rechtecke haben, drehen wir den Intersect-Aufruf um
	if ( mpImplRegion->mnRectCount+2 < rRegion.mpImplRegion->mnRectCount )
	{
		Region aTempRegion = rRegion;
		aTempRegion.Intersect( *this );
		*this = aTempRegion;
	}
	else
	{
		// no own instance data? -> make own copy!
		if ( mpImplRegion->mnRefCount > 1 )
			ImplCopyData();

		// mark all bands as untouched
		ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
		while ( pBand )
		{
			pBand->mbTouched = sal_False;
			pBand = pBand->mpNextBand;
		}

		pBand = rRegion.mpImplRegion->mpFirstBand;
		while ( pBand )
		{
			// insert bands if the boundaries are not allready in the list
			mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );

			// process all elements of the list
			ImplRegionBandSep* pSep = pBand->mpFirstSep;
			while ( pSep )
			{
				// left boundary?
				if ( pSep == pBand->mpFirstSep )
				{
					// process intersection and do not remove untouched bands
					mpImplRegion->Exclude( LONG_MIN+1, pBand->mnYTop,
										   pSep->mnXLeft-1, pBand->mnYBottom );
				}

				// right boundary?
				if ( pSep->mpNextSep == NULL )
				{
					// process intersection and do not remove untouched bands
					mpImplRegion->Exclude( pSep->mnXRight+1, pBand->mnYTop,
										   LONG_MAX-1, pBand->mnYBottom );
				}
				else
				{
					// process intersection and do not remove untouched bands
					mpImplRegion->Exclude( pSep->mnXRight+1, pBand->mnYTop,
										   pSep->mpNextSep->mnXLeft-1, pBand->mnYBottom );
				}

				pSep = pSep->mpNextSep;
			}

			pBand = pBand->mpNextBand;
		}

		// remove all untouched bands if bands allready left
		ImplRegionBand* pPrevBand = 0;
		pBand = mpImplRegion->mpFirstBand;
		while ( pBand )
		{
			if ( !pBand->mbTouched )
			{
				// save pointer
				ImplRegionBand* pOldBand = pBand;

				// previous element of the list
				if ( pBand == mpImplRegion->mpFirstBand )
					mpImplRegion->mpFirstBand = pBand->mpNextBand;
				else
					pPrevBand->mpNextBand = pBand->mpNextBand;

				pBand = pBand->mpNextBand;
				delete pOldBand;
			}
			else
			{
				pPrevBand = pBand;
				pBand = pBand->mpNextBand;
			}
		}

		// cleanup
		if ( !mpImplRegion->OptimizeBandList() )
		{
			delete mpImplRegion;
			mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
		}
	}

	return sal_True;
}

// -----------------------------------------------------------------------
void Region::ImplExcludePolyPolygon( const Region& i_rRegion )
{
    // get this B2DPolyPolygon
    basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
    if( aThisPolyPoly.count() == 0 )
        return;
    aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );

    // get the other B2DPolyPolygon
    basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() );
    aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
    
    basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly );
    *this = Region( aClip );
}

sal_Bool Region::Exclude( const Region& rRegion )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	if( rRegion.HasPolyPolygon() || HasPolyPolygon() )
	{
	    ImplExcludePolyPolygon( rRegion );
	    return sal_True;
	}

	ImplPolyPolyRegionToBandRegion();
	((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();

	// is region empty or null? -> nothing to do
	if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
		return sal_True;

	// no instance data? -> nothing to do
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return sal_True;

	// no own instance data? -> make own copy!
	if ( mpImplRegion->mnRefCount > 1 )
		ImplCopyData();

	// Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
	ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand;
	while ( pBand )
	{
		// insert bands if the boundaries are not allready in the list
		mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );

		// process all elements of the list
		ImplRegionBandSep* pSep = pBand->mpFirstSep;
		while ( pSep )
		{
			mpImplRegion->Exclude( pSep->mnXLeft, pBand->mnYTop,
								   pSep->mnXRight, pBand->mnYBottom );
			pSep = pSep->mpNextSep;
		}

		// Wir optimieren schon in der Schleife, da wir davon
		// ausgehen, das wir insgesammt weniger Baender ueberpruefen
		// muessen
		if ( !mpImplRegion->OptimizeBandList() )
		{
			delete mpImplRegion;
			mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
			break;
		}

		pBand = pBand->mpNextBand;
	}

	return sal_True;
}

// -----------------------------------------------------------------------
void Region::ImplXOrPolyPolygon( const Region& i_rRegion )
{
    // get this B2DPolyPolygon
    basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() );
    if( aThisPolyPoly.count() == 0 )
    {
        *this = i_rRegion;
        return;
    }
    aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );

    // get the other B2DPolyPolygon
    basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() );
    aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
    
    basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly );
    *this = Region( aClip );
}

sal_Bool Region::XOr( const Region& rRegion )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	if( rRegion.HasPolyPolygon() || HasPolyPolygon() )
	{
	    ImplXOrPolyPolygon( rRegion );
	    return sal_True;
	}

	ImplPolyPolyRegionToBandRegion();
	((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();

	// is region empty or null? -> nothing to do
	if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
		return sal_True;

	// no own instance data? -> XOr = copy
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
    {
        *this = rRegion;
		return sal_True;
    }

	// no own instance data? -> make own copy!
	if ( mpImplRegion->mnRefCount > 1 )
		ImplCopyData();

	// Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden
	ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand;
	while ( pBand )
	{
		// insert bands if the boundaries are not allready in the list
		mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom );

		// process all elements of the list
		ImplRegionBandSep* pSep = pBand->mpFirstSep;
		while ( pSep )
		{
			mpImplRegion->XOr( pSep->mnXLeft, pBand->mnYTop,
							   pSep->mnXRight, pBand->mnYBottom );
			pSep = pSep->mpNextSep;
		}

		pBand = pBand->mpNextBand;
	}

	// cleanup
	if ( !mpImplRegion->OptimizeBandList() )
	{
		delete mpImplRegion;
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
	}

	return sal_True;
}

// -----------------------------------------------------------------------

Rectangle Region::GetBoundRect() const
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	Rectangle aRect;

	// no internal data? -> region is empty!
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return aRect;

	// PolyPolygon data im Imp structure?
	if ( mpImplRegion->mpPolyPoly )
		return mpImplRegion->mpPolyPoly->GetBoundRect();
	if( mpImplRegion->mpB2DPolyPoly )
	{
		const basegfx::B2DRange aRange(basegfx::tools::getRange(*mpImplRegion->mpB2DPolyPoly));

        if(aRange.isEmpty())
        {
            // emulate PolyPolygon::GetBoundRect() when empty polygon
            return Rectangle();
        }
        else
        {
            return Rectangle(
                static_cast<sal_Int32>(floor(aRange.getMinX())), static_cast<sal_Int32>(floor(aRange.getMinY())),
                static_cast<sal_Int32>(ceil(aRange.getMaxX())), static_cast<sal_Int32>(ceil(aRange.getMaxY())));
        }
	}

	// no band in the list? -> region is empty!
	if ( !mpImplRegion->mpFirstBand )
		return aRect;

	// get the boundaries of the first band
	long nYTop	  = mpImplRegion->mpFirstBand->mnYTop;
	long nYBottom = mpImplRegion->mpFirstBand->mnYBottom;
	long nXLeft   = mpImplRegion->mpFirstBand->GetXLeftBoundary();
	long nXRight  = mpImplRegion->mpFirstBand->GetXRightBoundary();

	// look in the band list (don't test first band again!)
	ImplRegionBand* pBand = mpImplRegion->mpFirstBand->mpNextBand;
	while ( pBand )
	{
		nYBottom	= pBand->mnYBottom;
		nXLeft		= Min( nXLeft, pBand->GetXLeftBoundary() );
		nXRight 	= Max( nXRight, pBand->GetXRightBoundary() );

		pBand = pBand->mpNextBand;
	}

	// set rectangle
	aRect = Rectangle( nXLeft, nYTop, nXRight, nYBottom );
	return aRect;
}

// -----------------------------------------------------------------------

sal_Bool Region::HasPolyPolygon() const
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );
	if( !mpImplRegion )
		return false;
	if( mpImplRegion->mpPolyPoly )
		return true;
	if( mpImplRegion->mpB2DPolyPoly )
		return true;
    return false;
}

// -----------------------------------------------------------------------

PolyPolygon Region::GetPolyPolygon() const
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

    PolyPolygon aRet;

	if( mpImplRegion->mpPolyPoly )
        aRet = *mpImplRegion->mpPolyPoly;
    else if( mpImplRegion->mpB2DPolyPoly )
	{
		// the polygon needs to be converted
		aRet = PolyPolygon( *mpImplRegion->mpB2DPolyPoly );
		// TODO: cache the converted polygon?
		// mpImplRegion->mpB2DPolyPoly = aRet;
	}

    return aRet;
}

// -----------------------------------------------------------------------

const basegfx::B2DPolyPolygon Region::GetB2DPolyPolygon() const
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

    basegfx::B2DPolyPolygon aRet;

	if( mpImplRegion->mpB2DPolyPoly )
        aRet = *mpImplRegion->mpB2DPolyPoly;
    else if( mpImplRegion->mpPolyPoly )
	{
		// the polygon needs to be converted
		aRet = mpImplRegion->mpPolyPoly->getB2DPolyPolygon();
		// TODO: cache the converted polygon?
		// mpImplRegion->mpB2DPolyPoly = aRet;
	}
  
    return aRet;
}

// -----------------------------------------------------------------------

basegfx::B2DPolyPolygon Region::ConvertToB2DPolyPolygon()
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

    basegfx::B2DPolyPolygon aRet;

	if( HasPolyPolygon() )
        aRet = GetB2DPolyPolygon();
	else
	{
	    RegionHandle aHdl = BeginEnumRects();
	    Rectangle aSubRect;
	    while( GetNextEnumRect( aHdl, aSubRect ) )
	    {
	        basegfx::B2DPolygon aPoly( basegfx::tools::createPolygonFromRect(
                 basegfx::B2DRectangle( aSubRect.Left(), aSubRect.Top(), aSubRect.Right(), aSubRect.Bottom() ) ) );
	        aRet.append( aPoly );
	    }
	    EndEnumRects( aHdl );
	}
  
    return aRet;
}

// -----------------------------------------------------------------------

bool Region::ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo,
							   long& rX, long& rY,
							   long& rWidth, long& rHeight ) const
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	((Region*)this)->ImplPolyPolyRegionToBandRegion();

	// no internal data? -> region is empty!
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return false;

	// no band in the list? -> region is empty!
	if ( mpImplRegion->mpFirstBand == NULL )
		return false;

	// initialise pointer for first access
	ImplRegionBand* 	pCurrRectBand = mpImplRegion->mpFirstBand;
	ImplRegionBandSep*	pCurrRectBandSep = pCurrRectBand->mpFirstSep;

	DBG_ASSERT( pCurrRectBandSep != NULL, "Erstes Band wurde nicht optimiert." );
	if ( !pCurrRectBandSep )
		return false;

	// get boundaries of current rectangle
	rX		= pCurrRectBandSep->mnXLeft;
	rY		= pCurrRectBand->mnYTop;
	rWidth	= pCurrRectBandSep->mnXRight - pCurrRectBandSep->mnXLeft + 1;
	rHeight = pCurrRectBand->mnYBottom - pCurrRectBand->mnYTop + 1;

	// save pointers
	rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand;
	rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep;

	return true;
}

// -----------------------------------------------------------------------

bool Region::ImplGetNextRect( ImplRegionInfo& rImplRegionInfo,
							  long& rX, long& rY,
							  long& rWidth, long& rHeight ) const
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// no internal data? -> region is empty!
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return false;

	// get last pointers
	ImplRegionBand* 	pCurrRectBand = (ImplRegionBand*)rImplRegionInfo.mpVoidCurrRectBand;
	ImplRegionBandSep*	pCurrRectBandSep = (ImplRegionBandSep*)rImplRegionInfo.mpVoidCurrRectBandSep;

	// get next separation from current band
	pCurrRectBandSep = pCurrRectBandSep->mpNextSep;

	// no separation found? -> go to next band!
	if ( !pCurrRectBandSep )
	{
		// get next band
		pCurrRectBand = pCurrRectBand->mpNextBand;

		// no band found? -> not further rectangles!
		if( !pCurrRectBand )
			return false;

		// get first separation in current band
		pCurrRectBandSep = pCurrRectBand->mpFirstSep;
	}

	// get boundaries of current rectangle
	rX		= pCurrRectBandSep->mnXLeft;
	rY		= pCurrRectBand->mnYTop;
	rWidth	= pCurrRectBandSep->mnXRight - pCurrRectBandSep->mnXLeft + 1;
	rHeight = pCurrRectBand->mnYBottom - pCurrRectBand->mnYTop + 1;

	// save new pointers
	rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand;
	rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep;

	return true;
}

// -----------------------------------------------------------------------

RegionType Region::GetType() const
{
	if ( mpImplRegion == &aImplEmptyRegion )
		return REGION_EMPTY;
	else if ( mpImplRegion == &aImplNullRegion )
		return REGION_NULL;
	else if ( mpImplRegion->mnRectCount == 1 )
		return REGION_RECTANGLE;
	else
		return REGION_COMPLEX;
}

// -----------------------------------------------------------------------

sal_Bool Region::IsInside( const Point& rPoint ) const
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// PolyPolygon data im Imp structure?
	((Region*)this)->ImplPolyPolyRegionToBandRegion();
/*
	if ( mpImplRegion->mpPolyPoly )
		return mpImplRegion->mpPolyPoly->IsInside( rPoint );
*/

	// no instance data? -> not inside
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return sal_False;

	// search band list
	ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
	while ( pBand )
	{
		// is point within band?
		if ( (pBand->mnYTop <= rPoint.Y()) &&
			 (pBand->mnYBottom >= rPoint.Y()) )
		{
			// is point within separation of the band?
			if ( pBand->IsInside( rPoint.X() ) )
				return sal_True;
			else
				return sal_False;
		}

		pBand = pBand->mpNextBand;
	}

	return sal_False;
}

// -----------------------------------------------------------------------

sal_Bool Region::IsInside( const Rectangle& rRect ) const
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// is rectangle empty? -> not inside
	if ( rRect.IsEmpty() )
		return sal_False;

	// no instance data? -> not inside
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return sal_False;

	// create region from rectangle and intersect own region
	Region aRegion = rRect;
	aRegion.Exclude( *this );

	// rectangle is inside if exclusion is empty
	return aRegion.IsEmpty();
}

// -----------------------------------------------------------------------

sal_Bool Region::IsOver( const Rectangle& rRect ) const
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return sal_False;

	// Can we optimize this ??? - is used in StarDraw for brushes pointers
	// Why we have no IsOver for Regions ???
	// create region from rectangle and intersect own region
	Region aRegion = rRect;
	aRegion.Intersect( *this );

	// rectangle is over if include is not empty
	return !aRegion.IsEmpty();
}

// -----------------------------------------------------------------------

void Region::SetNull()
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// statische Object haben RefCount von 0
	if ( mpImplRegion->mnRefCount )
	{
		if ( mpImplRegion->mnRefCount > 1 )
			mpImplRegion->mnRefCount--;
		else
			delete mpImplRegion;
	}

	// set new type
	mpImplRegion = (ImplRegion*)(&aImplNullRegion);
}

// -----------------------------------------------------------------------

void Region::SetEmpty()
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// statische Object haben RefCount von 0
	if ( mpImplRegion->mnRefCount )
	{
		if ( mpImplRegion->mnRefCount > 1 )
			mpImplRegion->mnRefCount--;
		else
			delete mpImplRegion;
	}

	// set new type
	mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
}

// -----------------------------------------------------------------------

Region& Region::operator=( const Region& rRegion )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );
	DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );
	DBG_ASSERT( rRegion.mpImplRegion->mnRefCount < 0xFFFFFFFE, "Region: RefCount overflow" );

	// Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann
	// RefCount == 0 fuer statische Objekte
	if ( rRegion.mpImplRegion->mnRefCount )
		rRegion.mpImplRegion->mnRefCount++;

	// statische Object haben RefCount von 0
	if ( mpImplRegion->mnRefCount )
	{
		if ( mpImplRegion->mnRefCount > 1 )
			mpImplRegion->mnRefCount--;
		else
			delete mpImplRegion;
	}

	mpImplRegion = rRegion.mpImplRegion;
	return *this;
}

// -----------------------------------------------------------------------

Region& Region::operator=( const Rectangle& rRect )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// statische Object haben RefCount von 0
	if ( mpImplRegion->mnRefCount )
	{
		if ( mpImplRegion->mnRefCount > 1 )
			mpImplRegion->mnRefCount--;
		else
			delete mpImplRegion;
	}

	ImplCreateRectRegion( rRect );
	return *this;
}

// -----------------------------------------------------------------------

sal_Bool Region::operator==( const Region& rRegion ) const
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );
	DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );

	// reference to same object? -> equal!
	if ( mpImplRegion == rRegion.mpImplRegion )
		return sal_True;

	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return sal_False;

	if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) )
		return sal_False;

	if ( rRegion.mpImplRegion->mpPolyPoly && mpImplRegion->mpPolyPoly )
		return *rRegion.mpImplRegion->mpPolyPoly == *mpImplRegion->mpPolyPoly;
	else
	{
		((Region*)this)->ImplPolyPolyRegionToBandRegion();
		((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion();

		// Eine der beiden Regions kann jetzt Empty sein
		if ( mpImplRegion == rRegion.mpImplRegion )
			return sal_True;

		if ( mpImplRegion == &aImplEmptyRegion )
			return sal_False;

		if ( rRegion.mpImplRegion == &aImplEmptyRegion )
			return sal_False;
	}

	// initialise pointers
	ImplRegionBand* 	 pOwnRectBand = mpImplRegion->mpFirstBand;
	ImplRegionBandSep*	 pOwnRectBandSep = pOwnRectBand->mpFirstSep;
	ImplRegionBand* 	 pSecondRectBand = rRegion.mpImplRegion->mpFirstBand;
	ImplRegionBandSep*	 pSecondRectBandSep = pSecondRectBand->mpFirstSep;
	while ( pOwnRectBandSep && pSecondRectBandSep )
	{
		// get boundaries of current rectangle
		long nOwnXLeft = pOwnRectBandSep->mnXLeft;
		long nSecondXLeft = pSecondRectBandSep->mnXLeft;
		if ( nOwnXLeft != nSecondXLeft )
			return sal_False;

		long nOwnYTop = pOwnRectBand->mnYTop;
		long nSecondYTop = pSecondRectBand->mnYTop;
		if ( nOwnYTop != nSecondYTop )
			return sal_False;

		long nOwnXRight = pOwnRectBandSep->mnXRight;
		long nSecondXRight = pSecondRectBandSep->mnXRight;
		if ( nOwnXRight != nSecondXRight )
			return sal_False;

		long nOwnYBottom = pOwnRectBand->mnYBottom;
		long nSecondYBottom = pSecondRectBand->mnYBottom;
		if ( nOwnYBottom != nSecondYBottom )
			return sal_False;

		// get next separation from current band
		pOwnRectBandSep = pOwnRectBandSep->mpNextSep;

		// no separation found? -> go to next band!
		if ( !pOwnRectBandSep )
		{
			// get next band
			pOwnRectBand = pOwnRectBand->mpNextBand;

			// get first separation in current band
			if( pOwnRectBand )
				pOwnRectBandSep = pOwnRectBand->mpFirstSep;
		}

		// get next separation from current band
		pSecondRectBandSep = pSecondRectBandSep->mpNextSep;

		// no separation found? -> go to next band!
		if ( !pSecondRectBandSep )
		{
			// get next band
			pSecondRectBand = pSecondRectBand->mpNextBand;

			// get first separation in current band
			if( pSecondRectBand )
				pSecondRectBandSep = pSecondRectBand->mpFirstSep;
		}

		if ( pOwnRectBandSep && !pSecondRectBandSep )
			return sal_False;

		if ( !pOwnRectBandSep && pSecondRectBandSep )
			return sal_False;
	}

	return sal_True;
}

// -----------------------------------------------------------------------

enum StreamEntryType { STREAMENTRY_BANDHEADER, STREAMENTRY_SEPARATION, STREAMENTRY_END };

SvStream& operator>>( SvStream& rIStrm, Region& rRegion )
{
	DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );

	VersionCompat	aCompat( rIStrm, STREAM_READ );
	sal_uInt16			nVersion;
	sal_uInt16			nTmp16;

	// statische Object haben RefCount von 0
	if ( rRegion.mpImplRegion->mnRefCount )
	{
		if ( rRegion.mpImplRegion->mnRefCount > 1 )
			rRegion.mpImplRegion->mnRefCount--;
		else
			delete rRegion.mpImplRegion;
	}

	// get version of streamed region
	rIStrm >> nVersion;

	// get type of region
	rIStrm >> nTmp16;

	RegionType meStreamedType = (RegionType)nTmp16;

	switch( meStreamedType )
	{
		case REGION_NULL:
			rRegion.mpImplRegion = (ImplRegion*)&aImplNullRegion;
		break;

		case REGION_EMPTY:
			rRegion.mpImplRegion = (ImplRegion*)&aImplEmptyRegion;
		break;

		default:
        {
			// create instance of implementation class
			rRegion.mpImplRegion = new ImplRegion();

			// get header from first element
			rIStrm >> nTmp16;

			// get all bands
			rRegion.mpImplRegion->mnRectCount = 0;
			ImplRegionBand* pCurrBand = NULL;
			while ( (StreamEntryType)nTmp16 != STREAMENTRY_END )
			{
				// insert new band or new separation?
				if ( (StreamEntryType)nTmp16 == STREAMENTRY_BANDHEADER )
				{
					long nYTop;
					long nYBottom;

					rIStrm >> nYTop;
					rIStrm >> nYBottom;

					// create band
					ImplRegionBand* pNewBand = new ImplRegionBand( nYTop, nYBottom );

					// first element? -> set as first into the list
					if ( !pCurrBand )
						rRegion.mpImplRegion->mpFirstBand = pNewBand;
					else
						pCurrBand->mpNextBand = pNewBand;

					// save pointer for next creation
					pCurrBand = pNewBand;
				}
				else
				{
					long nXLeft;
					long nXRight;

					rIStrm >> nXLeft;
					rIStrm >> nXRight;

					// add separation
					if ( pCurrBand )
					{
						pCurrBand->Union( nXLeft, nXRight );
						rRegion.mpImplRegion->mnRectCount++;
					}
				}
                
                if( rIStrm.IsEof() )
                {
                    DBG_ERROR( "premature end of region stream" );
                    delete rRegion.mpImplRegion;
                    rRegion.mpImplRegion = (ImplRegion*)&aImplEmptyRegion;
                    return rIStrm;
                }

				// get next header
				rIStrm >> nTmp16;
			}

            if( aCompat.GetVersion() >= 2 )
            {
                sal_Bool bHasPolyPolygon;

                rIStrm >> bHasPolyPolygon;

                if( bHasPolyPolygon )
                {
                    delete rRegion.mpImplRegion->mpPolyPoly;
                    rRegion.mpImplRegion->mpPolyPoly = new PolyPolygon;
                    rIStrm >> *( rRegion.mpImplRegion->mpPolyPoly );
                }
            }
        }
        break;
	}

	return rIStrm;
}

// -----------------------------------------------------------------------

SvStream& operator<<( SvStream& rOStrm, const Region& rRegion )
{
	DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion );

	sal_uInt16          nVersion = 2;
	VersionCompat   aCompat( rOStrm, STREAM_WRITE, nVersion );
    Region          aTmpRegion( rRegion );

	// use tmp region to avoid destruction of internal region (polypolygon) of rRegion
    aTmpRegion.ImplPolyPolyRegionToBandRegion();

	// put version
	rOStrm << nVersion;

	// put type
	rOStrm << (sal_uInt16)aTmpRegion.GetType();

	// put all bands if not null or empty
	if ( (aTmpRegion.mpImplRegion != &aImplEmptyRegion) && (aTmpRegion.mpImplRegion != &aImplNullRegion) )
	{
		ImplRegionBand* pBand = aTmpRegion.mpImplRegion->mpFirstBand;
		while ( pBand )
		{
			// put boundaries
			rOStrm << (sal_uInt16) STREAMENTRY_BANDHEADER;
			rOStrm << pBand->mnYTop;
			rOStrm << pBand->mnYBottom;

			// put separations of current band
			ImplRegionBandSep* pSep = pBand->mpFirstSep;
			while ( pSep )
			{
				// put separation
				rOStrm << (sal_uInt16) STREAMENTRY_SEPARATION;
				rOStrm << pSep->mnXLeft;
				rOStrm << pSep->mnXRight;

				// next separation from current band
				pSep = pSep->mpNextSep;
			}

			pBand = pBand->mpNextBand;
		}

		// put endmarker
		rOStrm << (sal_uInt16) STREAMENTRY_END;
        
        // write polypolygon if available
        const sal_Bool bHasPolyPolygon = rRegion.HasPolyPolygon();
        rOStrm << bHasPolyPolygon;

        if( bHasPolyPolygon )
        {
            // #i105373#
            PolyPolygon aNoCurvePolyPolygon;
            rRegion.GetPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon);
            
            rOStrm << aNoCurvePolyPolygon;
        }
    }

	return rOStrm;
}

// -----------------------------------------------------------------------

void Region::ImplBeginAddRect()
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	// statische Object haben RefCount von 0
	if ( mpImplRegion->mnRefCount )
	{
		if ( mpImplRegion->mnRefCount > 1 )
			mpImplRegion->mnRefCount--;
		else
			delete mpImplRegion;
	}

	// create fresh region
	mpImplRegion = new ImplRegion();
}

// -----------------------------------------------------------------------

sal_Bool Region::ImplAddRect( const Rectangle& rRect )
{
	// Hier kein CheckThis, da nicht alle Daten auf Stand

	if ( rRect.IsEmpty() )
		return sal_True;

	// get justified rectangle
	long nTop;
	long nBottom;
	long nLeft;
	long nRight;
	if ( rRect.Top() <= rRect.Bottom() )
	{
		nTop = rRect.Top();
		nBottom = rRect.Bottom();
	}
	else
	{
		nTop = rRect.Bottom();
		nBottom = rRect.Top();
	}
	if ( rRect.Left() <= rRect.Right() )
	{
		nLeft = rRect.Left();
		nRight = rRect.Right();
	}
	else
	{
		nLeft = rRect.Right();
		nRight = rRect.Left();
	}

	if ( !mpImplRegion->mpLastCheckedBand )
	{
		// create new band
		mpImplRegion->mpLastCheckedBand = new ImplRegionBand( nTop, nBottom );

		// set band as current
		mpImplRegion->mpFirstBand = mpImplRegion->mpLastCheckedBand;
		mpImplRegion->mpLastCheckedBand->Union( nLeft, nRight );
	}
	else
	{
		DBG_ASSERT( nTop >= mpImplRegion->mpLastCheckedBand->mnYTop,
					"Region::ImplAddRect() - nTopY < nLastTopY" );

		// new band? create it!
		if ( (nTop != mpImplRegion->mpLastCheckedBand->mnYTop) ||
			 (nBottom != mpImplRegion->mpLastCheckedBand->mnYBottom) )
		{
			// create new band
			ImplRegionBand* pNewRegionBand = new ImplRegionBand( nTop, nBottom );

			// append band to the end
			mpImplRegion->mpLastCheckedBand->mpNextBand = pNewRegionBand;

			// skip to the new band
			mpImplRegion->mpLastCheckedBand = mpImplRegion->mpLastCheckedBand->mpNextBand;
		}

		// Insert Sep
		mpImplRegion->mpLastCheckedBand->Union( nLeft, nRight );
	}

	return sal_True;
}

// -----------------------------------------------------------------------

void Region::ImplEndAddRect()
{
	// check if we are empty
	if ( !mpImplRegion->mpFirstBand )
	{
		delete mpImplRegion;
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
		return;
	}

	// check if we have somthing to optimize
	if ( !mpImplRegion->mpFirstBand->mpNextBand )
	{
		// update mpImplRegion->mnRectCount, because no OptimizeBandList is called
		ImplRegionBandSep* pSep = mpImplRegion->mpFirstBand->mpFirstSep;
		mpImplRegion->mnRectCount = 0;
		while( pSep )
		{
			mpImplRegion->mnRectCount++;
			pSep = pSep->mpNextSep;
		}

		// Erst hier testen, da hier die Daten wieder stimmen
		DBG_CHKTHIS( Region, ImplDbgTestRegion );
		return;
	}

	// have to revert list? -> do it now!
	if ( mpImplRegion->mpFirstBand->mnYTop >
		 mpImplRegion->mpFirstBand->mpNextBand->mnYTop )
	{
		ImplRegionBand * pNewFirstRegionBand;

		// initialize temp list with first element
		pNewFirstRegionBand = mpImplRegion->mpFirstBand;
		mpImplRegion->mpFirstBand = mpImplRegion->mpFirstBand->mpNextBand;
		pNewFirstRegionBand->mpNextBand = NULL;

		// insert elements to the temp list
		while ( mpImplRegion->mpFirstBand )
		{
			ImplRegionBand * pSavedRegionBand = pNewFirstRegionBand;
			pNewFirstRegionBand = mpImplRegion->mpFirstBand;
			mpImplRegion->mpFirstBand = mpImplRegion->mpFirstBand->mpNextBand;
			pNewFirstRegionBand->mpNextBand = pSavedRegionBand;
		}

		// set temp list as new list
		mpImplRegion->mpFirstBand = pNewFirstRegionBand;
	}

	// cleanup
	if ( !mpImplRegion->OptimizeBandList() )
	{
		delete mpImplRegion;
		mpImplRegion = (ImplRegion*)(&aImplEmptyRegion);
	}

	// Erst hier testen, da hier die Daten wieder stimmen
	DBG_CHKTHIS( Region, ImplDbgTestRegion );
}

// -----------------------------------------------------------------------

sal_uLong Region::GetRectCount() const
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	((Region*)this)->ImplPolyPolyRegionToBandRegion();

#ifdef DBG_UTIL
	sal_uLong nCount = 0;

	// all bands if not null or empty
	if ( (mpImplRegion != &aImplEmptyRegion) && (mpImplRegion != &aImplNullRegion) )
	{
		ImplRegionBand* pBand = mpImplRegion->mpFirstBand;
		while ( pBand )
		{
			ImplRegionBandSep* pSep = pBand->mpFirstSep;
			while( pSep )
			{
				nCount++;
				pSep = pSep->mpNextSep;
			}

			pBand = pBand->mpNextBand;
		}
	}

	DBG_ASSERT( mpImplRegion->mnRectCount == nCount, "Region: invalid mnRectCount!" );
#endif

	return mpImplRegion->mnRectCount;
}

// -----------------------------------------------------------------------

RegionHandle Region::BeginEnumRects()
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	ImplPolyPolyRegionToBandRegion();

	// no internal data? -> region is empty!
	if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) )
		return 0;

	// no band in the list? -> region is empty!
	if ( mpImplRegion->mpFirstBand == NULL )
	{
		DBG_ASSERT( mpImplRegion->mpFirstBand, "Region::BeginEnumRects() First Band is Empty!" );
		return 0;
	}

	ImplRegionHandle* pData = new ImplRegionHandle;
	pData->mpRegion = new Region( *this );
	pData->mbFirst	= sal_True;

	// save pointers
	pData->mpCurrRectBand = pData->mpRegion->mpImplRegion->mpFirstBand;
	pData->mpCurrRectBandSep = pData->mpCurrRectBand->mpFirstSep;

	return (RegionHandle)pData;
}

// -----------------------------------------------------------------------

sal_Bool Region::GetEnumRects( RegionHandle pVoidData, Rectangle& rRect )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	ImplRegionHandle* pData = (ImplRegionHandle*)pVoidData;
	if ( !pData )
		return sal_False;

	if ( pData->mbFirst )
		pData->mbFirst = sal_False;
	else
	{
		// get next separation from current band
		pData->mpCurrRectBandSep = pData->mpCurrRectBandSep->mpNextSep;

		// no separation found? -> go to next band!
		if ( !pData->mpCurrRectBandSep )
		{
			// get next band
			pData->mpCurrRectBand = pData->mpCurrRectBand->mpNextBand;

			// no band found? -> not further rectangles!
			if ( !pData->mpCurrRectBand )
				return sal_False;

			// get first separation in current band
			pData->mpCurrRectBandSep = pData->mpCurrRectBand->mpFirstSep;
		}
	}

	// get boundaries of current rectangle
	rRect.Top() 	= pData->mpCurrRectBand->mnYTop;
	rRect.Bottom()	= pData->mpCurrRectBand->mnYBottom;
	rRect.Left()	= pData->mpCurrRectBandSep->mnXLeft;
	rRect.Right()	= pData->mpCurrRectBandSep->mnXRight;
	return sal_True;
}

// -----------------------------------------------------------------------

void Region::EndEnumRects( RegionHandle pVoidData )
{
	DBG_CHKTHIS( Region, ImplDbgTestRegion );

	ImplRegionHandle* pData = (ImplRegionHandle*)pVoidData;
	if ( !pData )
		return;

	// cleanup
	delete pData->mpRegion;
	delete pData;
}

// -----------------------------------------------------------------------

static inline bool ImplPolygonRectTest( const Polygon& rPoly, Rectangle* pRectOut = NULL )
{
    bool bIsRect = false;
    const Point* pPoints = rPoly.GetConstPointAry();
    sal_uInt16 nPoints = rPoly.GetSize();
    if( nPoints == 4 || (nPoints == 5 && pPoints[0] == pPoints[4]) )
    {
        long nX1 = pPoints[0].X(), nX2 = pPoints[2].X(),
        nY1 = pPoints[0].Y(), nY2 = pPoints[2].Y();
        if( ( (pPoints[1].X() == nX1 && pPoints[3].X() == nX2) &&
            (pPoints[1].Y() == nY2 && pPoints[3].Y() == nY1) )
        ||
        ( (pPoints[1].X() == nX2 && pPoints[3].X() == nX1) &&
        (pPoints[1].Y() == nY1 && pPoints[3].Y() == nY2) ) )
        {
            bIsRect = true;
            if( pRectOut )
            {
                long nSwap;
                if( nX2 < nX1 )
                {
                    nSwap = nX2;
                    nX2 = nX1;
                    nX1 = nSwap;
                }
                if( nY2 < nY1 )
                {
                    nSwap = nY2;
                    nY2 = nY1;
                    nY1 = nSwap;
                }
                if( nX2 != nX1 )
                    nX2--;
                if( nY2 != nY1 )
                    nY2--;
                pRectOut->Left()    = nX1;
                pRectOut->Right()   = nX2;
                pRectOut->Top()     = nY1;
                pRectOut->Bottom()  = nY2;
            }
        }
    }
    return bIsRect;
}

Region Region::GetRegionFromPolyPolygon( const PolyPolygon& rPolyPoly )
{
    //return Region( rPolyPoly );
    
    // check if it's worth extracting the XOr'ing the Rectangles
    // empiricism shows that break even between XOr'ing rectangles separately
    // and ImplPolyPolyRegionToBandRegion is at half rectangles/half polygons
    int nPolygonRects = 0, nPolygonPolygons = 0;
    int nPolygons = rPolyPoly.Count();
    
    for( sal_uInt16 i = 0; i < nPolygons; i++ )
    {
        const Polygon& rPoly = rPolyPoly[i];
        if( ImplPolygonRectTest( rPoly ) )
            nPolygonRects++;
        else
            nPolygonPolygons++;
    }
    if( nPolygonPolygons > nPolygonRects )
        return Region( rPolyPoly );
    
    Region aResult;
    Rectangle aRect;
    for( sal_uInt16 i = 0; i < nPolygons; i++ )
    {
        const Polygon& rPoly = rPolyPoly[i];
        if( ImplPolygonRectTest( rPoly, &aRect ) )
            aResult.XOr( aRect );
        else
            aResult.XOr( Region(rPoly) );
    }
    return aResult;
}
