LCOV - code coverage report
Current view: top level - libreoffice/vcl/source/gdi - region.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 600 1191 50.4 %
Date: 2012-12-27 Functions: 47 79 59.5 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.10