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