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