LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/vcl/source/gdi - region.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 385 715 53.8 %
Date: 2013-07-09 Functions: 33 44 75.0 %
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             : #include <tools/vcompat.hxx>
      22             : #include <tools/stream.hxx>
      23             : #include <tools/helpers.hxx>
      24             : #include <vcl/region.hxx>
      25             : #include <regionband.hxx>
      26             : 
      27             : #include <basegfx/matrix/b2dhommatrix.hxx>
      28             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      29             : #include <basegfx/polygon/b2dpolygontools.hxx>
      30             : #include <basegfx/polygon/b2dpolygonclipper.hxx>
      31             : #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
      32             : #include <basegfx/range/b2drange.hxx>
      33             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      34             : 
      35             : //////////////////////////////////////////////////////////////////////////////
      36             : 
      37             : DBG_NAME( Region )
      38             : DBG_NAMEEX( Polygon )
      39             : DBG_NAMEEX( PolyPolygon )
      40             : 
      41             : //////////////////////////////////////////////////////////////////////////////
      42             : 
      43             : namespace
      44             : {
      45             :     /** Return <TRUE/> when the given polygon is rectiliner and oriented so that
      46             :         all sides are either horizontal or vertical.
      47             :     */
      48          22 :     bool ImplIsPolygonRectilinear (const PolyPolygon& rPolyPoly)
      49             :     {
      50             :         // Iterate over all polygons.
      51          22 :         const sal_uInt16 nPolyCount = rPolyPoly.Count();
      52          52 :         for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
      53             :         {
      54          30 :             const Polygon&  aPoly = rPolyPoly.GetObject(nPoly);
      55             : 
      56             :             // Iterate over all edges of the current polygon.
      57          30 :             const sal_uInt16 nSize = aPoly.GetSize();
      58             : 
      59          30 :             if (nSize < 2)
      60           0 :                 continue;
      61          30 :             Point aPoint (aPoly.GetPoint(0));
      62          30 :             const Point aLastPoint (aPoint);
      63         150 :             for (sal_uInt16 nPoint = 1; nPoint < nSize; ++nPoint)
      64             :             {
      65         120 :                 const Point aNextPoint (aPoly.GetPoint(nPoint));
      66             :                 // When there is at least one edge that is neither vertical nor
      67             :                 // horizontal then the entire polygon is not rectilinear (and
      68             :                 // oriented along primary axes.)
      69         120 :                 if (aPoint.X() != aNextPoint.X() && aPoint.Y() != aNextPoint.Y())
      70           0 :                     return false;
      71             : 
      72         120 :                 aPoint = aNextPoint;
      73             :             }
      74             :             // Compare closing edge.
      75          30 :             if (aLastPoint.X() != aPoint.X() && aLastPoint.Y() != aPoint.Y())
      76           0 :                 return false;
      77             :         }
      78          22 :         return true;
      79             :     }
      80             : 
      81             :     /** Convert a rectilinear polygon (that is oriented along the primary axes)
      82             :         to a list of bands.  For this special form of polygon we can use an
      83             :         optimization that prevents the creation of one band per y value.
      84             :         However, it still is possible that some temporary bands are created that
      85             :         later can be optimized away.
      86             :         @param rPolyPolygon
      87             :             A set of zero, one, or more polygons, nested or not, that are
      88             :             converted into a list of bands.
      89             :         @return
      90             :             A new RegionBand object is returned that contains the bands that
      91             :             represent the given poly-polygon.
      92             :     */
      93          22 :     RegionBand* ImplRectilinearPolygonToBands(const PolyPolygon& rPolyPoly)
      94             :     {
      95             :         OSL_ASSERT(ImplIsPolygonRectilinear (rPolyPoly));
      96             : 
      97             :         // Create a new RegionBand object as container of the bands.
      98          22 :         RegionBand* pRegionBand = new RegionBand();
      99          22 :         long nLineId = 0L;
     100             : 
     101             :         // Iterate over all polygons.
     102          22 :         const sal_uInt16 nPolyCount = rPolyPoly.Count();
     103          52 :         for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
     104             :         {
     105          30 :             const Polygon&  aPoly = rPolyPoly.GetObject(nPoly);
     106             : 
     107             :             // Iterate over all edges of the current polygon.
     108          30 :             const sal_uInt16 nSize = aPoly.GetSize();
     109          30 :             if (nSize < 2)
     110           0 :                 continue;
     111             :             // Avoid fetching every point twice (each point is the start point
     112             :             // of one and the end point of another edge.)
     113          30 :             Point aStart (aPoly.GetPoint(0));
     114          30 :             Point aEnd;
     115         180 :             for (sal_uInt16 nPoint = 1; nPoint <= nSize; ++nPoint, aStart=aEnd)
     116             :             {
     117             :                 // We take the implicit closing edge into account by mapping
     118             :                 // index nSize to 0.
     119         150 :                 aEnd = aPoly.GetPoint(nPoint%nSize);
     120         150 :                 if (aStart.Y() == aEnd.Y())
     121             :                 {
     122             :                     // Horizontal lines are ignored.
     123          90 :                     continue;
     124             :                 }
     125             : 
     126             :                 // At this point the line has to be vertical.
     127             :                 OSL_ASSERT(aStart.X() == aEnd.X());
     128             : 
     129             :                 // Sort y-coordinates to simplify the algorithm and store the
     130             :                 // direction seperately.  The direction is calculated as it is
     131             :                 // in other places (but seems to be the wrong way.)
     132          60 :                 const long nTop (::std::min(aStart.Y(), aEnd.Y()));
     133          60 :                 const long nBottom (::std::max(aStart.Y(), aEnd.Y()));
     134          60 :                 const LineType eLineType (aStart.Y() > aEnd.Y() ? LINE_DESCENDING : LINE_ASCENDING);
     135             : 
     136             :                 // Make sure that the current line is covered by bands.
     137          60 :                 pRegionBand->ImplAddMissingBands(nTop,nBottom);
     138             : 
     139             :                 // Find top-most band that may contain nTop.
     140          60 :                 ImplRegionBand* pBand = pRegionBand->ImplGetFirstRegionBand();
     141         132 :                 while (pBand!=NULL && pBand->mnYBottom < nTop)
     142          12 :                     pBand = pBand->mpNextBand;
     143          60 :                 ImplRegionBand* pTopBand = pBand;
     144             :                 // If necessary split the band at nTop so that nTop is contained
     145             :                 // in the lower band.
     146          60 :                 if (pBand!=NULL
     147             :                        // Prevent the current band from becoming 0 pixel high
     148          60 :                     && pBand->mnYTop<nTop
     149             :                        // this allows the lowest pixel of the band to be split off
     150           0 :                     && pBand->mnYBottom>=nTop
     151             :                        // do not split a band that is just one pixel high
     152           0 :                     && pBand->mnYTop<pBand->mnYBottom)
     153             :                 {
     154             :                     // Split the top band.
     155           0 :                     pTopBand = pBand->SplitBand(nTop);
     156             :                 }
     157             : 
     158             :                 // Advance to band that may contain nBottom.
     159         120 :                 while (pBand!=NULL && pBand->mnYBottom < nBottom)
     160           0 :                     pBand = pBand->mpNextBand;
     161             :                 // The lowest band may have to be split at nBottom so that
     162             :                 // nBottom itself remains in the upper band.
     163          60 :                 if (pBand!=NULL
     164             :                        // allow the current band becoming 1 pixel high
     165          60 :                     && pBand->mnYTop<=nBottom
     166             :                        // prevent splitting off a band that is 0 pixel high
     167          60 :                     && pBand->mnYBottom>nBottom
     168             :                        // do not split a band that is just one pixel high
     169           0 :                     && pBand->mnYTop<pBand->mnYBottom)
     170             :                 {
     171             :                     // Split the bottom band.
     172           0 :                     pBand->SplitBand(nBottom+1);
     173             :                 }
     174             : 
     175             :                 // Note that we remember the top band (in pTopBand) but not the
     176             :                 // bottom band.  The later can be determined by comparing y
     177             :                 // coordinates.
     178             : 
     179             :                 // Add the x-value as point to all bands in the nTop->nBottom range.
     180         120 :                 for (pBand=pTopBand; pBand!=NULL&&pBand->mnYTop<=nBottom; pBand=pBand->mpNextBand)
     181          60 :                     pBand->InsertPoint(aStart.X(), nLineId++, true, eLineType);
     182             :             }
     183             :         }
     184             : 
     185          22 :         return pRegionBand;
     186             :     }
     187             : 
     188             :     /** Convert a general polygon (one for which ImplIsPolygonRectilinear()
     189             :         returns <FALSE/>) to bands.
     190             :     */
     191           0 :     RegionBand* ImplGeneralPolygonToBands(const PolyPolygon& rPolyPoly, const Rectangle& rPolygonBoundingBox)
     192             :     {
     193           0 :         long nLineID = 0L;
     194             : 
     195             :         // initialisation and creation of Bands
     196           0 :         RegionBand* pRegionBand = new RegionBand();
     197           0 :         pRegionBand->CreateBandRange(rPolygonBoundingBox.Top(), rPolygonBoundingBox.Bottom());
     198             : 
     199             :         // insert polygons
     200           0 :         const sal_uInt16 nPolyCount = rPolyPoly.Count();
     201             : 
     202           0 :         for ( sal_uInt16 nPoly = 0; nPoly < nPolyCount; nPoly++ )
     203             :         {
     204             :             // get reference to current polygon
     205           0 :             const Polygon&  aPoly = rPolyPoly.GetObject( nPoly );
     206           0 :             const sal_uInt16    nSize = aPoly.GetSize();
     207             : 
     208             :             // not enough points ( <= 2 )? -> nothing to do!
     209           0 :             if ( nSize <= 2 )
     210           0 :                 continue;
     211             : 
     212             :             // band the polygon
     213           0 :             for ( sal_uInt16 nPoint = 1; nPoint < nSize; nPoint++ )
     214             :             {
     215           0 :                 pRegionBand->InsertLine( aPoly.GetPoint(nPoint-1), aPoly.GetPoint(nPoint), nLineID++ );
     216             :             }
     217             : 
     218             :             // close polygon with line from first point to last point, if neccesary
     219           0 :             const Point rLastPoint = aPoly.GetPoint(nSize-1);
     220           0 :             const Point rFirstPoint = aPoly.GetPoint(0);
     221             : 
     222           0 :             if ( rLastPoint != rFirstPoint )
     223             :             {
     224           0 :                 pRegionBand->InsertLine( rLastPoint, rFirstPoint, nLineID++ );
     225             :             }
     226             :         }
     227             : 
     228           0 :         return pRegionBand;
     229             :     }
     230             : } // end of anonymous namespace
     231             : 
     232             : //////////////////////////////////////////////////////////////////////////////
     233             : 
     234     2891847 : bool Region::IsEmpty() const
     235             : {
     236     2891847 :     return !mbIsNull && !mpB2DPolyPolygon.get() && !mpPolyPolygon.get() && !mpRegionBand.get();
     237             : }
     238             : 
     239     2396857 : bool Region::IsNull() const
     240             : {
     241     2396857 :     return mbIsNull;
     242             : }
     243             : 
     244          22 : RegionBand* ImplCreateRegionBandFromPolyPolygon(const PolyPolygon& rPolyPolygon)
     245             : {
     246          22 :     RegionBand* pRetval = 0;
     247             : 
     248          22 :     if(rPolyPolygon.Count())
     249             :     {
     250             :         // ensure to subdivide when bezier segemnts are used, it's going to
     251             :         // be expanded to rectangles
     252          22 :         PolyPolygon aPolyPolygon;
     253             : 
     254          22 :         rPolyPolygon.AdaptiveSubdivide(aPolyPolygon);
     255             : 
     256          22 :         if(aPolyPolygon.Count())
     257             :         {
     258          22 :             const Rectangle aRect(aPolyPolygon.GetBoundRect());
     259             : 
     260          22 :             if(!aRect.IsEmpty())
     261             :             {
     262          22 :                 if(ImplIsPolygonRectilinear(aPolyPolygon))
     263             :                 {
     264             :                     // For rectilinear polygons there is an optimized band conversion.
     265          22 :                     pRetval = ImplRectilinearPolygonToBands(aPolyPolygon);
     266             :                 }
     267             :                 else
     268             :                 {
     269           0 :                     pRetval = ImplGeneralPolygonToBands(aPolyPolygon, aRect);
     270             :                 }
     271             : 
     272             :                 // Convert points into seps.
     273          22 :                 if(pRetval)
     274             :                 {
     275          22 :                     pRetval->processPoints();
     276             : 
     277             :                     // Optimize list of bands.  Adjacent bands with identical lists
     278             :                     // of seps are joined.
     279          22 :                     if(!pRetval->OptimizeBandList())
     280             :                     {
     281           0 :                         delete pRetval;
     282           0 :                         pRetval = 0;
     283             :                     }
     284             :                 }
     285             :             }
     286          22 :         }
     287             :     }
     288             : 
     289          22 :     return pRetval;
     290             : }
     291             : 
     292          51 : PolyPolygon Region::ImplCreatePolyPolygonFromRegionBand() const
     293             : {
     294          51 :     PolyPolygon aRetval;
     295             : 
     296          51 :     if(getRegionBand())
     297             :     {
     298          51 :         RectangleVector aRectangles;
     299          51 :         GetRegionRectangles(aRectangles);
     300             : 
     301         104 :         for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
     302             :         {
     303          53 :             aRetval.Insert(Polygon(*aRectIter));
     304          51 :         }
     305             :     }
     306             :     else
     307             :     {
     308             :         OSL_ENSURE(false, "Called with no local RegionBand (!)");
     309             :     }
     310             : 
     311          51 :     return aRetval;
     312             : }
     313             : 
     314          51 : basegfx::B2DPolyPolygon Region::ImplCreateB2DPolyPolygonFromRegionBand() const
     315             : {
     316          51 :     PolyPolygon aPoly(ImplCreatePolyPolygonFromRegionBand());
     317             : 
     318          51 :     return aPoly.getB2DPolyPolygon();
     319             : }
     320             : 
     321     1384704 : Region::Region(bool bIsNull)
     322             : :   mpB2DPolyPolygon(),
     323             :     mpPolyPolygon(),
     324             :     mpRegionBand(),
     325     1384704 :     mbIsNull(bIsNull)
     326             : {
     327     1384704 : }
     328             : 
     329      252870 : Region::Region(const Rectangle& rRect)
     330             : :   mpB2DPolyPolygon(),
     331             :     mpPolyPolygon(),
     332             :     mpRegionBand(),
     333      252870 :     mbIsNull(false)
     334             : {
     335      252870 :     mpRegionBand.reset(rRect.IsEmpty() ? 0 : new RegionBand(rRect));
     336      252870 : }
     337             : 
     338           0 : Region::Region(const Polygon& rPolygon)
     339             : :   mpB2DPolyPolygon(),
     340             :     mpPolyPolygon(),
     341             :     mpRegionBand(),
     342           0 :     mbIsNull(false)
     343             : {
     344             :     DBG_CHKOBJ( &rPolygon, Polygon, NULL );
     345             : 
     346           0 :     if(rPolygon.GetSize())
     347             :     {
     348           0 :         ImplCreatePolyPolyRegion(rPolygon);
     349             :     }
     350           0 : }
     351             : 
     352         133 : Region::Region(const PolyPolygon& rPolyPoly)
     353             : :   mpB2DPolyPolygon(),
     354             :     mpPolyPolygon(),
     355             :     mpRegionBand(),
     356         133 :     mbIsNull(false)
     357             : {
     358             :     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
     359             : 
     360         133 :     if(rPolyPoly.Count())
     361             :     {
     362         133 :         ImplCreatePolyPolyRegion(rPolyPoly);
     363             :     }
     364         133 : }
     365             : 
     366         138 : Region::Region(const basegfx::B2DPolyPolygon& rPolyPoly)
     367             : :   mpB2DPolyPolygon(),
     368             :     mpPolyPolygon(),
     369             :     mpRegionBand(),
     370         138 :     mbIsNull(false)
     371             : {
     372             :     DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
     373             : 
     374         138 :     if(rPolyPoly.count())
     375             :     {
     376         138 :         ImplCreatePolyPolyRegion(rPolyPoly);
     377             :     }
     378         138 : }
     379             : 
     380     1125757 : Region::Region(const Region& rRegion)
     381             : :   mpB2DPolyPolygon(rRegion.mpB2DPolyPolygon),
     382             :     mpPolyPolygon(rRegion.mpPolyPolygon),
     383             :     mpRegionBand(rRegion.mpRegionBand),
     384     1125757 :     mbIsNull(rRegion.mbIsNull)
     385             : {
     386     1125757 : }
     387             : 
     388     2761663 : Region::~Region()
     389             : {
     390     2761663 : }
     391             : 
     392         133 : void Region::ImplCreatePolyPolyRegion( const PolyPolygon& rPolyPoly )
     393             : {
     394         133 :     const sal_uInt16 nPolyCount = rPolyPoly.Count();
     395             : 
     396         133 :     if(nPolyCount)
     397             :     {
     398             :         // polypolygon empty? -> empty region
     399         133 :         const Rectangle aRect(rPolyPoly.GetBoundRect());
     400             : 
     401         133 :         if(!aRect.IsEmpty())
     402             :         {
     403             :             // width OR height == 1 ? => Rectangular region
     404         133 :             if((1 == aRect.GetWidth()) || (1 == aRect.GetHeight()) || rPolyPoly.IsRect())
     405             :             {
     406         111 :                 mpRegionBand.reset(new RegionBand(aRect));
     407             :             }
     408             :             else
     409             :             {
     410          22 :                 mpPolyPolygon.reset(new PolyPolygon(rPolyPoly));
     411             :             }
     412             : 
     413         133 :             mbIsNull = false;
     414             :         }
     415             :     }
     416         133 : }
     417             : 
     418         138 : void Region::ImplCreatePolyPolyRegion( const basegfx::B2DPolyPolygon& rPolyPoly )
     419             : {
     420         138 :     if(rPolyPoly.count() && !rPolyPoly.getB2DRange().isEmpty())
     421             :     {
     422         138 :         mpB2DPolyPolygon.reset(new basegfx::B2DPolyPolygon(rPolyPoly));
     423         138 :         mbIsNull = false;
     424             :     }
     425         138 : }
     426             : 
     427      352738 : void Region::Move( long nHorzMove, long nVertMove )
     428             : {
     429      352738 :     if(IsNull() || IsEmpty())
     430             :     {
     431             :         // empty or null need no move
     432       85965 :         return;
     433             :     }
     434             : 
     435      266773 :     if(!nHorzMove && !nVertMove)
     436             :     {
     437             :         // no move defined
     438         851 :         return;
     439             :     }
     440             : 
     441      265922 :     if(getB2DPolyPolygon())
     442             :     {
     443          16 :         basegfx::B2DPolyPolygon aPoly(*getB2DPolyPolygon());
     444             : 
     445          16 :         aPoly.transform(basegfx::tools::createTranslateB2DHomMatrix(nHorzMove, nVertMove));
     446          16 :         mpB2DPolyPolygon.reset(aPoly.count() ? new basegfx::B2DPolyPolygon(aPoly) : 0);
     447          16 :         mpPolyPolygon.reset();
     448          16 :         mpRegionBand.reset();
     449             :     }
     450      265906 :     else if(getPolyPolygon())
     451             :     {
     452          11 :         PolyPolygon aPoly(*getPolyPolygon());
     453             : 
     454          11 :         aPoly.Move(nHorzMove, nVertMove);
     455          11 :         mpB2DPolyPolygon.reset();
     456          11 :         mpPolyPolygon.reset(aPoly.Count() ? new PolyPolygon(aPoly) : 0);
     457          11 :         mpRegionBand.reset();
     458             :     }
     459      265895 :     else if(getRegionBand())
     460             :     {
     461      265895 :         RegionBand* pNew = new RegionBand(*getRegionBand());
     462             : 
     463      265895 :         pNew->Move(nHorzMove, nVertMove);
     464      265895 :         mpB2DPolyPolygon.reset();
     465      265895 :         mpPolyPolygon.reset();
     466      265895 :         mpRegionBand.reset(pNew);
     467             :     }
     468             :     else
     469             :     {
     470             :         OSL_ENSURE(false, "Region::Move error: impossible combination (!)");
     471             :     }
     472             : }
     473             : 
     474           0 : void Region::Scale( double fScaleX, double fScaleY )
     475             : {
     476           0 :     if(IsNull() || IsEmpty())
     477             :     {
     478             :         // empty or null need no scale
     479           0 :         return;
     480             :     }
     481             : 
     482           0 :     if(basegfx::fTools::equalZero(fScaleX) && basegfx::fTools::equalZero(fScaleY))
     483             :     {
     484             :         // no scale defined
     485           0 :         return;
     486             :     }
     487             : 
     488           0 :     if(getB2DPolyPolygon())
     489             :     {
     490           0 :         basegfx::B2DPolyPolygon aPoly(*getB2DPolyPolygon());
     491             : 
     492           0 :         aPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fScaleX, fScaleY));
     493           0 :         mpB2DPolyPolygon.reset(aPoly.count() ? new basegfx::B2DPolyPolygon(aPoly) : 0);
     494           0 :         mpPolyPolygon.reset();
     495           0 :         mpRegionBand.reset();
     496             :     }
     497           0 :     else if(getPolyPolygon())
     498             :     {
     499           0 :         PolyPolygon aPoly(*getPolyPolygon());
     500             : 
     501           0 :         aPoly.Scale(fScaleX, fScaleY);
     502           0 :         mpB2DPolyPolygon.reset();
     503           0 :         mpPolyPolygon.reset(aPoly.Count() ? new PolyPolygon(aPoly) : 0);
     504           0 :         mpRegionBand.reset();
     505             :     }
     506           0 :     else if(getRegionBand())
     507             :     {
     508           0 :         RegionBand* pNew = new RegionBand(*getRegionBand());
     509             : 
     510           0 :         pNew->Scale(fScaleX, fScaleY);
     511           0 :         mpB2DPolyPolygon.reset();
     512           0 :         mpPolyPolygon.reset();
     513           0 :         mpRegionBand.reset(pNew);
     514             :     }
     515             :     else
     516             :     {
     517             :         OSL_ENSURE(false, "Region::Scale error: impossible combination (!)");
     518             :     }
     519             : }
     520             : 
     521       73612 : bool Region::Union( const Rectangle& rRect )
     522             : {
     523       73612 :     if(rRect.IsEmpty())
     524             :     {
     525             :         // empty rectangle will not expand the existing union, nothing to do
     526         724 :         return true;
     527             :     }
     528             : 
     529       72888 :     if(IsEmpty())
     530             :     {
     531             :         // no local data, the union will be equal to source. Create using rectangle
     532       67796 :         *this = rRect;
     533       67796 :         return true;
     534             :     }
     535             : 
     536        5092 :     if(HasPolyPolygonOrB2DPolyPolygon())
     537             :     {
     538             :         // get this B2DPolyPolygon, solve on polygon base
     539           0 :         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
     540             : 
     541           0 :         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation(aThisPolyPoly);
     542             : 
     543           0 :         if(!aThisPolyPoly.count())
     544             :         {
     545             :             // no local polygon, use the rectangle as new region
     546           0 :             *this = rRect;
     547             :         }
     548             :         else
     549             :         {
     550             :             // get the other B2DPolyPolygon and use logical Or-Operation
     551             :             const basegfx::B2DPolygon aRectPoly(
     552             :                 basegfx::tools::createPolygonFromRect(
     553             :                     basegfx::B2DRectangle(
     554           0 :                         rRect.Left(),
     555           0 :                         rRect.Top(),
     556           0 :                         rRect.Right(),
     557           0 :                         rRect.Bottom())));
     558             :             const basegfx::B2DPolyPolygon aClip(
     559             :                 basegfx::tools::solvePolygonOperationOr(
     560             :                     aThisPolyPoly,
     561           0 :                     basegfx::B2DPolyPolygon(aRectPoly)));
     562           0 :             *this = Region(aClip);
     563             :         }
     564             : 
     565           0 :         return true;
     566             :     }
     567             : 
     568             :     // only region band mode possibility left here or null/empty
     569        5092 :     const RegionBand* pCurrent = getRegionBand();
     570             : 
     571        5092 :     if(!pCurrent)
     572             :     {
     573             :         // no region band, create using the rectangle
     574           0 :         *this = rRect;
     575           0 :         return true;
     576             :     }
     577             : 
     578        5092 :     RegionBand* pNew = new RegionBand(*pCurrent);
     579             : 
     580             :     // get justified rectangle
     581        5092 :     const long nLeft(std::min(rRect.Left(), rRect.Right()));
     582        5092 :     const long nTop(std::min(rRect.Top(), rRect.Bottom()));
     583        5092 :     const long nRight(std::max(rRect.Left(), rRect.Right()));
     584        5092 :     const long nBottom(std::max(rRect.Top(), rRect.Bottom()));
     585             : 
     586             :     // insert bands if the boundaries are not already in the list
     587        5092 :     pNew->InsertBands(nTop, nBottom);
     588             : 
     589             :     // process union
     590        5092 :     pNew->Union(nLeft, nTop, nRight, nBottom);
     591             : 
     592             :     // cleanup
     593        5092 :     if(!pNew->OptimizeBandList())
     594             :     {
     595           0 :         delete pNew;
     596           0 :         pNew = 0;
     597             :     }
     598             : 
     599        5092 :     mpRegionBand.reset(pNew);
     600        5092 :     return true;
     601             : }
     602             : 
     603      210370 : bool Region::Intersect( const Rectangle& rRect )
     604             : {
     605      210370 :     if ( rRect.IsEmpty() )
     606             :     {
     607             :         // empty rectangle will create empty region
     608          42 :         SetEmpty();
     609          42 :         return true;
     610             :     }
     611             : 
     612      210328 :     if(IsNull())
     613             :     {
     614             :         // null region (everything) intersect with rect will give rect
     615       19738 :         *this = rRect;
     616       19738 :         return true;
     617             :     }
     618             : 
     619      190590 :     if(IsEmpty())
     620             :     {
     621             :         // no content, cannot get more empty
     622       19451 :         return true;
     623             :     }
     624             : 
     625      171139 :     if(HasPolyPolygonOrB2DPolyPolygon())
     626             :     {
     627             :         // if polygon data prefer double precision, the other will be lost (if buffered)
     628           7 :         if(getB2DPolyPolygon())
     629             :         {
     630             :             const basegfx::B2DPolyPolygon aPoly(
     631             :                 basegfx::tools::clipPolyPolygonOnRange(
     632           7 :                     *getB2DPolyPolygon(),
     633             :                     basegfx::B2DRange(
     634           7 :                         rRect.Left(),
     635           7 :                         rRect.Top(),
     636           7 :                         rRect.Right() + 1,
     637           7 :                         rRect.Bottom() + 1),
     638             :                     true,
     639          35 :                     false));
     640             : 
     641           7 :             mpB2DPolyPolygon.reset(aPoly.count() ? new basegfx::B2DPolyPolygon(aPoly) : 0);
     642           7 :             mpPolyPolygon.reset();
     643           7 :             mpRegionBand.reset();
     644             :         }
     645             :         else // if(getPolyPolygon())
     646             :         {
     647           0 :             PolyPolygon aPoly(*getPolyPolygon());
     648             : 
     649             :             // use the PolyPolygon::Clip method for rectangles, this is
     650             :             // fairly simple (does not even use GPC) and saves us from
     651             :             // unnecessary banding
     652           0 :             aPoly.Clip(rRect);
     653             : 
     654           0 :             mpB2DPolyPolygon.reset();
     655           0 :             mpPolyPolygon.reset(aPoly.Count() ? new PolyPolygon(aPoly) : 0);
     656           0 :             mpRegionBand.reset();
     657             :         }
     658             : 
     659           7 :         return true;
     660             :     }
     661             : 
     662             :     // only region band mode possibility left here or null/empty
     663      171132 :     const RegionBand* pCurrent = getRegionBand();
     664             : 
     665      171132 :     if(!pCurrent)
     666             :     {
     667             :         // region is empty -> nothing to do!
     668           0 :         return true;
     669             :     }
     670             : 
     671      171132 :     RegionBand* pNew = new RegionBand(*pCurrent);
     672             : 
     673             :     // get justified rectangle
     674      171132 :     const long nLeft(std::min(rRect.Left(), rRect.Right()));
     675      171132 :     const long nTop(std::min(rRect.Top(), rRect.Bottom()));
     676      171132 :     const long nRight(std::max(rRect.Left(), rRect.Right()));
     677      171132 :     const long nBottom(std::max(rRect.Top(), rRect.Bottom()));
     678             : 
     679             :     // insert bands if the boundaries are not allready in the list
     680      171132 :     pNew->InsertBands(nTop, nBottom);
     681             : 
     682             :     // process intersect
     683      171132 :     pNew->Intersect(nLeft, nTop, nRight, nBottom);
     684             : 
     685             :     // cleanup
     686      171132 :     if(!pNew->OptimizeBandList())
     687             :     {
     688       69318 :         delete pNew;
     689       69318 :         pNew = 0;
     690             :     }
     691             : 
     692      171132 :     mpRegionBand.reset(pNew);
     693      171132 :     return true;
     694             : }
     695             : 
     696       58784 : bool Region::Exclude( const Rectangle& rRect )
     697             : {
     698       58784 :     if ( rRect.IsEmpty() )
     699             :     {
     700             :         // excluding nothing will do no change
     701       13859 :         return true;
     702             :     }
     703             : 
     704       44925 :     if(IsEmpty())
     705             :     {
     706             :         // cannot exclude from empty, done
     707        1557 :         return true;
     708             :     }
     709             : 
     710       43368 :     if(IsNull())
     711             :     {
     712             :         // error; cannnot exclude from null region since this is not representable
     713             :         // in the data
     714             :         OSL_ENSURE(false, "Region::Exclude error: Cannot exclude from null region (!)");
     715           0 :         return true;
     716             :     }
     717             : 
     718       43368 :     if( HasPolyPolygonOrB2DPolyPolygon() )
     719             :     {
     720             :         // get this B2DPolyPolygon
     721           0 :         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
     722             : 
     723           0 :         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation(aThisPolyPoly);
     724             : 
     725           0 :         if(!aThisPolyPoly.count())
     726             :         {
     727             :             // when local polygon is empty, nothing can be excluded
     728           0 :             return true;
     729             :         }
     730             : 
     731             :         // get the other B2DPolyPolygon
     732             :         const basegfx::B2DPolygon aRectPoly(
     733             :             basegfx::tools::createPolygonFromRect(
     734           0 :                 basegfx::B2DRectangle(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom())));
     735           0 :         const basegfx::B2DPolyPolygon aOtherPolyPoly(aRectPoly);
     736           0 :         const basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff(aThisPolyPoly, aOtherPolyPoly);
     737             : 
     738           0 :         *this = Region(aClip);
     739             : 
     740           0 :         return true;
     741             :     }
     742             : 
     743             :     // only region band mode possibility left here or null/empty
     744       43368 :     const RegionBand* pCurrent = getRegionBand();
     745             : 
     746       43368 :     if(!pCurrent)
     747             :     {
     748             :         // empty? -> done!
     749           0 :         return true;
     750             :     }
     751             : 
     752       43368 :     RegionBand* pNew = new RegionBand(*pCurrent);
     753             : 
     754             :     // get justified rectangle
     755       43368 :     const long nLeft(std::min(rRect.Left(), rRect.Right()));
     756       43368 :     const long nTop(std::min(rRect.Top(), rRect.Bottom()));
     757       43368 :     const long nRight(std::max(rRect.Left(), rRect.Right()));
     758       43368 :     const long nBottom(std::max(rRect.Top(), rRect.Bottom()));
     759             : 
     760             :     // insert bands if the boundaries are not allready in the list
     761       43368 :     pNew->InsertBands(nTop, nBottom);
     762             : 
     763             :     // process exclude
     764       43368 :     pNew->Exclude(nLeft, nTop, nRight, nBottom);
     765             : 
     766             :     // cleanup
     767       43368 :     if(!pNew->OptimizeBandList())
     768             :     {
     769       10989 :         delete pNew;
     770       10989 :         pNew = 0;
     771             :     }
     772             : 
     773       43368 :     mpRegionBand.reset(pNew);
     774       43368 :     return true;
     775             : }
     776             : 
     777           0 : bool Region::XOr( const Rectangle& rRect )
     778             : {
     779           0 :     if ( rRect.IsEmpty() )
     780             :     {
     781             :         // empty rectangle will not change local content
     782           0 :         return true;
     783             :     }
     784             : 
     785           0 :     if(IsEmpty())
     786             :     {
     787             :         // rRect will be the xored-form (local off, rect on)
     788           0 :         *this = rRect;
     789           0 :         return true;
     790             :     }
     791             : 
     792           0 :     if(IsNull())
     793             :     {
     794             :         // error; cannnot exclude from null region since this is not representable
     795             :         // in the data
     796             :         OSL_ENSURE(false, "Region::XOr error: Cannot XOr with null region (!)");
     797           0 :         return true;
     798             :     }
     799             : 
     800           0 :     if( HasPolyPolygonOrB2DPolyPolygon() )
     801             :     {
     802             :         // get this B2DPolyPolygon
     803           0 :         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
     804             : 
     805           0 :         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
     806             : 
     807           0 :         if(!aThisPolyPoly.count())
     808             :         {
     809             :             // no local content, XOr will be equal to rectangle
     810           0 :             *this = rRect;
     811           0 :             return true;
     812             :         }
     813             : 
     814             :         // get the other B2DPolyPolygon
     815             :         const basegfx::B2DPolygon aRectPoly(
     816             :             basegfx::tools::createPolygonFromRect(
     817           0 :                 basegfx::B2DRectangle(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom())));
     818           0 :         const basegfx::B2DPolyPolygon aOtherPolyPoly(aRectPoly);
     819           0 :         const basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor(aThisPolyPoly, aOtherPolyPoly);
     820             : 
     821           0 :         *this = Region(aClip);
     822             : 
     823           0 :         return true;
     824             :     }
     825             : 
     826             :     // only region band mode possibility left here or null/empty
     827           0 :     const RegionBand* pCurrent = getRegionBand();
     828             : 
     829           0 :     if(!pCurrent)
     830             :     {
     831             :         // rRect will be the xored-form (local off, rect on)
     832           0 :         *this = rRect;
     833           0 :         return true;
     834             :     }
     835             : 
     836             :     // only region band mode possibility left here or null/empty
     837           0 :     RegionBand* pNew = new RegionBand(*getRegionBand());
     838             : 
     839             :     // get justified rectangle
     840           0 :     const long nLeft(std::min(rRect.Left(), rRect.Right()));
     841           0 :     const long nTop(std::min(rRect.Top(), rRect.Bottom()));
     842           0 :     const long nRight(std::max(rRect.Left(), rRect.Right()));
     843           0 :     const long nBottom(std::max(rRect.Top(), rRect.Bottom()));
     844             : 
     845             :     // insert bands if the boundaries are not allready in the list
     846           0 :     pNew->InsertBands(nTop, nBottom);
     847             : 
     848             :     // process xor
     849           0 :     pNew->XOr(nLeft, nTop, nRight, nBottom);
     850             : 
     851             :     // cleanup
     852           0 :     if(!pNew->OptimizeBandList())
     853             :     {
     854           0 :         delete pNew;
     855           0 :         pNew = 0;
     856             :     }
     857             : 
     858           0 :     mpRegionBand.reset(pNew);
     859           0 :     return true;
     860             : }
     861             : 
     862       83969 : bool Region::Union( const Region& rRegion )
     863             : {
     864       83969 :     if(rRegion.IsEmpty())
     865             :     {
     866             :         // no extension at all
     867        1522 :         return true;
     868             :     }
     869             : 
     870       82447 :     if(rRegion.IsNull())
     871             :     {
     872             :         // extending with null region -> null region
     873           0 :         *this = Region(true);
     874           0 :         return true;
     875             :     }
     876             : 
     877       82447 :     if(IsEmpty())
     878             :     {
     879             :         // local is empty, union will give source region
     880       46205 :         *this = rRegion;
     881       46205 :         return true;
     882             :     }
     883             : 
     884       36242 :     if(IsNull())
     885             :     {
     886             :         // already fully expanded (is null region), cannot be extended
     887           0 :         return true;
     888             :     }
     889             : 
     890       36242 :     if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
     891             :     {
     892             :         // get this B2DPolyPolygon
     893          24 :         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
     894             : 
     895          24 :         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation(aThisPolyPoly);
     896             : 
     897          24 :         if(!aThisPolyPoly.count())
     898             :         {
     899             :             // when no local content, union will be equal to rRegion
     900           0 :             *this = rRegion;
     901           0 :             return true;
     902             :         }
     903             : 
     904             :         // get the other B2DPolyPolygon
     905          48 :         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
     906          24 :         aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation(aOtherPolyPoly);
     907             : 
     908             :         // use logical OR operation
     909          48 :         basegfx::B2DPolyPolygon aClip(basegfx::tools::solvePolygonOperationOr(aThisPolyPoly, aOtherPolyPoly));
     910             : 
     911          24 :         *this = Region( aClip );
     912          48 :         return true;
     913             :     }
     914             : 
     915             :     // only region band mode possibility left here or null/empty
     916       36218 :     const RegionBand* pCurrent = getRegionBand();
     917             : 
     918       36218 :     if(!pCurrent)
     919             :     {
     920             :         // local is empty, union will give source region
     921           0 :         *this = rRegion;
     922           0 :         return true;
     923             :     }
     924             : 
     925       36218 :     const RegionBand* pSource = rRegion.getRegionBand();
     926             : 
     927       36218 :     if(!pSource)
     928             :     {
     929             :         // no extension at all
     930           0 :         return true;
     931             :     }
     932             : 
     933             :     // prepare source and target
     934       36218 :     RegionBand* pNew = new RegionBand(*pCurrent);
     935             : 
     936             :     // union with source
     937       36218 :     pNew->Union(*pSource);
     938             : 
     939             :     // cleanup
     940       36218 :     if(!pNew->OptimizeBandList())
     941             :     {
     942           0 :         delete pNew;
     943           0 :         pNew = 0;
     944             :     }
     945             : 
     946       36218 :     mpRegionBand.reset(pNew);
     947       36218 :     return true;
     948             : }
     949             : 
     950      577382 : bool Region::Intersect( const Region& rRegion )
     951             : {
     952             :     // same instance data? -> nothing to do!
     953      577382 :     if(getB2DPolyPolygon() && getB2DPolyPolygon() == rRegion.getB2DPolyPolygon())
     954             :     {
     955           0 :         return true;
     956             :     }
     957             : 
     958      577382 :     if(getPolyPolygon() && getPolyPolygon() == rRegion.getPolyPolygon())
     959             :     {
     960           0 :         return true;
     961             :     }
     962             : 
     963      577382 :     if(getRegionBand() && getRegionBand() == rRegion.getRegionBand())
     964             :     {
     965           0 :         return true;
     966             :     }
     967             : 
     968      577382 :     if(rRegion.IsNull())
     969             :     {
     970             :         // source region is null-region, intersect will not change local region
     971           0 :         return true;
     972             :     }
     973             : 
     974      577382 :     if(IsNull())
     975             :     {
     976             :         // when local region is null-region, intersect will be equal to source
     977      103004 :         *this = rRegion;
     978      103004 :         return true;
     979             :     }
     980             : 
     981      474378 :     if(rRegion.IsEmpty())
     982             :     {
     983             :         // source region is empty, intersection will always be empty
     984       94852 :         SetEmpty();
     985       94852 :         return true;
     986             :     }
     987             : 
     988      379526 :     if(IsEmpty())
     989             :     {
     990             :         // local region is empty, cannot get more emty than that. Nothing to do
     991       27162 :         return true;
     992             :     }
     993             : 
     994      352364 :     if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
     995             :     {
     996             :         // get this B2DPolyPolygon
     997          61 :         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
     998             : 
     999          61 :         if(!aThisPolyPoly.count())
    1000             :         {
    1001             :             // local region is empty, cannot get more emty than that. Nothing to do
    1002           0 :             return true;
    1003             :         }
    1004             : 
    1005             :         // get the other B2DPolyPolygon
    1006         122 :         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
    1007             : 
    1008          61 :         if(!aOtherPolyPoly.count())
    1009             :         {
    1010             :             // source region is empty, intersection will always be empty
    1011           0 :             SetEmpty();
    1012           0 :             return true;
    1013             :         }
    1014             : 
    1015             :         const basegfx::B2DPolyPolygon aClip(
    1016             :             basegfx::tools::clipPolyPolygonOnPolyPolygon(
    1017             :                 aOtherPolyPoly,
    1018             :                 aThisPolyPoly,
    1019             :                 true,
    1020         122 :                 false));
    1021          61 :         *this = Region( aClip );
    1022         122 :         return true;
    1023             :     }
    1024             : 
    1025             :     // only region band mode possibility left here or null/empty
    1026      352303 :     const RegionBand* pCurrent = getRegionBand();
    1027             : 
    1028      352303 :     if(!pCurrent)
    1029             :     {
    1030             :         // local region is empty, cannot get more emty than that. Nothing to do
    1031           0 :         return true;
    1032             :     }
    1033             : 
    1034      352303 :     const RegionBand* pSource = rRegion.getRegionBand();
    1035             : 
    1036      352303 :     if(!pSource)
    1037             :     {
    1038             :         // source region is empty, intersection will always be empty
    1039           0 :         SetEmpty();
    1040           0 :         return true;
    1041             :     }
    1042             : 
    1043             :     // both RegionBands exist and are not empty
    1044      352303 :     if(pCurrent->getRectangleCount() + 2 < pSource->getRectangleCount())
    1045             :     {
    1046             :         // when we have less rectangles, turn around the call
    1047           0 :         Region aTempRegion = rRegion;
    1048           0 :         aTempRegion.Intersect( *this );
    1049           0 :         *this = aTempRegion;
    1050             :     }
    1051             :     else
    1052             :     {
    1053             :         // prepare new regionBand
    1054      352303 :         RegionBand* pNew = pCurrent ? new RegionBand(*pCurrent) : new RegionBand();
    1055             : 
    1056             :         // intersect with source
    1057      352303 :         pNew->Intersect(*pSource);
    1058             : 
    1059             :         // cleanup
    1060      352303 :         if(!pNew->OptimizeBandList())
    1061             :         {
    1062       23769 :             delete pNew;
    1063       23769 :             pNew = 0;
    1064             :         }
    1065             : 
    1066      352303 :         mpRegionBand.reset(pNew);
    1067             :     }
    1068             : 
    1069      352303 :     return true;
    1070             : }
    1071             : 
    1072        1815 : bool Region::Exclude( const Region& rRegion )
    1073             : {
    1074        1815 :     if ( rRegion.IsEmpty() )
    1075             :     {
    1076             :         // excluding nothing will do no change
    1077         886 :         return true;
    1078             :     }
    1079             : 
    1080         929 :     if ( rRegion.IsNull() )
    1081             :     {
    1082             :         // excluding everything will create empty region
    1083           0 :         SetEmpty();
    1084           0 :         return true;
    1085             :     }
    1086             : 
    1087         929 :     if(IsEmpty())
    1088             :     {
    1089             :         // cannot exclude from empty, done
    1090           0 :         return true;
    1091             :     }
    1092             : 
    1093         929 :     if(IsNull())
    1094             :     {
    1095             :         // error; cannnot exclude from null region since this is not representable
    1096             :         // in the data
    1097             :         OSL_ENSURE(false, "Region::Exclude error: Cannot exclude from null region (!)");
    1098           0 :         return true;
    1099             :     }
    1100             : 
    1101         929 :     if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
    1102             :     {
    1103             :         // get this B2DPolyPolygon
    1104           0 :         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
    1105             : 
    1106           0 :         if(!aThisPolyPoly.count())
    1107             :         {
    1108             :             // cannot exclude from empty, done
    1109           0 :             return true;
    1110             :         }
    1111             : 
    1112           0 :         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
    1113             : 
    1114             :         // get the other B2DPolyPolygon
    1115           0 :         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
    1116           0 :         aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
    1117             : 
    1118           0 :         basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly );
    1119           0 :         *this = Region( aClip );
    1120           0 :         return true;
    1121             :     }
    1122             : 
    1123             :     // only region band mode possibility left here or null/empty
    1124         929 :     const RegionBand* pCurrent = getRegionBand();
    1125             : 
    1126         929 :     if(!pCurrent)
    1127             :     {
    1128             :         // cannot exclude from empty, done
    1129           0 :         return true;
    1130             :     }
    1131             : 
    1132         929 :     const RegionBand* pSource = rRegion.getRegionBand();
    1133             : 
    1134         929 :     if(!pSource)
    1135             :     {
    1136             :         // excluding nothing will do no change
    1137           0 :         return true;
    1138             :     }
    1139             : 
    1140             :     // prepare source and target
    1141         929 :     RegionBand* pNew = new RegionBand(*pCurrent);
    1142             : 
    1143             :     // union with source
    1144         929 :     const bool bSuccess(pNew->Exclude(*pSource));
    1145             : 
    1146             :     // cleanup
    1147         929 :     if(!bSuccess)
    1148             :     {
    1149          51 :         delete pNew;
    1150          51 :         pNew = 0;
    1151             :     }
    1152             : 
    1153         929 :     mpRegionBand.reset(pNew);
    1154         929 :     return true;
    1155             : }
    1156             : 
    1157           0 : bool Region::XOr( const Region& rRegion )
    1158             : {
    1159           0 :     if ( rRegion.IsEmpty() )
    1160             :     {
    1161             :         // empty region will not change local content
    1162           0 :         return true;
    1163             :     }
    1164             : 
    1165           0 :     if ( rRegion.IsNull() )
    1166             :     {
    1167             :         // error; cannnot exclude null region from local since this is not representable
    1168             :         // in the data
    1169             :         OSL_ENSURE(false, "Region::XOr error: Cannot XOr with null region (!)");
    1170           0 :         return true;
    1171             :     }
    1172             : 
    1173           0 :     if(IsEmpty())
    1174             :     {
    1175             :         // rRect will be the xored-form (local off, rect on)
    1176           0 :         *this = rRegion;
    1177           0 :         return true;
    1178             :     }
    1179             : 
    1180           0 :     if(IsNull())
    1181             :     {
    1182             :         // error; cannnot exclude from null region since this is not representable
    1183             :         // in the data
    1184             :         OSL_ENSURE(false, "Region::XOr error: Cannot XOr with null region (!)");
    1185           0 :         return false;
    1186             :     }
    1187             : 
    1188           0 :     if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
    1189             :     {
    1190             :         // get this B2DPolyPolygon
    1191           0 :         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
    1192             : 
    1193           0 :         if(!aThisPolyPoly.count())
    1194             :         {
    1195             :             // rRect will be the xored-form (local off, rect on)
    1196           0 :             *this = rRegion;
    1197           0 :             return true;
    1198             :         }
    1199             : 
    1200           0 :         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
    1201             : 
    1202             :         // get the other B2DPolyPolygon
    1203           0 :         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
    1204           0 :         aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
    1205             : 
    1206           0 :         basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly );
    1207           0 :         *this = Region( aClip );
    1208           0 :         return true;
    1209             :     }
    1210             : 
    1211             :     // only region band mode possibility left here or null/empty
    1212           0 :     const RegionBand* pCurrent = getRegionBand();
    1213             : 
    1214           0 :     if(!pCurrent)
    1215             :     {
    1216             :         // rRect will be the xored-form (local off, rect on)
    1217           0 :         *this = rRegion;
    1218           0 :         return true;
    1219             :     }
    1220             : 
    1221           0 :     const RegionBand* pSource = rRegion.getRegionBand();
    1222             : 
    1223           0 :     if(!pSource)
    1224             :     {
    1225             :         // empty region will not change local content
    1226           0 :         return true;
    1227             :     }
    1228             : 
    1229             :     // prepare source and target
    1230           0 :     RegionBand* pNew = new RegionBand(*pCurrent);
    1231             : 
    1232             :     // union with source
    1233           0 :     pNew->XOr(*pSource);
    1234             : 
    1235             :     // cleanup
    1236           0 :     if(!pNew->OptimizeBandList())
    1237             :     {
    1238           0 :         delete pNew;
    1239           0 :         pNew = 0;
    1240             :     }
    1241             : 
    1242           0 :     mpRegionBand.reset(pNew);
    1243             : 
    1244           0 :     return true;
    1245             : }
    1246             : 
    1247      178990 : Rectangle Region::GetBoundRect() const
    1248             : {
    1249      178990 :     if(IsEmpty())
    1250             :     {
    1251             :         // no internal data? -> region is empty!
    1252        1404 :         return Rectangle();
    1253             :     }
    1254             : 
    1255      177586 :     if(IsNull())
    1256             :     {
    1257             :         // error; null region has no BoundRect
    1258             :         // OSL_ENSURE(false, "Region::GetBoundRect error: null region has unlimitied bound rect, not representable (!)");
    1259        3812 :         return Rectangle();
    1260             :     }
    1261             : 
    1262             :     // prefer double precision source
    1263      173774 :     if(getB2DPolyPolygon())
    1264             :     {
    1265          35 :         const basegfx::B2DRange aRange(basegfx::tools::getRange(*getB2DPolyPolygon()));
    1266             : 
    1267          35 :         if(aRange.isEmpty())
    1268             :         {
    1269             :             // emulate PolyPolygon::GetBoundRect() when empty polygon
    1270           0 :             return Rectangle();
    1271             :         }
    1272             :         else
    1273             :         {
    1274             :             return Rectangle(
    1275          70 :                 static_cast<sal_Int32>(floor(aRange.getMinX())), static_cast<sal_Int32>(floor(aRange.getMinY())),
    1276         105 :                 static_cast<sal_Int32>(ceil(aRange.getMaxX())), static_cast<sal_Int32>(ceil(aRange.getMaxY())));
    1277             :         }
    1278             :     }
    1279             : 
    1280      173739 :     if(getPolyPolygon())
    1281             :     {
    1282           0 :         return getPolyPolygon()->GetBoundRect();
    1283             :     }
    1284             : 
    1285      173739 :     if(getRegionBand())
    1286             :     {
    1287      173739 :         return getRegionBand()->GetBoundRect();
    1288             :     }
    1289             : 
    1290           0 :     return Rectangle();
    1291             : }
    1292             : 
    1293           0 : const PolyPolygon Region::GetAsPolyPolygon() const
    1294             : {
    1295           0 :     if(getPolyPolygon())
    1296             :     {
    1297           0 :         return *getPolyPolygon();
    1298             :     }
    1299             : 
    1300           0 :     if(getB2DPolyPolygon())
    1301             :     {
    1302             :         // the polygon needs to be converted, buffer the down converion
    1303           0 :         const PolyPolygon aPolyPolgon(*getB2DPolyPolygon());
    1304           0 :         const_cast< Region* >(this)->mpPolyPolygon.reset(new PolyPolygon(aPolyPolgon));
    1305             : 
    1306           0 :         return *getPolyPolygon();
    1307             :     }
    1308             : 
    1309           0 :     if(getRegionBand())
    1310             :     {
    1311             :         // the BandRegion needs to be converted, buffer the converion
    1312           0 :         const PolyPolygon aPolyPolgon(ImplCreatePolyPolygonFromRegionBand());
    1313           0 :         const_cast< Region* >(this)->mpPolyPolygon.reset(new PolyPolygon(aPolyPolgon));
    1314             : 
    1315           0 :         return *getPolyPolygon();
    1316             :     }
    1317             : 
    1318           0 :     return PolyPolygon();
    1319             : }
    1320             : 
    1321         170 : const basegfx::B2DPolyPolygon Region::GetAsB2DPolyPolygon() const
    1322             : {
    1323         170 :     if(getB2DPolyPolygon())
    1324             :     {
    1325         108 :         return *getB2DPolyPolygon();
    1326             :     }
    1327             : 
    1328          62 :     if(getPolyPolygon())
    1329             :     {
    1330             :         // the polygon needs to be converted, buffer the up conversion. This will be preferred from now.
    1331          11 :         const basegfx::B2DPolyPolygon aB2DPolyPolygon(getPolyPolygon()->getB2DPolyPolygon());
    1332          11 :         const_cast< Region* >(this)->mpB2DPolyPolygon.reset(new basegfx::B2DPolyPolygon(aB2DPolyPolygon));
    1333             : 
    1334          11 :         return *getB2DPolyPolygon();
    1335             :     }
    1336             : 
    1337          51 :     if(getRegionBand())
    1338             :     {
    1339             :         // the BandRegion needs to be converted, buffer the converion
    1340          51 :         const basegfx::B2DPolyPolygon aB2DPolyPolygon(ImplCreateB2DPolyPolygonFromRegionBand());
    1341          51 :         const_cast< Region* >(this)->mpB2DPolyPolygon.reset(new basegfx::B2DPolyPolygon(aB2DPolyPolygon));
    1342             : 
    1343          51 :         return *getB2DPolyPolygon();
    1344             :     }
    1345             : 
    1346           0 :     return basegfx::B2DPolyPolygon();
    1347             : }
    1348             : 
    1349      379761 : const RegionBand* Region::GetAsRegionBand() const
    1350             : {
    1351      379761 :     if(!getRegionBand())
    1352             :     {
    1353         326 :         if(getB2DPolyPolygon())
    1354             :         {
    1355             :             // convert B2DPolyPolygon to RegionBand, buffer it and return it
    1356          22 :             const_cast< Region* >(this)->mpRegionBand.reset(ImplCreateRegionBandFromPolyPolygon(PolyPolygon(*getB2DPolyPolygon())));
    1357             :         }
    1358         304 :         else if(getPolyPolygon())
    1359             :         {
    1360             :             // convert B2DPolyPolygon to RegionBand, buffer it and return it
    1361           0 :             const_cast< Region* >(this)->mpRegionBand.reset(ImplCreateRegionBandFromPolyPolygon(*getPolyPolygon()));
    1362             :         }
    1363             :     }
    1364             : 
    1365      379761 :     return getRegionBand();
    1366             : }
    1367             : 
    1368           0 : bool Region::IsInside( const Point& rPoint ) const
    1369             : {
    1370           0 :     if(IsEmpty())
    1371             :     {
    1372             :         // no point can be in empty region
    1373           0 :         return false;
    1374             :     }
    1375             : 
    1376           0 :     if(IsNull())
    1377             :     {
    1378             :         // all points are inside null-region
    1379           0 :         return true;
    1380             :     }
    1381             : 
    1382             :     // Too expensive (?)
    1383             :     //if(mpImplRegion->getRegionPolyPoly())
    1384             :     //{
    1385             :     //  return mpImplRegion->getRegionPolyPoly()->IsInside( rPoint );
    1386             :     //}
    1387             : 
    1388             :     // ensure RegionBand existance
    1389           0 :     const RegionBand* pRegionBand = GetAsRegionBand();
    1390             : 
    1391           0 :     if(pRegionBand)
    1392             :     {
    1393           0 :         return pRegionBand->IsInside(rPoint);
    1394             :     }
    1395             : 
    1396           0 :     return false;
    1397             : }
    1398             : 
    1399           0 : bool Region::IsInside( const Rectangle& rRect ) const
    1400             : {
    1401           0 :     if(IsEmpty())
    1402             :     {
    1403             :         // no rectangle can be in empty region
    1404           0 :         return false;
    1405             :     }
    1406             : 
    1407           0 :     if(IsNull())
    1408             :     {
    1409             :         // rectangle always inside null-region
    1410           0 :         return true;
    1411             :     }
    1412             : 
    1413           0 :     if ( rRect.IsEmpty() )
    1414             :     {
    1415             :         // is rectangle empty? -> not inside
    1416           0 :         return false;
    1417             :     }
    1418             : 
    1419             :     // create region from rectangle and intersect own region
    1420           0 :     Region aRegion(rRect);
    1421           0 :     aRegion.Exclude(*this);
    1422             : 
    1423             :     // rectangle is inside if exclusion is empty
    1424           0 :     return aRegion.IsEmpty();
    1425             : }
    1426             : 
    1427             : // -----------------------------------------------------------------------
    1428             : 
    1429       16364 : bool Region::IsOver( const Rectangle& rRect ) const
    1430             : {
    1431       16364 :     if(IsEmpty())
    1432             :     {
    1433             :         // nothing can be over something empty
    1434        9530 :         return false;
    1435             :     }
    1436             : 
    1437        6834 :     if(IsNull())
    1438             :     {
    1439             :         // everything is over null region
    1440           0 :         return true;
    1441             :     }
    1442             : 
    1443             :     // Can we optimize this ??? - is used in StarDraw for brushes pointers
    1444             :     // Why we have no IsOver for Regions ???
    1445             :     // create region from rectangle and intersect own region
    1446        6834 :     Region aRegion(rRect);
    1447        6834 :     aRegion.Intersect( *this );
    1448             : 
    1449             :     // rectangle is over if include is not empty
    1450        6834 :     return !aRegion.IsEmpty();
    1451             : }
    1452             : 
    1453      188392 : void Region::SetNull()
    1454             : {
    1455             :     // reset all content
    1456      188392 :     mpB2DPolyPolygon.reset();
    1457      188392 :     mpPolyPolygon.reset();
    1458      188392 :     mpRegionBand.reset();
    1459      188392 :     mbIsNull = true;
    1460      188392 : }
    1461             : 
    1462      146855 : void Region::SetEmpty()
    1463             : {
    1464             :     // reset all content
    1465      146855 :     mpB2DPolyPolygon.reset();
    1466      146855 :     mpPolyPolygon.reset();
    1467      146855 :     mpRegionBand.reset();
    1468      146855 :     mbIsNull = false;
    1469      146855 : }
    1470             : 
    1471     1439935 : Region& Region::operator=( const Region& rRegion )
    1472             : {
    1473             :     // reset all content
    1474     1439935 :     mpB2DPolyPolygon = rRegion.mpB2DPolyPolygon;
    1475     1439935 :     mpPolyPolygon = rRegion.mpPolyPolygon;
    1476     1439935 :     mpRegionBand = rRegion.mpRegionBand;
    1477     1439935 :     mbIsNull = rRegion.mbIsNull;
    1478             : 
    1479     1439935 :     return *this;
    1480             : }
    1481             : 
    1482      187218 : Region& Region::operator=( const Rectangle& rRect )
    1483             : {
    1484      187218 :     mpB2DPolyPolygon.reset();
    1485      187218 :     mpPolyPolygon.reset();
    1486      187218 :     mpRegionBand.reset(rRect.IsEmpty() ? 0 : new RegionBand(rRect));
    1487      187218 :     mbIsNull = false;
    1488             : 
    1489      187218 :     return *this;
    1490             : }
    1491             : 
    1492       15970 : bool Region::operator==( const Region& rRegion ) const
    1493             : {
    1494       15970 :     if(IsNull() && rRegion.IsNull())
    1495             :     {
    1496             :         // both are null region
    1497           0 :         return true;
    1498             :     }
    1499             : 
    1500       15970 :     if(IsEmpty() && rRegion.IsEmpty())
    1501             :     {
    1502             :         // both are empty
    1503           0 :         return true;
    1504             :     }
    1505             : 
    1506       15970 :     if(getB2DPolyPolygon() && getB2DPolyPolygon() == rRegion.getB2DPolyPolygon())
    1507             :     {
    1508             :         // same instance data? -> equal
    1509           0 :         return true;
    1510             :     }
    1511             : 
    1512       15970 :     if(getPolyPolygon() && getPolyPolygon() == rRegion.getPolyPolygon())
    1513             :     {
    1514             :         // same instance data? -> equal
    1515           0 :         return true;
    1516             :     }
    1517             : 
    1518       15970 :     if(getRegionBand() && getRegionBand() == rRegion.getRegionBand())
    1519             :     {
    1520             :         // same instance data? -> equal
    1521           0 :         return true;
    1522             :     }
    1523             : 
    1524       15970 :     if(IsNull() || IsEmpty())
    1525             :     {
    1526           0 :         return false;
    1527             :     }
    1528             : 
    1529       15970 :     if(rRegion.IsNull() || rRegion.IsEmpty())
    1530             :     {
    1531           0 :         return false;
    1532             :     }
    1533             : 
    1534       15970 :     if(rRegion.getB2DPolyPolygon() || getB2DPolyPolygon())
    1535             :     {
    1536             :         // one of both has a B2DPolyPolygon based region, ensure both have it
    1537             :         // by evtl. conversion
    1538           0 :         const_cast< Region* >(this)->GetAsB2DPolyPolygon();
    1539           0 :         const_cast< Region& >(rRegion).GetAsB2DPolyPolygon();
    1540             : 
    1541           0 :         return *rRegion.getB2DPolyPolygon() == *getB2DPolyPolygon();
    1542             :     }
    1543             : 
    1544       15970 :     if(rRegion.getPolyPolygon() || getPolyPolygon())
    1545             :     {
    1546             :         // one of both has a B2DPolyPolygon based region, ensure both have it
    1547             :         // by evtl. conversion
    1548           0 :         const_cast< Region* >(this)->GetAsPolyPolygon();
    1549           0 :         const_cast< Region& >(rRegion).GetAsPolyPolygon();
    1550             : 
    1551           0 :         return *rRegion.getPolyPolygon() == *getPolyPolygon();
    1552             :     }
    1553             : 
    1554             :     // both are not empty or null (see above) and if content supported polygon
    1555             :     // data the comparison is already done. Only both on RegionBand base can be left,
    1556             :     // but better check
    1557       15970 :     if(rRegion.getRegionBand() && getRegionBand())
    1558             :     {
    1559       15970 :         return *rRegion.getRegionBand() == *getRegionBand();
    1560             :     }
    1561             : 
    1562             :     // should not happen, but better deny equality
    1563           0 :     return false;
    1564             : }
    1565             : 
    1566           4 : SvStream& operator>>(SvStream& rIStrm, Region& rRegion)
    1567             : {
    1568           4 :     VersionCompat aCompat(rIStrm, STREAM_READ);
    1569           4 :     sal_uInt16 nVersion(0);
    1570           4 :     sal_uInt16 nTmp16(0);
    1571             : 
    1572             :     // clear region to be loaded
    1573           4 :     rRegion.SetEmpty();
    1574             : 
    1575             :     // get version of streamed region
    1576           4 :     rIStrm >> nVersion;
    1577             : 
    1578             :     // get type of region
    1579           4 :     rIStrm >> nTmp16;
    1580             : 
    1581             :     enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX };
    1582           4 :     RegionType meStreamedType = (RegionType)nTmp16;
    1583             : 
    1584           4 :     switch(meStreamedType)
    1585             :     {
    1586             :         case REGION_NULL:
    1587             :         {
    1588           0 :             rRegion.SetNull();
    1589           0 :             break;
    1590             :         }
    1591             : 
    1592             :         case REGION_EMPTY:
    1593             :         {
    1594           0 :             rRegion.SetEmpty();
    1595           0 :             break;
    1596             :         }
    1597             : 
    1598             :         default:
    1599             :         {
    1600           4 :             RegionBand* pNewRegionBand = new RegionBand();
    1601           4 :             pNewRegionBand->load(rIStrm);
    1602           4 :             rRegion.mpRegionBand.reset(pNewRegionBand);
    1603             : 
    1604           4 :             if(aCompat.GetVersion() >= 2)
    1605             :             {
    1606           4 :                 sal_Bool bHasPolyPolygon(sal_False);
    1607             : 
    1608           4 :                 rIStrm >> bHasPolyPolygon;
    1609             : 
    1610           4 :                 if(bHasPolyPolygon)
    1611             :                 {
    1612           0 :                     PolyPolygon* pNewPoly = new PolyPolygon();
    1613           0 :                     rIStrm >> *pNewPoly;
    1614           0 :                     rRegion.mpPolyPolygon.reset(pNewPoly);
    1615             :                 }
    1616             :             }
    1617             : 
    1618           4 :             break;
    1619             :         }
    1620             :     }
    1621             : 
    1622           4 :     return rIStrm;
    1623             : }
    1624             : 
    1625           0 : SvStream& operator<<( SvStream& rOStrm, const Region& rRegion )
    1626             : {
    1627           0 :     const sal_uInt16 nVersion(2);
    1628           0 :     VersionCompat aCompat(rOStrm, STREAM_WRITE, nVersion);
    1629             : 
    1630             :     // put version
    1631           0 :     rOStrm << nVersion;
    1632             : 
    1633             :     // put type
    1634             :     enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX };
    1635           0 :     RegionType aRegionType(REGION_COMPLEX);
    1636           0 :     bool bEmpty(rRegion.IsEmpty());
    1637             : 
    1638           0 :     if(!bEmpty && rRegion.getB2DPolyPolygon() && 0 == rRegion.getB2DPolyPolygon()->count())
    1639             :     {
    1640             :         OSL_ENSURE(false, "Region with empty B2DPolyPolygon, should not be created (!)");
    1641           0 :         bEmpty = true;
    1642             :     }
    1643             : 
    1644           0 :     if(!bEmpty && rRegion.getPolyPolygon() && 0 == rRegion.getPolyPolygon()->Count())
    1645             :     {
    1646             :         OSL_ENSURE(false, "Region with empty PolyPolygon, should not be created (!)");
    1647           0 :         bEmpty = true;
    1648             :     }
    1649             : 
    1650           0 :     if(bEmpty)
    1651             :     {
    1652           0 :         aRegionType = REGION_EMPTY;
    1653             :     }
    1654           0 :     else if(rRegion.IsNull())
    1655             :     {
    1656           0 :         aRegionType = REGION_NULL;
    1657             :     }
    1658           0 :     else if(rRegion.getRegionBand() && rRegion.getRegionBand()->isSingleRectangle())
    1659             :     {
    1660           0 :         aRegionType = REGION_RECTANGLE;
    1661             :     }
    1662             : 
    1663           0 :     rOStrm << (sal_uInt16)aRegionType;
    1664             : 
    1665             :     // get RegionBand
    1666           0 :     const RegionBand* pRegionBand = rRegion.getRegionBand();
    1667             : 
    1668           0 :     if(pRegionBand)
    1669             :     {
    1670           0 :         pRegionBand->save(rOStrm);
    1671             :     }
    1672             :     else
    1673             :     {
    1674             :         // for compatibility, write an empty RegionBand (will only write
    1675             :         // the end marker STREAMENTRY_END, but this *is* needed)
    1676           0 :         const RegionBand aRegionBand;
    1677             : 
    1678           0 :         aRegionBand.save(rOStrm);
    1679             :     }
    1680             : 
    1681             :     // write polypolygon if available
    1682           0 :     const sal_Bool bHasPolyPolygon(rRegion.HasPolyPolygonOrB2DPolyPolygon());
    1683           0 :     rOStrm << bHasPolyPolygon;
    1684             : 
    1685           0 :     if(bHasPolyPolygon)
    1686             :     {
    1687             :         // #i105373#
    1688           0 :         PolyPolygon aNoCurvePolyPolygon;
    1689           0 :         rRegion.GetAsPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon);
    1690             : 
    1691           0 :         rOStrm << aNoCurvePolyPolygon;
    1692             :     }
    1693             : 
    1694           0 :     return rOStrm;
    1695             : }
    1696             : 
    1697      379761 : void Region::GetRegionRectangles(RectangleVector& rTarget) const
    1698             : {
    1699             :     // clear returnvalues
    1700      379761 :     rTarget.clear();
    1701             : 
    1702             :     // ensure RegionBand existance
    1703      379761 :     const RegionBand* pRegionBand = GetAsRegionBand();
    1704             : 
    1705      379761 :     if(pRegionBand)
    1706             :     {
    1707      379457 :         pRegionBand->GetRegionRectangles(rTarget);
    1708             :     }
    1709      379761 : }
    1710             : 
    1711           0 : static inline bool ImplPolygonRectTest( const Polygon& rPoly, Rectangle* pRectOut = NULL )
    1712             : {
    1713           0 :     bool bIsRect = false;
    1714           0 :     const Point* pPoints = rPoly.GetConstPointAry();
    1715           0 :     sal_uInt16 nPoints = rPoly.GetSize();
    1716             : 
    1717           0 :     if( nPoints == 4 || (nPoints == 5 && pPoints[0] == pPoints[4]) )
    1718             :     {
    1719           0 :         long nX1 = pPoints[0].X(), nX2 = pPoints[2].X(), nY1 = pPoints[0].Y(), nY2 = pPoints[2].Y();
    1720             : 
    1721           0 :         if( ( (pPoints[1].X() == nX1 && pPoints[3].X() == nX2) && (pPoints[1].Y() == nY2 && pPoints[3].Y() == nY1) )
    1722           0 :          || ( (pPoints[1].X() == nX2 && pPoints[3].X() == nX1) && (pPoints[1].Y() == nY1 && pPoints[3].Y() == nY2) ) )
    1723             :         {
    1724           0 :             bIsRect = true;
    1725             : 
    1726           0 :             if( pRectOut )
    1727             :             {
    1728             :                 long nSwap;
    1729             : 
    1730           0 :                 if( nX2 < nX1 )
    1731             :                 {
    1732           0 :                     nSwap = nX2;
    1733           0 :                     nX2 = nX1;
    1734           0 :                     nX1 = nSwap;
    1735             :                 }
    1736             : 
    1737           0 :                 if( nY2 < nY1 )
    1738             :                 {
    1739           0 :                     nSwap = nY2;
    1740           0 :                     nY2 = nY1;
    1741           0 :                     nY1 = nSwap;
    1742             :                 }
    1743             : 
    1744           0 :                 if( nX2 != nX1 )
    1745             :                 {
    1746           0 :                     nX2--;
    1747             :                 }
    1748             : 
    1749           0 :                 if( nY2 != nY1 )
    1750             :                 {
    1751           0 :                     nY2--;
    1752             :                 }
    1753             : 
    1754           0 :                 pRectOut->Left()    = nX1;
    1755           0 :                 pRectOut->Right()   = nX2;
    1756           0 :                 pRectOut->Top()     = nY1;
    1757           0 :                 pRectOut->Bottom()  = nY2;
    1758             :             }
    1759             :         }
    1760             :     }
    1761             : 
    1762           0 :     return bIsRect;
    1763             : }
    1764             : 
    1765           0 : Region Region::GetRegionFromPolyPolygon( const PolyPolygon& rPolyPoly )
    1766             : {
    1767             :     //return Region( rPolyPoly );
    1768             : 
    1769             :     // check if it's worth extracting the XOr'ing the Rectangles
    1770             :     // empiricism shows that break even between XOr'ing rectangles separately
    1771             :     // and ImplCreateRegionBandFromPolyPolygon is at half rectangles/half polygons
    1772           0 :     int nPolygonRects = 0, nPolygonPolygons = 0;
    1773           0 :     int nPolygons = rPolyPoly.Count();
    1774             : 
    1775           0 :     for( sal_uInt16 i = 0; i < nPolygons; i++ )
    1776             :     {
    1777           0 :         const Polygon& rPoly = rPolyPoly[i];
    1778             : 
    1779           0 :         if( ImplPolygonRectTest( rPoly ) )
    1780             :         {
    1781           0 :             nPolygonRects++;
    1782             :         }
    1783             :         else
    1784             :         {
    1785           0 :             nPolygonPolygons++;
    1786             :         }
    1787             :     }
    1788             : 
    1789           0 :     if( nPolygonPolygons > nPolygonRects )
    1790             :     {
    1791           0 :         return Region( rPolyPoly );
    1792             :     }
    1793             : 
    1794           0 :     Region aResult;
    1795           0 :     Rectangle aRect;
    1796             : 
    1797           0 :     for( sal_uInt16 i = 0; i < nPolygons; i++ )
    1798             :     {
    1799           0 :         const Polygon& rPoly = rPolyPoly[i];
    1800             : 
    1801           0 :         if( ImplPolygonRectTest( rPoly, &aRect ) )
    1802             :         {
    1803           0 :             aResult.XOr( aRect );
    1804             :         }
    1805             :         else
    1806             :         {
    1807           0 :             aResult.XOr( Region(rPoly) );
    1808             :         }
    1809             :     }
    1810             : 
    1811           0 :     return aResult;
    1812             : }
    1813             : 
    1814             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10