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

Generated by: LCOV version 1.10