diff options
author | Armin Le Grand <alg@apache.org> | 2012-10-23 12:46:28 +0000 |
---|---|---|
committer | Armin Le Grand <alg@apache.org> | 2012-10-23 12:46:28 +0000 |
commit | cab10eeb7878edf224a004fd7640bd4adf8d3c51 (patch) | |
tree | ca8c7780822a571f0ade4ab1b90fc89d2c245b63 | |
parent | 498926039ce717631eda046b1aa256efd24dfdf6 (diff) |
#121237# Rework/Cleanup of Region code due to missing complete support for B2DPolygon class
Notes
Notes:
merged as: e717d1dcce7f8906311c5ccdbb2326b61a702630
38 files changed, 3791 insertions, 3207 deletions
diff --git a/canvas/source/vcl/canvashelper.cxx b/canvas/source/vcl/canvashelper.cxx index 0dcc74fd03fc..e62baa330ef5 100644 --- a/canvas/source/vcl/canvashelper.cxx +++ b/canvas/source/vcl/canvashelper.cxx @@ -1230,7 +1230,7 @@ namespace vclcanvas // accumulate non-empty clips into one region // ========================================== - Region aClipRegion( REGION_NULL ); + Region aClipRegion(true); if( viewState.Clip.is() ) { diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx index 2a8e3dbd0950..a3a27174afb8 100644 --- a/cppcanvas/source/mtfrenderer/implrenderer.cxx +++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx @@ -1396,7 +1396,7 @@ namespace cppcanvas } else { - if( !pClipAction->GetRegion().HasPolyPolygon() ) + if( !pClipAction->GetRegion().HasPolyPolygonOrB2DPolyPolygon() ) { VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip " "region encountered, falling back to bounding box!" ); @@ -1418,9 +1418,11 @@ namespace cppcanvas // with old one, just set it) // #121806# explicitely kept integer + basegfx::B2DPolyPolygon aPolyPolygon(pClipAction->GetRegion().GetAsB2DPolyPolygon()); + + aPolyPolygon.transform(rVDev.GetViewTransformation()); updateClipping( - rVDev.LogicToPixel( - pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(), + aPolyPolygon, rFactoryParms, false ); } @@ -1450,7 +1452,7 @@ namespace cppcanvas { MetaISectRegionClipRegionAction* pClipAction = static_cast<MetaISectRegionClipRegionAction*>(pCurrAct); - if( !pClipAction->GetRegion().HasPolyPolygon() ) + if( !pClipAction->GetRegion().HasPolyPolygonOrB2DPolyPolygon() ) { VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip " "region encountered, falling back to bounding box!" ); @@ -1470,9 +1472,11 @@ namespace cppcanvas // intersect current clip with given clip polygon // #121806# explicitely kept integer + basegfx::B2DPolyPolygon aPolyPolygon(pClipAction->GetRegion().GetAsB2DPolyPolygon()); + + aPolyPolygon.transform(rVDev.GetViewTransformation()); updateClipping( - rVDev.LogicToPixel( - pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(), + aPolyPolygon, rFactoryParms, true ); } diff --git a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx index 11f9fd790f5b..25f4867a3b2d 100644 --- a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx @@ -387,26 +387,8 @@ namespace if(!rRegion.IsEmpty()) { Region aRegion(rRegion); - aRetval = aRegion.GetB2DPolyPolygon(); - if(!aRetval.count()) - { - RegionHandle aRegionHandle(aRegion.BeginEnumRects()); - Rectangle aRegionRectangle; - - while(aRegion.GetEnumRects(aRegionHandle, aRegionRectangle)) - { - if(!aRegionRectangle.IsEmpty()) - { - const basegfx::B2DRange aRegionRange( - aRegionRectangle.Left(), aRegionRectangle.Top(), - aRegionRectangle.Right(), aRegionRectangle.Bottom()); - aRetval.append(basegfx::tools::createPolygonFromRect(aRegionRange)); - } - } - - aRegion.EndEnumRects(aRegionHandle); - } + aRetval = aRegion.GetAsB2DPolyPolygon(); } return aRetval; diff --git a/filter/source/graphicfilter/eps/eps.cxx b/filter/source/graphicfilter/eps/eps.cxx index 22fc78edb788..c19732f7581b 100644 --- a/filter/source/graphicfilter/eps/eps.cxx +++ b/filter/source/graphicfilter/eps/eps.cxx @@ -1637,15 +1637,16 @@ void PSWriter::ImplSetClipRegion( Region& rClipRegion ) { if ( !rClipRegion.IsEmpty() ) { - Rectangle aRect; - RegionHandle hRegionHandle = rClipRegion.BeginEnumRects(); + RectangleVector aRectangles; + rClipRegion.GetRegionRectangles(aRectangles); - while ( rClipRegion.GetNextEnumRect( hRegionHandle, aRect ) ) + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - double nX1 = aRect.Left(); - double nY1 = aRect.Top(); - double nX2 = aRect.Right(); - double nY2 = aRect.Bottom(); + double nX1(aRectIter->Left()); + double nY1(aRectIter->Top()); + double nX2(aRectIter->Right()); + double nY2(aRectIter->Bottom()); + ImplWriteDouble( nX1 ); ImplWriteDouble( nY1 ); ImplWriteByte( 'm' ); @@ -1661,8 +1662,34 @@ void PSWriter::ImplSetClipRegion( Region& rClipRegion ) ImplWriteDouble( nX1 ); ImplWriteDouble( nY1 ); ImplWriteByte( 'l', PS_SPACE | PS_WRAP ); - }; - rClipRegion.EndEnumRects( hRegionHandle ); + } + + //Rectangle aRect; + //RegionHandle hRegionHandle = rClipRegion.BeginEnumRects(); + // + //while ( rClipRegion.GetEnumRects( hRegionHandle, aRect ) ) + //{ + // double nX1 = aRect.Left(); + // double nY1 = aRect.Top(); + // double nX2 = aRect.Right(); + // double nY2 = aRect.Bottom(); + // ImplWriteDouble( nX1 ); + // ImplWriteDouble( nY1 ); + // ImplWriteByte( 'm' ); + // ImplWriteDouble( nX2 ); + // ImplWriteDouble( nY1 ); + // ImplWriteByte( 'l' ); + // ImplWriteDouble( nX2 ); + // ImplWriteDouble( nY2 ); + // ImplWriteByte( 'l' ); + // ImplWriteDouble( nX1 ); + // ImplWriteDouble( nY2 ); + // ImplWriteByte( 'l' ); + // ImplWriteDouble( nX1 ); + // ImplWriteDouble( nY1 ); + // ImplWriteByte( 'l', PS_SPACE | PS_WRAP ); + //}; + //rClipRegion.EndEnumRects( hRegionHandle ); ImplWriteLine( "eoclip newpath" ); } } @@ -1711,12 +1738,18 @@ void PSWriter::ImplBmp( Bitmap* pBitmap, Bitmap* pMaskBitmap, const Point & rPoi aRect = Rectangle( Point( 0, nHeightOrg - nHeightLeft ), Size( (long)nWidth, (long)nHeight ) ); aRegion = Region( pMaskBitmap->CreateRegion( COL_BLACK, aRect ) ); - if ( ( mnLevel == 1 ) && ( aRegion.GetRectCount() * 5 > 1000 ) ) + if( mnLevel == 1 ) { - nHeight >>= 1; - if ( nHeight < 2 ) - return; - continue; + RectangleVector aRectangleVector; + aRegion.GetRegionRectangles(aRectangleVector); + + if ( aRectangleVector.size() * 5 > 1000 ) + { + nHeight >>= 1; + if ( nHeight < 2 ) + return; + continue; + } } break; } @@ -1731,26 +1764,50 @@ void PSWriter::ImplBmp( Bitmap* pBitmap, Bitmap* pMaskBitmap, const Point & rPoi ImplWriteLine( "gs\npum" ); ImplTranslate( aSourcePos.X(), aSourcePos.Y() ); ImplScale( nXWidth / nWidth, nYHeight / nHeight ); - RegionHandle hRegionHandle = aRegion.BeginEnumRects(); - while ( aRegion.GetNextEnumRect( hRegionHandle, aRect ) ) + RectangleVector aRectangles; + aRegion.GetRegionRectangles(aRectangles); + const long nMoveVertical(nHeightLeft - nHeightOrg); + + for(RectangleVector::iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - aRect.Move( 0, - ( nHeightOrg - nHeightLeft ) ); - ImplWriteLong( aRect.Left() ); - ImplWriteLong( aRect.Top() ); + aRectIter->Move(0, nMoveVertical); + + ImplWriteLong( aRectIter->Left() ); + ImplWriteLong( aRectIter->Top() ); ImplWriteByte( 'm' ); - ImplWriteLong( aRect.Right() + 1 ); - ImplWriteLong( aRect.Top() ); + ImplWriteLong( aRectIter->Right() + 1 ); + ImplWriteLong( aRectIter->Top() ); ImplWriteByte( 'l' ); - ImplWriteLong( aRect.Right() + 1 ); - ImplWriteLong( aRect.Bottom() + 1 ); + ImplWriteLong( aRectIter->Right() + 1 ); + ImplWriteLong( aRectIter->Bottom() + 1 ); ImplWriteByte( 'l' ); - ImplWriteLong( aRect.Left() ); - ImplWriteLong( aRect.Bottom() + 1 ); + ImplWriteLong( aRectIter->Left() ); + ImplWriteLong( aRectIter->Bottom() + 1 ); ImplWriteByte( 'l' ); ImplWriteByte( 'p', PS_SPACE | PS_WRAP ); - }; - aRegion.EndEnumRects( hRegionHandle ); + } + + //RegionHandle hRegionHandle = aRegion.BeginEnumRects(); + // + //while ( aRegion.GetEnumRects( hRegionHandle, aRect ) ) + //{ + // aRect.Move( 0, - ( nHeightOrg - nHeightLeft ) ); + // ImplWriteLong( aRect.Left() ); + // ImplWriteLong( aRect.Top() ); + // ImplWriteByte( 'm' ); + // ImplWriteLong( aRect.Right() + 1 ); + // ImplWriteLong( aRect.Top() ); + // ImplWriteByte( 'l' ); + // ImplWriteLong( aRect.Right() + 1 ); + // ImplWriteLong( aRect.Bottom() + 1 ); + // ImplWriteByte( 'l' ); + // ImplWriteLong( aRect.Left() ); + // ImplWriteLong( aRect.Bottom() + 1 ); + // ImplWriteByte( 'l' ); + // ImplWriteByte( 'p', PS_SPACE | PS_WRAP ); + //}; + //aRegion.EndEnumRects( hRegionHandle ); ImplWriteLine( "eoclip newpath" ); ImplWriteLine( "pom" ); } diff --git a/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx b/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx index 89d750449cf2..de560b64f77d 100644 --- a/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx +++ b/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx @@ -79,19 +79,26 @@ void DeviceCopy ( void ForAllRectangles (const Region& rRegion, ::boost::function<void(const Rectangle&)> aFunction) { OSL_ASSERT(aFunction); + RectangleVector aRectangles; + rRegion.GetRegionRectangles(aRectangles); - if (rRegion.GetRectCount() <= 1) + if(0 == aRectangles.size()) { - aFunction(rRegion.GetBoundRect()); + aFunction(Rectangle()); } else { - Region aMutableRegionCopy (rRegion); - RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects()); - Rectangle aBox; - while (aMutableRegionCopy.GetNextEnumRect(aHandle, aBox)) - aFunction(aBox); - aMutableRegionCopy.EndEnumRects(aHandle); + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) + { + aFunction(*aRectIter); + } + + //Region aMutableRegionCopy (rRegion); + //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects()); + //Rectangle aBox; + //while (aMutableRegionCopy.GetEnumRects(aHandle, aBox)) + // aFunction(aBox); + //aMutableRegionCopy.EndEnumRects(aHandle); } } diff --git a/svx/source/sdr/overlay/overlaymanagerbuffered.cxx b/svx/source/sdr/overlay/overlaymanagerbuffered.cxx index 17b30ed724af..7c2879628b1e 100644 --- a/svx/source/sdr/overlay/overlaymanagerbuffered.cxx +++ b/svx/source/sdr/overlay/overlaymanagerbuffered.cxx @@ -116,33 +116,33 @@ namespace sdr void OverlayManagerBuffered::ImpRestoreBackground(const Region& rRegionPixel) const { - // local region - Region aRegionPixel(rRegionPixel); - RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects()); - Rectangle aRegionRectanglePixel; - // MapModes off const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled()); const bool bMapModeWasEnabledSource(maBufferDevice.IsMapModeEnabled()); getOutputDevice().EnableMapMode(false); ((OverlayManagerBuffered*)this)->maBufferDevice.EnableMapMode(false); - while(aRegionPixel.GetEnumRects(aRegionHandle, aRegionRectanglePixel)) + // local region + RectangleVector aRectangles; + rRegionPixel.GetRegionRectangles(aRectangles); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { #ifdef DBG_UTIL // #i72754# possible graphical region test only with non-pro static bool bDoPaintForVisualControl(false); + if(bDoPaintForVisualControl) { getOutputDevice().SetLineColor(COL_LIGHTGREEN); getOutputDevice().SetFillColor(); - getOutputDevice().DrawRect(aRegionRectanglePixel); + getOutputDevice().DrawRect(*aRectIter); } #endif // restore the area - const Point aTopLeft(aRegionRectanglePixel.TopLeft()); - const Size aSize(aRegionRectanglePixel.GetSize()); + const Point aTopLeft(aRectIter->TopLeft()); + const Size aSize(aRectIter->GetSize()); getOutputDevice().DrawOutDev( aTopLeft, aSize, // destination @@ -150,7 +150,33 @@ namespace sdr maBufferDevice); } - aRegionPixel.EndEnumRects(aRegionHandle); + //Region aRegionPixel(rRegionPixel); + //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects()); + //Rectangle aRegionRectanglePixel; + // + //while(aRegionPixel.GetEnumRects(aRegionHandle, aRegionRectanglePixel)) + //{ +#ifdef DBG_U//TIL + // // #i72754# possible graphical region test only with non-pro + // static bool bDoPaintForVisualControl(false); + // if(bDoPaintForVisualControl) + // { + // getOutputDevice().SetLineColor(COL_LIGHTGREEN); + // getOutputDevice().SetFillColor(); + // getOutputDevice().DrawRect(aRegionRectanglePixel); + // } +#endif // + // // restore the area + // const Point aTopLeft(aRegionRectanglePixel.TopLeft()); + // const Size aSize(aRegionRectanglePixel.GetSize()); + // + // getOutputDevice().DrawOutDev( + // aTopLeft, aSize, // destination + // aTopLeft, aSize, // source + // maBufferDevice); + //} + // + //aRegionPixel.EndEnumRects(aRegionHandle); // restore MapModes getOutputDevice().EnableMapMode(bMapModeWasEnabledDest); @@ -182,24 +208,24 @@ namespace sdr } // also limit to buffer size - const Rectangle aBufferDeviceRectanglePixel = Rectangle(Point(), maBufferDevice.GetOutputSizePixel()); + const Rectangle aBufferDeviceRectanglePixel(Point(), maBufferDevice.GetOutputSizePixel()); aRegion.Intersect(aBufferDeviceRectanglePixel); - // prepare to iterate over the rectangles from the region in pixels - RegionHandle aRegionHandle(aRegion.BeginEnumRects()); - Rectangle aRegionRectanglePixel; - // MapModes off const bool bMapModeWasEnabledDest(rSource.IsMapModeEnabled()); const bool bMapModeWasEnabledSource(maBufferDevice.IsMapModeEnabled()); rSource.EnableMapMode(false); maBufferDevice.EnableMapMode(false); - while(aRegion.GetEnumRects(aRegionHandle, aRegionRectanglePixel)) + // prepare to iterate over the rectangles from the region in pixels + RectangleVector aRectangles; + aRegion.GetRegionRectangles(aRectangles); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { // for each rectangle, save the area - Point aTopLeft(aRegionRectanglePixel.TopLeft()); - Size aSize(aRegionRectanglePixel.GetSize()); + const Point aTopLeft(aRectIter->TopLeft()); + const Size aSize(aRectIter->GetSize()); maBufferDevice.DrawOutDev( aTopLeft, aSize, // destination @@ -209,17 +235,20 @@ namespace sdr #ifdef DBG_UTIL // #i72754# possible graphical region test only with non-pro static bool bDoPaintForVisualControl(false); + if(bDoPaintForVisualControl) { const bool bMapModeWasEnabledTest(getOutputDevice().IsMapModeEnabled()); + getOutputDevice().EnableMapMode(false); getOutputDevice().SetLineColor(COL_LIGHTRED); getOutputDevice().SetFillColor(); - getOutputDevice().DrawRect(aRegionRectanglePixel); + getOutputDevice().DrawRect(*aRectIter); getOutputDevice().EnableMapMode(bMapModeWasEnabledTest); } static bool bDoSaveForVisualControl(false); + if(bDoSaveForVisualControl) { const Bitmap aBitmap(maBufferDevice.GetBitmap(aTopLeft, aSize)); @@ -229,7 +258,44 @@ namespace sdr #endif } - aRegion.EndEnumRects(aRegionHandle); + //RegionHandle aRegionHandle(aRegion.BeginEnumRects()); + //Rectangle aRegionRectanglePixel; + // + //while(aRegion.GetEnumRects(aRegionHandle, aRegionRectanglePixel)) + //{ + // // for each rectangle, save the area + // Point aTopLeft(aRegionRectanglePixel.TopLeft()); + // Size aSize(aRegionRectanglePixel.GetSize()); + // + // maBufferDevice.DrawOutDev( + // aTopLeft, aSize, // destination + // aTopLeft, aSize, // source + // rSource); + // +#ifdef DBG_U//TIL + // // #i72754# possible graphical region test only with non-pro + // static bool bDoPaintForVisualControl(false); + // if(bDoPaintForVisualControl) + // { + // const bool bMapModeWasEnabledTest(getOutputDevice().IsMapModeEnabled()); + // getOutputDevice().EnableMapMode(false); + // getOutputDevice().SetLineColor(COL_LIGHTRED); + // getOutputDevice().SetFillColor(); + // getOutputDevice().DrawRect(aRegionRectanglePixel); + // getOutputDevice().EnableMapMode(bMapModeWasEnabledTest); + // } + // + // static bool bDoSaveForVisualControl(false); + // if(bDoSaveForVisualControl) + // { + // const Bitmap aBitmap(maBufferDevice.GetBitmap(aTopLeft, aSize)); + // SvFileStream aNew((const String&)String(ByteString( "c:\\test.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); + // aNew << aBitmap; + // } +#endif // + //} + // + //aRegion.EndEnumRects(aRegionHandle); // restore MapModes rSource.EnableMapMode(bMapModeWasEnabledDest); diff --git a/svx/source/sdr/properties/itemsettools.cxx b/svx/source/sdr/properties/itemsettools.cxx index 10c9af6f2907..bb3057fe1e86 100644 --- a/svx/source/sdr/properties/itemsettools.cxx +++ b/svx/source/sdr/properties/itemsettools.cxx @@ -27,10 +27,9 @@ #include <tools/debug.hxx> #include <svl/itemset.hxx> #include <svl/whiter.hxx> - -#include <vector> #include <svx/svdogrp.hxx> #include <svx/svditer.hxx> +#include <vcl/region.hxx> ////////////////////////////////////////////////////////////////////////////// // class to remember broadcast start positions @@ -39,9 +38,6 @@ namespace sdr { namespace properties { - // helper vector to remember rectangles - typedef ::std::vector< Rectangle > RectangleVector; - ItemChangeBroadcaster::ItemChangeBroadcaster(const SdrObject& rObj) { if(rObj.ISA(SdrObjGroup)) diff --git a/svx/source/svdraw/sdrpaintwindow.cxx b/svx/source/svdraw/sdrpaintwindow.cxx index 9b421606b330..42f84ca7156b 100644 --- a/svx/source/svdraw/sdrpaintwindow.cxx +++ b/svx/source/svdraw/sdrpaintwindow.cxx @@ -62,9 +62,9 @@ void SdrPreRenderDevice::PreparePreRenderDevice() void SdrPreRenderDevice::OutputPreRenderDevice(const Region& rExpandedRegion) { // region to pixels - Region aRegionPixel(mrOutputDevice.LogicToPixel(rExpandedRegion)); - RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects()); - Rectangle aRegionRectanglePixel; + const Region aRegionPixel(mrOutputDevice.LogicToPixel(rExpandedRegion)); + //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects()); + //Rectangle aRegionRectanglePixel; // MapModes off sal_Bool bMapModeWasEnabledDest(mrOutputDevice.IsMapModeEnabled()); @@ -72,11 +72,14 @@ void SdrPreRenderDevice::OutputPreRenderDevice(const Region& rExpandedRegion) mrOutputDevice.EnableMapMode(sal_False); maPreRenderDevice.EnableMapMode(sal_False); - while(aRegionPixel.GetEnumRects(aRegionHandle, aRegionRectanglePixel)) + RectangleVector aRectangles; + aRegionPixel.GetRegionRectangles(aRectangles); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { // for each rectangle, copy the area - const Point aTopLeft(aRegionRectanglePixel.TopLeft()); - const Size aSize(aRegionRectanglePixel.GetSize()); + const Point aTopLeft(aRectIter->TopLeft()); + const Size aSize(aRectIter->GetSize()); mrOutputDevice.DrawOutDev( aTopLeft, aSize, @@ -86,17 +89,43 @@ void SdrPreRenderDevice::OutputPreRenderDevice(const Region& rExpandedRegion) #ifdef DBG_UTIL // #i74769# static bool bDoPaintForVisualControlRegion(false); + if(bDoPaintForVisualControlRegion) { - Color aColor((((((rand()&0x7f)|0x80)<<8L)|((rand()&0x7f)|0x80))<<8L)|((rand()&0x7f)|0x80)); + const Color aColor((((((rand()&0x7f)|0x80)<<8L)|((rand()&0x7f)|0x80))<<8L)|((rand()&0x7f)|0x80)); + mrOutputDevice.SetLineColor(aColor); mrOutputDevice.SetFillColor(); - mrOutputDevice.DrawRect(aRegionRectanglePixel); + mrOutputDevice.DrawRect(*aRectIter); } #endif } - aRegionPixel.EndEnumRects(aRegionHandle); +// while(aRegionPixel.GetEnumRects(aRegionHandle, aRegionRectanglePixel)) +// { +// // for each rectangle, copy the area +// const Point aTopLeft(aRegionRectanglePixel.TopLeft()); +// const Size aSize(aRegionRectanglePixel.GetSize()); +// +// mrOutputDevice.DrawOutDev( +// aTopLeft, aSize, +// aTopLeft, aSize, +// maPreRenderDevice); +// +//#ifdef DBG_UTIL +// // #i74769# +// static bool bDoPaintForVisualControlRegion(false); +// if(bDoPaintForVisualControlRegion) +// { +// Color aColor((((((rand()&0x7f)|0x80)<<8L)|((rand()&0x7f)|0x80))<<8L)|((rand()&0x7f)|0x80)); +// mrOutputDevice.SetLineColor(aColor); +// mrOutputDevice.SetFillColor(); +// mrOutputDevice.DrawRect(aRegionRectanglePixel); +// } +//#endif +// } +// +// aRegionPixel.EndEnumRects(aRegionHandle); mrOutputDevice.EnableMapMode(bMapModeWasEnabledDest); maPreRenderDevice.EnableMapMode(bMapModeWasEnabledSource); diff --git a/svx/source/svdraw/svdfmtf.cxx b/svx/source/svdraw/svdfmtf.cxx index 1397dffb6aae..d164cb1ed913 100644 --- a/svx/source/svdraw/svdfmtf.cxx +++ b/svx/source/svdraw/svdfmtf.cxx @@ -809,9 +809,7 @@ void ImpSdrGDIMetaFileImport::checkClip() { if(maVD.IsClipRegion()) { - Region aRegion(maVD.GetClipRegion()); - - maClip = aRegion.ConvertToB2DPolyPolygon(); + maClip = maVD.GetClipRegion().GetAsB2DPolyPolygon(); if(isClip()) { diff --git a/svx/source/svdraw/svdpntv.cxx b/svx/source/svdraw/svdpntv.cxx index 83fd7a3daf7d..e8b62af6cfb4 100644 --- a/svx/source/svdraw/svdpntv.cxx +++ b/svx/source/svdraw/svdpntv.cxx @@ -806,19 +806,31 @@ void SdrPaintView::CompleteRedraw(OutputDevice* pOut, const Region& rReg, sdr::c #ifdef DBG_UTIL // #i74769# test-paint repaint region static bool bDoPaintForVisualControl(false); + if(bDoPaintForVisualControl) { - RegionHandle aRegionHandle(aOptimizedRepaintRegion.BeginEnumRects()); - Rectangle aRegionRectangle; + RectangleVector aRectangles; + aOptimizedRepaintRegion.GetRegionRectangles(aRectangles); + + pWindow->SetLineColor(COL_LIGHTGREEN); + pWindow->SetFillColor(); - while(aOptimizedRepaintRegion.GetEnumRects(aRegionHandle, aRegionRectangle)) + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - pWindow->SetLineColor(COL_LIGHTGREEN); - pWindow->SetFillColor(); - pWindow->DrawRect(aRegionRectangle); + pWindow->DrawRect(*aRectIter); } - aOptimizedRepaintRegion.EndEnumRects(aRegionHandle); + //RegionHandle aRegionHandle(aOptimizedRepaintRegion.BeginEnumRects()); + //Rectangle aRegionRectangle; + // + //while(aOptimizedRepaintRegion.GetEnumRects(aRegionHandle, aRegionRectangle)) + //{ + // pWindow->SetLineColor(COL_LIGHTGREEN); + // pWindow->SetFillColor(); + // pWindow->DrawRect(aRegionRectangle); + //} + // + //aOptimizedRepaintRegion.EndEnumRects(aRegionHandle); } #endif } @@ -988,19 +1000,31 @@ SdrPaintWindow* SdrPaintView::BeginDrawLayers(OutputDevice* pOut, const Region& #ifdef DBG_UTIL // #i74769# test-paint repaint region static bool bDoPaintForVisualControl(false); + if(bDoPaintForVisualControl) { - RegionHandle aRegionHandle(aOptimizedRepaintRegion.BeginEnumRects()); - Rectangle aRegionRectangle; + RectangleVector aRectangles; + aOptimizedRepaintRegion.GetRegionRectangles(aRectangles); + + pWindow->SetLineColor(COL_LIGHTGREEN); + pWindow->SetFillColor(); - while(aOptimizedRepaintRegion.GetEnumRects(aRegionHandle, aRegionRectangle)) + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - pWindow->SetLineColor(COL_LIGHTGREEN); - pWindow->SetFillColor(); - pWindow->DrawRect(aRegionRectangle); + pWindow->DrawRect(*aRectIter); } - aOptimizedRepaintRegion.EndEnumRects(aRegionHandle); + //RegionHandle aRegionHandle(aOptimizedRepaintRegion.BeginEnumRects()); + //Rectangle aRegionRectangle; + // + //while(aOptimizedRepaintRegion.GetEnumRects(aRegionHandle, aRegionRectangle)) + //{ + // pWindow->SetLineColor(COL_LIGHTGREEN); + // pWindow->SetFillColor(); + // pWindow->DrawRect(aRegionRectangle); + //} + // + //aOptimizedRepaintRegion.EndEnumRects(aRegionHandle); } #endif } diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx index 2a24e87055e4..c8db1db6d8d3 100644 --- a/sw/source/core/view/viewsh.cxx +++ b/sw/source/core/view/viewsh.cxx @@ -2004,12 +2004,20 @@ void ViewShell::Paint(const Rectangle &rRect) if ( bInEndAction && GetWin() ) { - Region aRegion( GetWin()->GetPaintRegion() ); - RegionHandle hHdl( aRegion.BeginEnumRects() ); - Rectangle aRect; - while ( aRegion.GetNextEnumRect( hHdl, aRect ) ) - Imp()->AddPaintRect( aRect ); - aRegion.EndEnumRects( hHdl ); + const Region aRegion(GetWin()->GetPaintRegion()); + RectangleVector aRectangles; + aRegion.GetRegionRectangles(aRectangles); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) + { + Imp()->AddPaintRect(*aRectIter); + } + + //RegionHandle hHdl( aRegion.BeginEnumRects() ); + //Rectangle aRect; + //while ( aRegion.GetEnumRects( hHdl, aRect ) ) + // Imp()->AddPaintRect( aRect ); + //aRegion.EndEnumRects( hHdl ); } else if ( SfxProgress::GetActiveProgress( GetDoc()->GetDocShell() ) && GetOut() == GetWin() ) diff --git a/toolkit/source/awt/vclxregion.cxx b/toolkit/source/awt/vclxregion.cxx index 15942e635331..bd1696da270c 100644 --- a/toolkit/source/awt/vclxregion.cxx +++ b/toolkit/source/awt/vclxregion.cxx @@ -150,15 +150,24 @@ void VCLXRegion::xOrRegion( const ::com::sun::star::uno::Reference< ::com::sun:: { ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); - sal_uLong nRects = maRegion.GetRectCount(); - ::com::sun::star::uno::Sequence< ::com::sun::star::awt::Rectangle > aRects( nRects ); - - Rectangle aRect; - sal_uInt32 nR = 0; - RegionHandle h = maRegion.BeginEnumRects(); - while ( maRegion.GetNextEnumRect( h, aRect ) ) - aRects.getArray()[nR++] = AWTRectangle( aRect ); - maRegion.EndEnumRects( h ); + RectangleVector aRectangles; + maRegion.GetRegionRectangles(aRectangles); + +// sal_uLong nRects = maRegion.GetRectCount(); + ::com::sun::star::uno::Sequence< ::com::sun::star::awt::Rectangle > aRects(aRectangles.size()); + sal_uInt32 a(0); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) + { + aRects.getArray()[a++] = AWTRectangle(*aRectIter); + } + + //Rectangle aRect; + //sal_uInt32 nR = 0; + //RegionHandle h = maRegion.BeginEnumRects(); + //while ( maRegion.GetEnumRects( h, aRect ) ) + // aRects.getArray()[nR++] = AWTRectangle( aRect ); + //maRegion.EndEnumRects( h ); return aRects; } diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 3cd0073bc357..734934c79a80 100755 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -377,6 +377,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/gdi/print \ vcl/source/gdi/regband \ vcl/source/gdi/region \ + vcl/source/gdi/regionband \ vcl/source/gdi/salgdilayout \ vcl/source/gdi/sallayout \ vcl/source/gdi/salmisc \ diff --git a/vcl/aqua/source/gdi/salgdi.cxx b/vcl/aqua/source/gdi/salgdi.cxx index 93a0b394ae28..b448538cdf09 100644 --- a/vcl/aqua/source/gdi/salgdi.cxx +++ b/vcl/aqua/source/gdi/salgdi.cxx @@ -50,7 +50,6 @@ #include "fontsubset.hxx" #include "impfont.hxx" -#include "region.h" #include "sallayout.hxx" #include "sft.hxx" @@ -572,24 +571,31 @@ bool AquaSalGraphics::setClipRegion( const Region& i_rClip ) mxClipPath = CGPathCreateMutable(); // set current path, either as polypolgon or sequence of rectangles - if( i_rClip.HasPolyPolygon() ) + if(i_rClip.HasPolyPolygonOrB2DPolyPolygon()) { - basegfx::B2DPolyPolygon aClip( const_cast<Region&>(i_rClip).ConvertToB2DPolyPolygon() ); + const basegfx::B2DPolyPolygon aClip(i_rClip.GetAsB2DPolyPolygon()); + AddPolyPolygonToPath( mxClipPath, aClip, !getAntiAliasB2DDraw(), false ); } else { - long nX, nY, nW, nH; - ImplRegionInfo aInfo; - bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); - while( bRegionRect ) + RectangleVector aRectangles; + i_rClip.GetRegionRectangles(aRectangles); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - if( nW && nH ) + const long nW(aRectIter->Right() - aRectIter->Left() + 1); // uses +1 logic in original + + if(nW) { - CGRect aRect = {{nX,nY}, {nW,nH}}; - CGPathAddRect( mxClipPath, NULL, aRect ); + const long nH(aRectIter->Bottom() - aRectIter->Top() + 1); // uses +1 logic in original + + if(nH) + { + CGRect aRect = {{ aRectIter->Left(), aRectIter->Top() }, { nW, nH }}; + CGPathAddRect( mxClipPath, NULL, aRect ); + } } - bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); } } // set the current path as clip region diff --git a/vcl/inc/region.h b/vcl/inc/region.h deleted file mode 100644 index 3595b2097919..000000000000 --- a/vcl/inc/region.h +++ /dev/null @@ -1,130 +0,0 @@ -/************************************************************** - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - *************************************************************/ - - - -#ifndef _SV_REGION_H -#define _SV_REGION_H - -#include <vcl/regband.hxx> -#include <tools/poly.hxx> -#include <vcl/region.hxx> - -// ----------------- -// - Hilfsmethoden - -// ----------------- - -#ifdef DBG_UTIL -const char* ImplDbgTestRegion( const void* pObj ); -#endif - -// -------------------- -// - ImplRegionHandle - -// -------------------- - -struct ImplRegionHandle -{ - Region* mpRegion; - ImplRegionBand* mpCurrRectBand; - ImplRegionBandSep* mpCurrRectBandSep; - sal_Bool mbFirst; -}; - -// ------------------ -// - ImplRegionInfo - -// ------------------ - -struct ImplRegionInfo -{ - void* mpVoidCurrRectBand; - void* mpVoidCurrRectBandSep; -}; - -// -------------- -// - ImplRegion - -// -------------- - -struct ImplRegionBase -{ -public: - ImplRegionBase( int nCount = 1 ); // TODO: replace manual refcounting - virtual ~ImplRegionBase(); -public: - sal_uIntPtr mnRefCount; - sal_uIntPtr mnRectCount; - PolyPolygon* mpPolyPoly; - basegfx::B2DPolyPolygon* mpB2DPolyPoly; -}; - -class ImplRegion : public ImplRegionBase -{ - friend class Region; - -private: - ImplRegionBand* mpFirstBand; // root of the list with y-bands - ImplRegionBand* mpLastCheckedBand; - -public: - ImplRegion(); - ImplRegion( const PolyPolygon& rPolyPoly ); - ImplRegion( const basegfx::B2DPolyPolygon& ); - ImplRegion( const ImplRegion& rImplRegion ); - ~ImplRegion(); - - ImplRegionBand* ImplGetFirstRegionBand() const { return mpFirstBand; } - PolyPolygon* ImplGetPolyPoly() const { return mpPolyPoly; } - - void CreateBandRange( long nYTop, long nYBottom ); - void InsertBands( long nYTop, long nYBottom ); - sal_Bool InsertSingleBand( ImplRegionBand* mpImplRegionBand, - long nYBandPosition ); - sal_Bool InsertLine( const Point & rFirstPoint, - const Point & rSecondPoint, - long nLineID ); - sal_Bool InsertPoint( const Point &rPoint, - long nLineID, - sal_Bool bEndPoint, LineType eLineType ); - - /** Insert one band either after another band or as the first or only - band. Both the forward as well as the backward links are updated. - @param pPreviousBand - When <NULL/> then pBandToInsert is inserted as first band or as - only band when there are no other bands. - When not <NULL/> then pBandToInsert is inserted directly after - pPreviousBand. - @param pBandToInsert - The band to insert. - */ - void InsertBand (ImplRegionBand* pPreviousBand, - ImplRegionBand* pBandToInsert); - - void Union( long nLeft, long nTop, long nRight, long nBottom ); - void Exclude( long nLeft, long nTop, long nRight, long nBottom ); - void XOr( long nLeft, long nTop, long nRight, long nBottom ); - - // remove emtpy rects - sal_Bool OptimizeBandList(); - - friend SvStream& operator>>( SvStream& rIStm, Region& rRegion ); - friend SvStream& operator<<( SvStream& rOStm, const Region& rRegion ); -}; - -#endif // _SV_REGION_H diff --git a/vcl/inc/regionband.hxx b/vcl/inc/regionband.hxx new file mode 100755 index 000000000000..58c45ed106e0 --- /dev/null +++ b/vcl/inc/regionband.hxx @@ -0,0 +1,87 @@ +/************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + *************************************************************/ + +#ifndef _SV_REGIONBAND_HXX +#define _SV_REGIONBAND_HXX + +#include <vcl/regband.hxx> +#include <vcl/region.hxx> + +#ifdef DBG_UTIL +const char* ImplDbgTestRegionBand(const void*); +#endif + +////////////////////////////////////////////////////////////////////////////// + +class RegionBand +{ +private: + friend const char* ImplDbgTestRegionBand(const void*); + + ImplRegionBand* mpFirstBand; // root of the list with y-bands + ImplRegionBand* mpLastCheckedBand; + + void implReset(); + +public: + RegionBand(); + RegionBand(const RegionBand&); + RegionBand& operator=(const RegionBand&); + RegionBand(const Rectangle&); + ~RegionBand(); + + bool operator==( const RegionBand& rRegionBand ) const; + bool operator!=( const RegionBand& rRegionBand ) const { return !(RegionBand::operator==( rRegionBand )); } + + void load(SvStream& rIStrm); + void save(SvStream& rIStrm) const; + + bool isSingleRectangle() const; + ImplRegionBand* ImplGetFirstRegionBand() const { return mpFirstBand; } + void ImplAddMissingBands(const long nTop, const long nBottom); + void InsertBand(ImplRegionBand* pPreviousBand, ImplRegionBand* pBandToInsert); + void processPoints(); + void CreateBandRange(long nYTop, long nYBottom); + bool InsertLine(const Point& rStartPt, const Point& rEndPt, long nLineId); + bool InsertPoint(const Point &rPoint, long nLineID, bool bEndPoint, LineType eLineType); + bool OptimizeBandList(); + void Move(long nHorzMove, long nVertMove); + void Scale(double fScaleX, double fScaleY); + void InsertBands(long nTop, long nBottom); + bool InsertSingleBand(ImplRegionBand* pBand, long nYBandPosition); + void Union(long nLeft, long nTop, long nRight, long nBottom); + void Intersect(long nLeft, long nTop, long nRight, long nBottom); + void Union(const RegionBand& rSource); + void Exclude(long nLeft, long nTop, long nRight, long nBottom); + void XOr(long nLeft, long nTop, long nRight, long nBottom); + void Intersect(const RegionBand& rSource); + bool Exclude(const RegionBand& rSource); + void XOr(const RegionBand& rSource); + Rectangle GetBoundRect() const; + bool IsInside(const Point& rPoint) const; + sal_uInt32 getRectangleCount() const; // only users are Region::Intersect and PSWriter::ImplBmp + void GetRegionRectangles(RectangleVector& rTarget) const; +}; + +#endif // _SV_REGIONBAND_HXX + +////////////////////////////////////////////////////////////////////////////// +//eof diff --git a/vcl/inc/unx/gtk/gtkgdi.hxx b/vcl/inc/unx/gtk/gtkgdi.hxx index 2d7269cf4a04..0f7ec041b5ed 100644 --- a/vcl/inc/unx/gtk/gtkgdi.hxx +++ b/vcl/inc/unx/gtk/gtkgdi.hxx @@ -40,7 +40,7 @@ class GtkSalGraphics : public X11SalGraphics public: GtkSalGraphics( GtkWidget *window ) : m_pWindow( window ), - m_aClipRegion( REGION_NULL ) + m_aClipRegion(true) {} virtual ~GtkSalGraphics(); diff --git a/vcl/inc/vcl/regband.hxx b/vcl/inc/vcl/regband.hxx index 962dc821033d..5987d02a6eaa 100644 --- a/vcl/inc/vcl/regband.hxx +++ b/vcl/inc/vcl/regband.hxx @@ -53,7 +53,7 @@ struct ImplRegionBandSep ImplRegionBandSep* mpNextSep; long mnXLeft; long mnXRight; - sal_Bool mbRemoved; + bool mbRemoved; }; enum LineType { LINE_ASCENDING, LINE_DESCENDING, LINE_HORIZONTAL }; @@ -64,7 +64,7 @@ struct ImplRegionBandPoint ImplRegionBandPoint* mpNextBandPoint; long mnX; long mnLineId; - sal_Bool mbEndPoint; + bool mbEndPoint; LineType meLineType; }; @@ -81,7 +81,9 @@ public: ImplRegionBandPoint* mpFirstBandPoint; // root of the list with lines long mnYTop; // actual boundary of the band long mnYBottom; - sal_Bool mbTouched; + + // bitfield + bool mbTouched : 1; // create y-band with boundaries ImplRegionBand( long nYTop, long nYBottom ); @@ -106,14 +108,14 @@ public: long GetXRightBoundary() const; // combine overlapping bands - sal_Bool OptimizeBand(); + bool OptimizeBand(); // generate separations from lines and process // union with existing separations void ProcessPoints(); // insert point in the list for later processing - sal_Bool InsertPoint( long nX, long nLineID, - sal_Bool bEndPoint, LineType eLineType ); + bool InsertPoint( long nX, long nLineID, + bool bEndPoint, LineType eLineType ); void Union( long nXLeft, long nXRight ); void Intersect( long nXLeft, long nXRight ); @@ -123,13 +125,13 @@ public: void MoveX( long nHorzMove ); void ScaleX( double fHorzScale ); - sal_Bool IsInside( long nX ); - sal_Bool IsInside( long nLeft, long nRight ); - sal_Bool IsOver( long nLeft, long nRight ); + bool IsInside( long nX ); + bool IsInside( long nLeft, long nRight ); + bool IsOver( long nLeft, long nRight ); - sal_Bool IsEmpty() const { return ((!mpFirstSep) && (!mpFirstBandPoint)); } + bool IsEmpty() const { return ((!mpFirstSep) && (!mpFirstBandPoint)); } - sal_Bool operator==( const ImplRegionBand& rRegionBand ) const; + bool operator==( const ImplRegionBand& rRegionBand ) const; /** Split the called band at the given vertical coordinate. After the split the called band will cover the upper part not including nY. diff --git a/vcl/inc/vcl/region.hxx b/vcl/inc/vcl/region.hxx index c01be8240444..3fee7b00d1d2 100755 --- a/vcl/inc/vcl/region.hxx +++ b/vcl/inc/vcl/region.hxx @@ -19,125 +19,102 @@ * *************************************************************/ - - #ifndef _SV_REGION_HXX #define _SV_REGION_HXX #include <tools/gen.hxx> #include <vcl/sv.h> #include <vcl/dllapi.h> - #include <basegfx/polygon/b2dpolypolygon.hxx> +#include <boost/shared_ptr.hpp> -class ImplRegion; class ImplRegionBand; +class RegionBand; class Polygon; class PolyPolygon; -struct ImplRegionInfo; -// -------------- -// - RegionType - -// -------------- +////////////////////////////////////////////////////////////////////////////// -enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX }; -enum RegionOverlapType { REGION_INSIDE, REGION_OVER, REGION_OUTSIDE }; +typedef boost::shared_ptr< RegionBand > RegionBandPtr; +typedef boost::shared_ptr< PolyPolygon > PolyPolygonPtr; +typedef boost::shared_ptr< basegfx::B2DPolyPolygon > B2DPolyPolygonPtr; +typedef std::vector< Rectangle > RectangleVector; -typedef long RegionHandle; - -// ---------- -// - Region - -// ---------- +////////////////////////////////////////////////////////////////////////////// class VCL_DLLPUBLIC Region { +private: friend class OutputDevice; friend class Window; friend class Bitmap; -private: - ImplRegion* mpImplRegion; - - SAL_DLLPRIVATE void ImplCopyData(); - SAL_DLLPRIVATE void ImplCreateRectRegion( const Rectangle& rRect ); - SAL_DLLPRIVATE void ImplCreatePolyPolyRegion( const PolyPolygon& rPolyPoly ); - SAL_DLLPRIVATE void ImplCreatePolyPolyRegion( const basegfx::B2DPolyPolygon& rPolyPoly ); - SAL_DLLPRIVATE void ImplPolyPolyRegionToBandRegionFunc(); - SAL_DLLPRIVATE inline void ImplPolyPolyRegionToBandRegion(); - SAL_DLLPRIVATE const ImplRegion* ImplGetImplRegion() const { return mpImplRegion; } - SAL_DLLPRIVATE ImplRegion* ImplGetImplRegion() { return mpImplRegion; } - SAL_DLLPRIVATE void ImplBeginAddRect( ); - SAL_DLLPRIVATE sal_Bool ImplAddRect( const Rectangle& rRect ); - SAL_DLLPRIVATE void ImplEndAddRect( ); - SAL_DLLPRIVATE void ImplIntersectWithPolyPolygon( const Region& ); - SAL_DLLPRIVATE void ImplExcludePolyPolygon( const Region& ); - SAL_DLLPRIVATE void ImplUnionPolyPolygon( const Region& ); - SAL_DLLPRIVATE void ImplXOrPolyPolygon( const Region& ); - -public: // public within vcl - VCL_PLUGIN_PUBLIC bool ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo, - long& nX, long& nY, long& nWidth, long& nHeight ) const; - VCL_PLUGIN_PUBLIC bool ImplGetNextRect( ImplRegionInfo& rImplRegionInfo, - long& nX, long& nY, long& nWidth, long& nHeight ) const; -#ifdef DBG_UTIL - friend const char* ImplDbgTestRegion( const void* pObj ); -#endif + // possible contents + B2DPolyPolygonPtr mpB2DPolyPolygon; + PolyPolygonPtr mpPolyPolygon; + RegionBandPtr mpRegionBand; + + /// bitfield + bool mbIsNull : 1; + + // helpers + SAL_DLLPRIVATE void ImplCreatePolyPolyRegion( const PolyPolygon& rPolyPoly ); + SAL_DLLPRIVATE void ImplCreatePolyPolyRegion( const basegfx::B2DPolyPolygon& rPolyPoly ); + + SAL_DLLPRIVATE PolyPolygon ImplCreatePolyPolygonFromRegionBand() const; + SAL_DLLPRIVATE basegfx::B2DPolyPolygon ImplCreateB2DPolyPolygonFromRegionBand() const; public: - Region(); - Region( RegionType eType ); - Region( const Rectangle& rRect ); - Region( const Polygon& rPolygon ); - Region( const PolyPolygon& rPolyPoly ); - Region( const basegfx::B2DPolyPolygon& ); - Region( const Region& rRegion ); - ~Region(); - - void Move( long nHorzMove, long nVertMove ); - void Scale( double fScaleX, double fScaleY ); - sal_Bool Union( const Rectangle& rRegion ); - sal_Bool Intersect( const Rectangle& rRegion ); - sal_Bool Exclude( const Rectangle& rRegion ); - sal_Bool XOr( const Rectangle& rRegion ); - sal_Bool Union( const Region& rRegion ); - sal_Bool Intersect( const Region& rRegion ); - sal_Bool Exclude( const Region& rRegion ); - sal_Bool XOr( const Region& rRegion ); - - RegionType GetType() const; - sal_Bool IsEmpty() const { return GetType() == REGION_EMPTY; }; - sal_Bool IsNull() const { return GetType() == REGION_NULL; }; - - void SetEmpty(); - void SetNull(); - - Rectangle GetBoundRect() const; - - sal_Bool HasPolyPolygon() const; - PolyPolygon GetPolyPolygon() const; - // returns an empty polypolygon in case HasPolyPolygon is sal_False - const basegfx::B2DPolyPolygon GetB2DPolyPolygon() const; - // returns a PolyPolygon either copied from the set PolyPolygon region - // or created from the constituent rectangles - basegfx::B2DPolyPolygon ConvertToB2DPolyPolygon(); - - sal_uLong GetRectCount() const; - RegionHandle BeginEnumRects(); - sal_Bool GetEnumRects( RegionHandle hRegionHandle, Rectangle& rRect ); - sal_Bool GetNextEnumRect( RegionHandle hRegionHandle, Rectangle& rRect ) - { return GetEnumRects( hRegionHandle, rRect ); } - void EndEnumRects( RegionHandle hRegionHandle ); - - sal_Bool IsInside( const Point& rPoint ) const; - sal_Bool IsInside( const Rectangle& rRect ) const; - sal_Bool IsOver( const Rectangle& rRect ) const; - - Region& operator=( const Region& rRegion ); - Region& operator=( const Rectangle& rRect ); - - sal_Bool operator==( const Region& rRegion ) const; - sal_Bool operator!=( const Region& rRegion ) const - { return !(Region::operator==( rRegion )); } + Region(bool bIsNull = false); // default creates empty region, with true a null region is created + Region(const Rectangle& rRect); + Region(const Polygon& rPolygon); + Region(const PolyPolygon& rPolyPoly); + Region(const basegfx::B2DPolyPolygon&); + Region(const Region& rRegion); + ~Region(); + + // direct access to contents + const basegfx::B2DPolyPolygon* getB2DPolyPolygon() const { return mpB2DPolyPolygon.get(); } + const PolyPolygon* getPolyPolygon() const { return mpPolyPolygon.get(); } + const RegionBand* getRegionBand() const { return mpRegionBand.get(); } + + // access with converters, the asked data will be created from the most + // valuable data, buffered and returned + const PolyPolygon GetAsPolyPolygon() const; + const basegfx::B2DPolyPolygon GetAsB2DPolyPolygon() const; + const RegionBand* GetAsRegionBand() const; + + // manipulators + void Move( long nHorzMove, long nVertMove ); + void Scale( double fScaleX, double fScaleY ); + bool Union( const Rectangle& rRegion ); + bool Intersect( const Rectangle& rRegion ); + bool Exclude( const Rectangle& rRegion ); + bool XOr( const Rectangle& rRegion ); + bool Union( const Region& rRegion ); + bool Intersect( const Region& rRegion ); + bool Exclude( const Region& rRegion ); + bool XOr( const Region& rRegion ); + + bool IsEmpty() const; + bool IsNull() const; + + void SetEmpty(); + void SetNull(); + + Rectangle GetBoundRect() const; + bool HasPolyPolygonOrB2DPolyPolygon() const { return (getB2DPolyPolygon() || getPolyPolygon()); } + void GetRegionRectangles(RectangleVector& rTarget) const; + + bool IsInside( const Point& rPoint ) const; + bool IsInside( const Rectangle& rRect ) const; + bool IsOver( const Rectangle& rRect ) const; + + Region& operator=( const Region& rRegion ); + Region& operator=( const Rectangle& rRect ); + + bool operator==( const Region& rRegion ) const; + bool operator!=( const Region& rRegion ) const { return !(Region::operator==( rRegion )); } friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, Region& rRegion ); friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const Region& rRegion ); @@ -155,3 +132,6 @@ public: }; #endif // _SV_REGION_HXX + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/vcl/os2/source/gdi/salgdi.cxx b/vcl/os2/source/gdi/salgdi.cxx index 20c6d1388e07..9bb54096732d 100644 --- a/vcl/os2/source/gdi/salgdi.cxx +++ b/vcl/os2/source/gdi/salgdi.cxx @@ -35,8 +35,6 @@ #include <rtl/strbuf.hxx> #endif -#include <region.h> - #ifndef __H_FT2LIB #include <os2/wingdi.h> #include <ft2lib.h> @@ -217,27 +215,48 @@ void Os2SalGraphics::ResetClipRegion() bool Os2SalGraphics::setClipRegion( const Region& i_rClip ) { - ULONG nCount = i_rClip.GetRectCount(); - - mpClipRectlAry = new RECTL[ nCount ]; - mnClipElementCount = 0; + RectangleVector aRectangles; + i_rClip.GetRegionRectangles(aRectangles); + mnClipElementCount = aRectangles.size(); + mpClipRectlAry = 0; - ImplRegionInfo aInfo; - long nX, nY, nW, nH; - bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); - while( bRegionRect ) + if(mnClipElementCount) { - if ( nW && nH ) + mpClipRectlAry = new RECTL[mnClipElementCount]; + + for(sal_uInt32 a(0); a < mnClipElementCount; a++) { - RECTL* pClipRect = &mpClipRectlAry[ mnClipElementCount ]; - pClipRect->xLeft = nX; - pClipRect->yTop = mnHeight - nY; - pClipRect->xRight = nX + nW; - pClipRect->yBottom = mnHeight - (nY + nH); - mnClipElementCount++; + const Rectangle& rRect = aRectangles[a]; + RECTL* pClipRect = &mpClipRectlAry[a]; + + pClipRect->xLeft = rRect.Left(); + pClipRect->yTop = mnHeight - rRect.Top(); + pClipRect->xRight = rRect.Right() + 1; // nX + nW -> L + ((R - L) + 1) -> R + 1 + pClipRect->yBottom = mnHeight - (rRect.Bottom() + 1); // same for height } - bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); } + +// ULONG nCount = i_rClip.GetRectCount(); +// +// mpClipRectlAry = new RECTL[ nCount ]; +// mnClipElementCount = 0; +// +// ImplRegionInfo aInfo; +// long nX, nY, nW, nH; +// bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); +// while( bRegionRect ) +// { +// if ( nW && nH ) +// { +// RECTL* pClipRect = &mpClipRectlAry[ mnClipElementCount ]; +// pClipRect->xLeft = nX; +// pClipRect->yTop = mnHeight - nY; +// pClipRect->xRight = nX + nW; +// pClipRect->yBottom = mnHeight - (nY + nH); +// mnClipElementCount++; +// } +// bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); +// } #ifdef SAL_PRINTER_CLIPPATH if ( mbPrinter ) { diff --git a/vcl/source/gdi/bitmap.cxx b/vcl/source/gdi/bitmap.cxx index 409cf5cf2828..0c8cb36118db 100644 --- a/vcl/source/gdi/bitmap.cxx +++ b/vcl/source/gdi/bitmap.cxx @@ -1384,38 +1384,92 @@ Region Bitmap::CreateRegion( const Color& rColor, const Rectangle& rRect ) const if( pReadAcc ) { - Rectangle aSubRect; + //Rectangle aSubRect; const long nLeft = aRect.Left(); const long nTop = aRect.Top(); const long nRight = aRect.Right(); const long nBottom = aRect.Bottom(); const BitmapColor aMatch( pReadAcc->GetBestMatchingColor( rColor ) ); - aRegion.ImplBeginAddRect(); + //RectangleVector aRectangles; + //aRegion.ImplBeginAddRect(); + std::vector< long > aLine; + long nYStart(nTop); + long nY(nTop); - for( long nY = nTop; nY <= nBottom; nY++ ) + for( ; nY <= nBottom; nY++ ) { - aSubRect.Top() = aSubRect.Bottom() = nY; + //aSubRect.Top() = aSubRect.Bottom() = nY; + std::vector< long > aNewLine; + long nX(nLeft); - for( long nX = nLeft; nX <= nRight; ) + for( ; nX <= nRight; ) { while( ( nX <= nRight ) && ( aMatch != pReadAcc->GetPixel( nY, nX ) ) ) nX++; if( nX <= nRight ) { - aSubRect.Left() = nX; + aNewLine.push_back(nX); + //aSubRect.Left() = nX; while( ( nX <= nRight ) && ( aMatch == pReadAcc->GetPixel( nY, nX ) ) ) nX++; - aSubRect.Right() = nX - 1L; - aRegion.ImplAddRect( aSubRect ); + //aSubRect.Right() = nX - 1L; + aNewLine.push_back(nX - 1); + + //aRegion.ImplAddRect( aSubRect ); + //aRectangles.push_back(aSubRect); + //aRegion.Union(aSubRect); } } + + if(aNewLine != aLine) + { + // need to write aLine, it's different from the next line + if(aLine.size()) + { + Rectangle aSubRect; + + // enter y values and proceed ystart + aSubRect.Top() = nYStart; + aSubRect.Bottom() = nY ? nY - 1 : 0; + + for(sal_uInt32 a(0); a < aLine.size();) + { + aSubRect.Left() = aLine[a++]; + aSubRect.Right() = aLine[a++]; + aRegion.Union(aSubRect); + } + } + + // copy line as new line + aLine = aNewLine; + nYStart = nY; + } } - aRegion.ImplEndAddRect(); + // write last line if used + if(aLine.size()) + { + Rectangle aSubRect; + + // enter y values + aSubRect.Top() = nYStart; + aSubRect.Bottom() = nY ? nY - 1 : 0; + + for(sal_uInt32 a(0); a < aLine.size();) + { + aSubRect.Left() = aLine[a++]; + aSubRect.Right() = aLine[a++]; + aRegion.Union(aSubRect); + } + } + + //aRegion.ImplEndAddRect(); + //aRegion.SetRegionRectangles(aRectangles); + ( (Bitmap*) this )->ReleaseAccess( pReadAcc ); } else diff --git a/vcl/source/gdi/bmpacc3.cxx b/vcl/source/gdi/bmpacc3.cxx index 59cd346c0c02..dfedfe5bbea4 100644 --- a/vcl/source/gdi/bmpacc3.cxx +++ b/vcl/source/gdi/bmpacc3.cxx @@ -317,20 +317,34 @@ void BitmapWriteAccess::FillPolygon( const Polygon& rPoly ) { const BitmapColor& rFillColor = *mpFillColor; Region aRegion( rPoly ); - Rectangle aRect; +// Rectangle aRect; aRegion.Intersect( Rectangle( Point(), Size( Width(), Height() ) ) ); if( !aRegion.IsEmpty() ) { - RegionHandle aRegHandle( aRegion.BeginEnumRects() ); + RectangleVector aRectangles; + aRegion.GetRegionRectangles(aRectangles); - while( aRegion.GetNextEnumRect( aRegHandle, aRect ) ) - for( long nY = aRect.Top(), nEndY = aRect.Bottom(); nY <= nEndY; nY++ ) - for( long nX = aRect.Left(), nEndX = aRect.Right(); nX <= nEndX; nX++ ) - SetPixel( nY, nX, rFillColor ); + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) + { + for(long nY = aRectIter->Top(), nEndY = aRectIter->Bottom(); nY <= nEndY; nY++) + { + for(long nX = aRectIter->Left(), nEndX = aRectIter->Right(); nX <= nEndX; nX++) + { + SetPixel(nY, nX, rFillColor); + } + } + } - aRegion.EndEnumRects( aRegHandle ); + //RegionHandle aRegHandle( aRegion.BeginEnumRects() ); + // + //while( aRegion.GetEnumRects( aRegHandle, aRect ) ) + // for( long nY = aRect.Top(), nEndY = aRect.Bottom(); nY <= nEndY; nY++ ) + // for( long nX = aRect.Left(), nEndX = aRect.Right(); nX <= nEndX; nX++ ) + // SetPixel( nY, nX, rFillColor ); + // + //aRegion.EndEnumRects( aRegHandle ); } } } @@ -364,20 +378,34 @@ void BitmapWriteAccess::FillPolyPolygon( const PolyPolygon& rPolyPoly ) { const BitmapColor& rFillColor = *mpFillColor; Region aRegion( rPolyPoly ); - Rectangle aRect; + //Rectangle aRect; aRegion.Intersect( Rectangle( Point(), Size( Width(), Height() ) ) ); if( !aRegion.IsEmpty() ) { - RegionHandle aRegHandle( aRegion.BeginEnumRects() ); + RectangleVector aRectangles; + aRegion.GetRegionRectangles(aRectangles); - while( aRegion.GetNextEnumRect( aRegHandle, aRect ) ) - for( long nY = aRect.Top(), nEndY = aRect.Bottom(); nY <= nEndY; nY++ ) - for( long nX = aRect.Left(), nEndX = aRect.Right(); nX <= nEndX; nX++ ) - SetPixel( nY, nX, rFillColor ); + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) + { + for(long nY = aRectIter->Top(), nEndY = aRectIter->Bottom(); nY <= nEndY; nY++) + { + for(long nX = aRectIter->Left(), nEndX = aRectIter->Right(); nX <= nEndX; nX++) + { + SetPixel(nY, nX, rFillColor); + } + } + } - aRegion.EndEnumRects( aRegHandle ); + //RegionHandle aRegHandle( aRegion.BeginEnumRects() ); + // + //while( aRegion.GetEnumRects( aRegHandle, aRect ) ) + // for( long nY = aRect.Top(), nEndY = aRect.Bottom(); nY <= nEndY; nY++ ) + // for( long nX = aRect.Left(), nEndX = aRect.Right(); nX <= nEndX; nX++ ) + // SetPixel( nY, nX, rFillColor ); + // + //aRegion.EndEnumRects( aRegHandle ); } } } diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx index a5073daf2f2e..68870d8486a4 100644 --- a/vcl/source/gdi/gdimtf.cxx +++ b/vcl/source/gdi/gdimtf.cxx @@ -1384,8 +1384,8 @@ void GDIMetaFile::Rotate( long nAngle10 ) { MetaClipRegionAction* pAct = (MetaClipRegionAction*) pAction; - if( pAct->IsClipping() && pAct->GetRegion().HasPolyPolygon() ) - aMtf.AddAction( new MetaClipRegionAction( Region( ImplGetRotatedPolyPolygon( pAct->GetRegion().GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ), sal_True ) ); + if( pAct->IsClipping() && pAct->GetRegion().HasPolyPolygonOrB2DPolyPolygon() ) + aMtf.AddAction( new MetaClipRegionAction( Region( ImplGetRotatedPolyPolygon( pAct->GetRegion().GetAsPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ), sal_True ) ); else { pAction->Duplicate(); @@ -1406,8 +1406,8 @@ void GDIMetaFile::Rotate( long nAngle10 ) MetaISectRegionClipRegionAction* pAct = (MetaISectRegionClipRegionAction*) pAction; const Region& rRegion = pAct->GetRegion(); - if( rRegion.HasPolyPolygon() ) - aMtf.AddAction( new MetaISectRegionClipRegionAction( Region( ImplGetRotatedPolyPolygon( rRegion.GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ) ); + if( rRegion.HasPolyPolygonOrB2DPolyPolygon() ) + aMtf.AddAction( new MetaISectRegionClipRegionAction( Region( ImplGetRotatedPolyPolygon( rRegion.GetAsPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ) ); else { pAction->Duplicate(); @@ -2744,12 +2744,12 @@ sal_uLong GDIMetaFile::GetChecksum() const MetaClipRegionAction* pAct = dynamic_cast< MetaClipRegionAction* >(pAction); const Region& rRegion = pAct->GetRegion(); - if(rRegion.HasPolyPolygon()) + if(rRegion.HasPolyPolygonOrB2DPolyPolygon()) { // It has shown that this is a possible bottleneck for checksum calculation. // In worst case a very expensive RegionHandle representation gets created. // In this case it's cheaper to use the PolyPolygon - const basegfx::B2DPolyPolygon aPolyPolygon(rRegion.GetB2DPolyPolygon()); + const basegfx::B2DPolyPolygon aPolyPolygon(rRegion.GetAsB2DPolyPolygon()); const sal_uInt32 nPolyCount(aPolyPolygon.count()); SVBT64 aSVBT64; diff --git a/vcl/source/gdi/outdev.cxx b/vcl/source/gdi/outdev.cxx index ca9c0eb6393e..d1b03de76ba9 100644 --- a/vcl/source/gdi/outdev.cxx +++ b/vcl/source/gdi/outdev.cxx @@ -50,7 +50,6 @@ #include <svdata.hxx> #include <window.h> #include <outdev.h> -#include <region.h> #include <outdata.hxx> #include <basegfx/point/b2dpoint.hxx> @@ -329,7 +328,7 @@ void OutputDevice::ImplDrawPolyPolygon( sal_uInt16 nPoly, const PolyPolygon& rPo // ======================================================================= OutputDevice::OutputDevice() : - maRegion( REGION_NULL ), + maRegion(true), maFillColor( COL_WHITE ), maTextLineColor( COL_TRANSPARENT ), maSettings( Application::GetSettings() ) @@ -541,23 +540,35 @@ void OutputDevice::ImplReMirror( Rectangle &rRect ) const } void OutputDevice::ImplReMirror( Region &rRegion ) const { - long nX; - long nY; - long nWidth; - long nHeight; - ImplRegionInfo aInfo; - sal_Bool bRegionRect; - Region aMirroredRegion; + RectangleVector aRectangles; + rRegion.GetRegionRectangles(aRectangles); + Region aMirroredRegion; - bRegionRect = rRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); - while ( bRegionRect ) + for(RectangleVector::iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - Rectangle aRect( Point(nX, nY), Size(nWidth, nHeight) ); - ImplReMirror( aRect ); - aMirroredRegion.Union( aRect ); - bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + ImplReMirror(*aRectIter); + aMirroredRegion.Union(*aRectIter); } + rRegion = aMirroredRegion; + +// long nX; +// long nY; +// long nWidth; +// long nHeight; +// ImplRegionInfo aInfo; +// sal_Bool bRegionRect; +// Region aMirroredRegion; +// +// bRegionRect = rRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); +// while ( bRegionRect ) +// { +// Rectangle aRect( Point(nX, nY), Size(nWidth, nHeight) ); +// ImplReMirror( aRect ); +// aMirroredRegion.Union( aRect ); +// bRegionRect = rRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); +// } +// rRegion = aMirroredRegion; } @@ -1037,7 +1048,7 @@ void OutputDevice::ImplSetClipRegion( const Region* pRegion ) { if ( mbClipRegion ) { - maRegion = Region( REGION_NULL ); + maRegion = Region(true); mbClipRegion = sal_False; mbInitClipRegion = sal_True; } @@ -1072,13 +1083,14 @@ void OutputDevice::SetClipRegion( const Region& rRegion ) { DBG_TRACE( "OutputDevice::SetClipRegion( rRegion )" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); - DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); if ( mpMetaFile ) mpMetaFile->AddAction( new MetaClipRegionAction( rRegion, sal_True ) ); - if ( rRegion.GetType() == REGION_NULL ) + if ( rRegion.IsNull() ) + { ImplSetClipRegion( NULL ); + } else { Region aRegion = LogicToPixel( rRegion ); @@ -1106,7 +1118,7 @@ Region OutputDevice::GetActiveClipRegion() const if ( GetOutDevType() == OUTDEV_WINDOW ) { - Region aRegion( REGION_NULL ); + Region aRegion(true); Window* pWindow = (Window*)this; if ( pWindow->mpWindowImpl->mbInPaint ) { @@ -1167,11 +1179,8 @@ void OutputDevice::IntersectClipRegion( const Region& rRegion ) { DBG_TRACE( "OutputDevice::IntersectClipRegion( rRegion )" ); DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); - DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); - - RegionType eType = rRegion.GetType(); - if ( eType != REGION_NULL ) + if(!rRegion.IsNull()) { if ( mpMetaFile ) mpMetaFile->AddAction( new MetaISectRegionClipRegionAction( rRegion ) ); diff --git a/vcl/source/gdi/outdev2.cxx b/vcl/source/gdi/outdev2.cxx index 9a90ae414fe6..a57da0cde9ca 100644 --- a/vcl/source/gdi/outdev2.cxx +++ b/vcl/source/gdi/outdev2.cxx @@ -45,7 +45,6 @@ #include <image.h> #include <outdev.h> #include <window.h> -#include <region.h> #include <outdata.hxx> #define BAND_MAX_SIZE 512000 @@ -2136,7 +2135,7 @@ void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask // do painting const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight(); - long nX, nY, nWorkX, nWorkY, nWorkWidth, nWorkHeight; + long nX, nY; // , nWorkX, nWorkY, nWorkWidth, nWorkHeight; long* pMapX = new long[ nSrcWidth + 1 ]; long* pMapY = new long[ nSrcHeight + 1 ]; const sal_Bool bOldMap = mbMap; @@ -2151,22 +2150,38 @@ void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight ); // walk through all rectangles of mask - Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) ); - ImplRegionInfo aInfo; - sal_Bool bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); + const Region aWorkRgn(aMask.CreateRegion(COL_BLACK, Rectangle(Point(), aMask.GetSizePixel()))); + RectangleVector aRectangles; + aWorkRgn.GetRegionRectangles(aRectangles); - while( bRgnRect ) + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - Bitmap aBandBmp( aPaint ); - const Rectangle aBandRect( Point( nWorkX, nWorkY ), Size( nWorkWidth, nWorkHeight ) ); - const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] ); - const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() ); - - aBandBmp.Crop( aBandRect ); - ImplDrawBitmap( aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION ); - bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); + const Point aMapPt(pMapX[aRectIter->Left()], pMapY[aRectIter->Top()]); + const Size aMapSz( + pMapX[aRectIter->Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1 + pMapY[aRectIter->Bottom() + 1] - aMapPt.Y()); // same for Y + Bitmap aBandBmp(aPaint); + + aBandBmp.Crop(*aRectIter); + ImplDrawBitmap(aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION); } + //Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) ); + //ImplRegionInfo aInfo; + //sal_Bool bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); + // + //while( bRgnRect ) + //{ + // Bitmap aBandBmp( aPaint ); + // const Rectangle aBandRect( Point( nWorkX, nWorkY ), Size( nWorkWidth, nWorkHeight ) ); + // const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] ); + // const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() ); + // + // aBandBmp.Crop( aBandRect ); + // ImplDrawBitmap( aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION ); + // bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); + //} + mbMap = bOldMap; delete[] pMapX; @@ -2221,7 +2236,7 @@ void OutputDevice::ImplPrintMask( const Bitmap& rMask, const Color& rMaskColor, // do painting const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight(); - long nX, nY, nWorkX, nWorkY, nWorkWidth, nWorkHeight; + long nX, nY; //, nWorkX, nWorkY, nWorkWidth, nWorkHeight; long* pMapX = new long[ nSrcWidth + 1 ]; long* pMapY = new long[ nSrcHeight + 1 ]; GDIMetaFile* pOldMetaFile = mpMetaFile; @@ -2243,19 +2258,33 @@ void OutputDevice::ImplPrintMask( const Bitmap& rMask, const Color& rMaskColor, pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight ); // walk through all rectangles of mask - Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) ); - ImplRegionInfo aInfo; - sal_Bool bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); + const Region aWorkRgn(aMask.CreateRegion(COL_BLACK, Rectangle(Point(), aMask.GetSizePixel()))); + RectangleVector aRectangles; + aWorkRgn.GetRegionRectangles(aRectangles); - while( bRgnRect ) + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] ); - const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() ); + const Point aMapPt(pMapX[aRectIter->Left()], pMapY[aRectIter->Top()]); + const Size aMapSz( + pMapX[aRectIter->Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1 + pMapY[aRectIter->Bottom() + 1] - aMapPt.Y()); // same for Y - DrawRect( Rectangle( aMapPt, aMapSz ) ); - bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); + DrawRect(Rectangle(aMapPt, aMapSz)); } + //Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) ); + //ImplRegionInfo aInfo; + //sal_Bool bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); + // + //while( bRgnRect ) + //{ + // const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] ); + // const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() ); + // + // DrawRect( Rectangle( aMapPt, aMapSz ) ); + // bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight ); + //} + Pop(); delete[] pMapX; delete[] pMapY; diff --git a/vcl/source/gdi/outmap.cxx b/vcl/source/gdi/outmap.cxx index f42f791d5a69..f8b329549aad 100644 --- a/vcl/source/gdi/outmap.cxx +++ b/vcl/source/gdi/outmap.cxx @@ -40,7 +40,6 @@ #include <vcl/outdev.hxx> #include <svdata.hxx> -#include <region.h> #include <window.h> #include <outdev.h> #include <salgdi.hxx> @@ -798,8 +797,6 @@ Rectangle OutputDevice::ImplDevicePixelToLogic( const Rectangle& rPixelRect ) co Region OutputDevice::ImplPixelToDevicePixel( const Region& rRegion ) const { - DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); - if ( !mnOutOffX && !mnOutOffY ) return rRegion; @@ -1274,45 +1271,50 @@ basegfx::B2DPolyPolygon OutputDevice::LogicToPixel( const basegfx::B2DPolyPolygo Region OutputDevice::LogicToPixel( const Region& rLogicRegion ) const { DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); - DBG_CHKOBJ( &rLogicRegion, Region, ImplDbgTestRegion ); - - RegionType eType = rLogicRegion.GetType(); - if ( !mbMap || (eType == REGION_EMPTY) || (eType == REGION_NULL) ) + if(!mbMap || rLogicRegion.IsNull() || rLogicRegion.IsEmpty()) + { return rLogicRegion; + } - Region aRegion; - const ImplRegion& rImplRegion = *rLogicRegion.ImplGetImplRegion(); - const PolyPolygon* pPolyPoly = rImplRegion.mpPolyPoly; - const basegfx::B2DPolyPolygon* pB2DPolyPoly = rImplRegion.mpB2DPolyPoly; + Region aRegion; - if ( pPolyPoly ) - aRegion = Region( LogicToPixel( *pPolyPoly ) ); - else if( pB2DPolyPoly ) + if(rLogicRegion.getB2DPolyPolygon()) { - basegfx::B2DPolyPolygon aTransformedPoly = *pB2DPolyPoly; - const ::basegfx::B2DHomMatrix& rTransformationMatrix = GetViewTransformation(); - aTransformedPoly.transform( rTransformationMatrix ); - aRegion = Region( aTransformedPoly ); + aRegion = Region(LogicToPixel(*rLogicRegion.getB2DPolyPolygon())); } - else + else if(rLogicRegion.getPolyPolygon()) + { + aRegion = Region(LogicToPixel(*rLogicRegion.getPolyPolygon())); + } + else if(rLogicRegion.getRegionBand()) { - long nX; - long nY; - long nWidth; - long nHeight; - ImplRegionInfo aInfo; - sal_Bool bRegionRect; + RectangleVector aRectangles; + rLogicRegion.GetRegionRectangles(aRectangles); + const RectangleVector& rRectangles(aRectangles); // needed to make the '!=' work - aRegion.ImplBeginAddRect(); - bRegionRect = rLogicRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); - while ( bRegionRect ) + // make reverse run to fill new region bottom-up, this will speed it up due to the used data structuring + for(RectangleVector::const_reverse_iterator aRectIter(rRectangles.rbegin()); aRectIter != rRectangles.rend(); aRectIter++) { - Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); - aRegion.ImplAddRect( LogicToPixel( aRect ) ); - bRegionRect = rLogicRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + aRegion.Union(LogicToPixel(*aRectIter)); } - aRegion.ImplEndAddRect(); + + //long nX(0); + //long nY(0); + //long nWidth(0); + //long nHeight(0); + //ImplRegionInfo aInfo; + //aRegion.ImplBeginAddRect(); + //bool bRegionRect(rLogicRegion.ImplGetFirstRect(aInfo, nX, nY, nWidth, nHeight)); + // + //while(bRegionRect) + //{ + // const Rectangle aRect(Point(nX, nY), Size(nWidth, nHeight)); + // aRegion.ImplAddRect(LogicToPixel(aRect)); + // bRegionRect = rLogicRegion.ImplGetNextRect(aInfo, nX, nY, nWidth, nHeight); + //} + // + //aRegion.ImplEndAddRect(); } return aRegion; @@ -1477,40 +1479,53 @@ basegfx::B2DPolygon OutputDevice::LogicToPixel( const basegfx::B2DPolygon& rLogi // ----------------------------------------------------------------------- -Region OutputDevice::LogicToPixel( const Region& rLogicRegion, - const MapMode& rMapMode ) const +Region OutputDevice::LogicToPixel( const Region& rLogicRegion, const MapMode& rMapMode ) const { DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); - DBG_CHKOBJ( &rLogicRegion, Region, ImplDbgTestRegion ); - RegionType eType = rLogicRegion.GetType(); - - if ( rMapMode.IsDefault() || (eType == REGION_EMPTY) || (eType == REGION_NULL) ) + if(rMapMode.IsDefault() || rLogicRegion.IsNull() || rLogicRegion.IsEmpty()) + { return rLogicRegion; + } - Region aRegion; - PolyPolygon* pPolyPoly = rLogicRegion.ImplGetImplRegion()->mpPolyPoly; + Region aRegion; - if( pPolyPoly ) - aRegion = Region( LogicToPixel( *pPolyPoly, rMapMode ) ); - else + if(rLogicRegion.getB2DPolyPolygon()) + { + aRegion = Region(LogicToPixel(*rLogicRegion.getB2DPolyPolygon(), rMapMode)); + } + else if(rLogicRegion.getPolyPolygon()) + { + aRegion = Region(LogicToPixel(*rLogicRegion.getPolyPolygon(), rMapMode)); + } + else if(rLogicRegion.getRegionBand()) { - long nX; - long nY; - long nWidth; - long nHeight; - ImplRegionInfo aInfo; - sal_Bool bRegionRect; + RectangleVector aRectangles; + rLogicRegion.GetRegionRectangles(aRectangles); + const RectangleVector& rRectangles(aRectangles); // needed to make the '!=' work - aRegion.ImplBeginAddRect(); - bRegionRect = rLogicRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); - while ( bRegionRect ) + // make reverse run to fill new region bottom-up, this will speed it up due to the used data structuring + for(RectangleVector::const_reverse_iterator aRectIter(rRectangles.rbegin()); aRectIter != rRectangles.rend(); aRectIter++) { - Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); - aRegion.ImplAddRect( LogicToPixel( aRect, rMapMode ) ); - bRegionRect = rLogicRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + aRegion.Union(LogicToPixel(*aRectIter, rMapMode)); } - aRegion.ImplEndAddRect(); + + //long nX(0); + //long nY(0); + //long nWidth(0); + //long nHeight(0); + //ImplRegionInfo aInfo; + //aRegion.ImplBeginAddRect(); + //bool bRegionRect(rLogicRegion.ImplGetFirstRect(aInfo, nX, nY, nWidth, nHeight)); + // + //while(bRegionRect) + //{ + // const Rectangle aRect(Point(nX, nY), Size(nWidth, nHeight)); + // aRegion.ImplAddRect(LogicToPixel(aRect, rMapMode)); + // bRegionRect = rLogicRegion.ImplGetNextRect(aInfo, nX, nY, nWidth, nHeight); + //} + // + //aRegion.ImplEndAddRect(); } return aRegion; @@ -1651,43 +1666,50 @@ basegfx::B2DPolyPolygon OutputDevice::PixelToLogic( const basegfx::B2DPolyPolygo Region OutputDevice::PixelToLogic( const Region& rDeviceRegion ) const { DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); - DBG_CHKOBJ( &rDeviceRegion, Region, ImplDbgTestRegion ); - - RegionType eType = rDeviceRegion.GetType(); - if ( !mbMap || (eType == REGION_EMPTY) || (eType == REGION_NULL) ) + if(!mbMap || rDeviceRegion.IsNull() || rDeviceRegion.IsEmpty()) + { return rDeviceRegion; + } - Region aRegion; - basegfx::B2DPolyPolygon* pB2DPolyPoly = rDeviceRegion.ImplGetImplRegion()->mpB2DPolyPoly; - PolyPolygon* pPolyPoly = pB2DPolyPoly ? 0 : rDeviceRegion.ImplGetImplRegion()->mpPolyPoly; + Region aRegion; - if ( pB2DPolyPoly ) // conversion with B2DPolyPolygon lost polygon-based ClipRegion + if(rDeviceRegion.getB2DPolyPolygon()) { - aRegion = Region( PixelToLogic( *pB2DPolyPoly ) ); + aRegion = Region(PixelToLogic(*rDeviceRegion.getB2DPolyPolygon())); } - else if ( pPolyPoly ) + else if(rDeviceRegion.getPolyPolygon()) { - aRegion = Region( PixelToLogic( *pPolyPoly ) ); + aRegion = Region(PixelToLogic(*rDeviceRegion.getPolyPolygon())); } - else + else if(rDeviceRegion.getRegionBand()) { - long nX; - long nY; - long nWidth; - long nHeight; - ImplRegionInfo aInfo; - sal_Bool bRegionRect; + RectangleVector aRectangles; + rDeviceRegion.GetRegionRectangles(aRectangles); + const RectangleVector& rRectangles(aRectangles); // needed to make the '!=' work - aRegion.ImplBeginAddRect(); - bRegionRect = rDeviceRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); - while ( bRegionRect ) + // make reverse run to fill new region bottom-up, this will speed it up due to the used data structuring + for(RectangleVector::const_reverse_iterator aRectIter(rRectangles.rbegin()); aRectIter != rRectangles.rend(); aRectIter++) { - Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); - aRegion.ImplAddRect( PixelToLogic( aRect ) ); - bRegionRect = rDeviceRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + aRegion.Union(PixelToLogic(*aRectIter)); } - aRegion.ImplEndAddRect(); + + //long nX(0); + //long nY(0); + //long nWidth(0); + //long nHeight(0); + //ImplRegionInfo aInfo; + //aRegion.ImplBeginAddRect(); + //bool bRegionRect(rDeviceRegion.ImplGetFirstRect(aInfo, nX, nY, nWidth, nHeight)); + // + //while(bRegionRect) + //{ + // const Rectangle aRect(Point(nX, nY), Size(nWidth, nHeight)); + // aRegion.ImplAddRect(PixelToLogic(aRect)); + // bRegionRect = rDeviceRegion.ImplGetNextRect(aInfo, nX, nY, nWidth, nHeight); + //} + // + //aRegion.ImplEndAddRect(); } return aRegion; @@ -1856,40 +1878,53 @@ basegfx::B2DPolyPolygon OutputDevice::PixelToLogic( const basegfx::B2DPolyPolygo // ----------------------------------------------------------------------- -Region OutputDevice::PixelToLogic( const Region& rDeviceRegion, - const MapMode& rMapMode ) const +Region OutputDevice::PixelToLogic( const Region& rDeviceRegion, const MapMode& rMapMode ) const { DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice ); - DBG_CHKOBJ( &rDeviceRegion, Region, ImplDbgTestRegion ); - RegionType eType = rDeviceRegion.GetType(); - - if ( rMapMode.IsDefault() || (eType == REGION_EMPTY) || (eType == REGION_NULL) ) + if(rMapMode.IsDefault() || rDeviceRegion.IsNull() || rDeviceRegion.IsEmpty()) + { return rDeviceRegion; + } - Region aRegion; - PolyPolygon* pPolyPoly = rDeviceRegion.ImplGetImplRegion()->mpPolyPoly; + Region aRegion; - if ( pPolyPoly ) - aRegion = Region( PixelToLogic( *pPolyPoly, rMapMode ) ); - else + if(rDeviceRegion.getB2DPolyPolygon()) + { + aRegion = Region(PixelToLogic(*rDeviceRegion.getB2DPolyPolygon(), rMapMode)); + } + else if(rDeviceRegion.getPolyPolygon()) { - long nX; - long nY; - long nWidth; - long nHeight; - ImplRegionInfo aInfo; - sal_Bool bRegionRect; + aRegion = Region(PixelToLogic(*rDeviceRegion.getPolyPolygon(), rMapMode)); + } + else if(rDeviceRegion.getRegionBand()) + { + RectangleVector aRectangles; + rDeviceRegion.GetRegionRectangles(aRectangles); + const RectangleVector& rRectangles(aRectangles); // needed to make the '!=' work - aRegion.ImplBeginAddRect(); - bRegionRect = rDeviceRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); - while ( bRegionRect ) + // make reverse run to fill new region bottom-up, this will speed it up due to the used data structuring + for(RectangleVector::const_reverse_iterator aRectIter(rRectangles.rbegin()); aRectIter != rRectangles.rend(); aRectIter++) { - Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); - aRegion.ImplAddRect( PixelToLogic( aRect, rMapMode ) ); - bRegionRect = rDeviceRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + aRegion.Union(PixelToLogic(*aRectIter, rMapMode)); } - aRegion.ImplEndAddRect(); + + //long nX(0); + //long nY(0); + //long nWidth(0); + //long nHeight(0); + //ImplRegionInfo aInfo; + //aRegion.ImplBeginAddRect(); + //bool bRegionRect(rDeviceRegion.ImplGetFirstRect(aInfo, nX, nY, nWidth, nHeight)); + // + //while(bRegionRect) + //{ + // const Rectangle aRect(Point(nX, nY), Size(nWidth, nHeight)); + // aRegion.ImplAddRect(PixelToLogic(aRect, rMapMode)); + // bRegionRect = rDeviceRegion.ImplGetNextRect(aInfo, nX, nY, nWidth, nHeight); + //} + // + //aRegion.ImplEndAddRect(); } return aRegion; diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx index f7919a397fb8..28031aab7535 100644 --- a/vcl/source/gdi/pdfwriter_impl2.cxx +++ b/vcl/source/gdi/pdfwriter_impl2.cxx @@ -886,7 +886,7 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa else { Region aReg( pA->GetRegion() ); - m_rOuterFace.SetClipRegion( aReg.ConvertToB2DPolyPolygon() ); + m_rOuterFace.SetClipRegion( aReg.GetAsB2DPolyPolygon() ); } } else @@ -905,7 +905,7 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa { const MetaISectRegionClipRegionAction* pA = (const MetaISectRegionClipRegionAction*) pAction; Region aReg( pA->GetRegion() ); - m_rOuterFace.IntersectClipRegion( aReg.ConvertToB2DPolyPolygon() ); + m_rOuterFace.IntersectClipRegion( aReg.GetAsB2DPolyPolygon() ); } break; diff --git a/vcl/source/gdi/regband.cxx b/vcl/source/gdi/regband.cxx index 26ee49d42fd2..2dec6ecac2be 100644 --- a/vcl/source/gdi/regband.cxx +++ b/vcl/source/gdi/regband.cxx @@ -59,7 +59,7 @@ ImplRegionBand::ImplRegionBand( long nTop, long nBottom ) mpPrevBand = NULL; mpFirstSep = NULL; mpFirstBandPoint = NULL; - mbTouched = sal_False; + mbTouched = false; } // ----------------------------------------------------------------------- @@ -208,8 +208,8 @@ void ImplRegionBand::ProcessPoints() // generate separations from lines and process union with existing // separations -sal_Bool ImplRegionBand::InsertPoint( long nX, long nLineId, - sal_Bool bEndPoint, LineType eLineType ) +bool ImplRegionBand::InsertPoint( long nX, long nLineId, + bool bEndPoint, LineType eLineType ) { if ( !mpFirstBandPoint ) { @@ -219,7 +219,7 @@ sal_Bool ImplRegionBand::InsertPoint( long nX, long nLineId, mpFirstBandPoint->mbEndPoint = bEndPoint; mpFirstBandPoint->meLineType = eLineType; mpFirstBandPoint->mpNextBandPoint = NULL; - return sal_True; + return true; } // look if line allready touched the band @@ -238,8 +238,8 @@ sal_Bool ImplRegionBand::InsertPoint( long nX, long nLineId, { // if we've only got one point => replace first point pRegionBandPoint->mnX = nX; - pRegionBandPoint->mbEndPoint = sal_True; - return sal_True; + pRegionBandPoint->mbEndPoint = true; + return true; } else { @@ -263,7 +263,7 @@ sal_Bool ImplRegionBand::InsertPoint( long nX, long nLineId, } } else - return sal_False; + return false; } // use next element @@ -294,7 +294,7 @@ sal_Bool ImplRegionBand::InsertPoint( long nX, long nLineId, else pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint; - return sal_True; + return true; } // use next element @@ -313,7 +313,7 @@ sal_Bool ImplRegionBand::InsertPoint( long nX, long nLineId, // connections to the new point pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint; - return sal_True; + return true; } // ----------------------------------------------------------------------- @@ -347,7 +347,7 @@ void ImplRegionBand::ScaleX( double fHorzScale ) // // combine overlaping sparations -sal_Bool ImplRegionBand::OptimizeBand() +bool ImplRegionBand::OptimizeBand() { ImplRegionBandSep* pPrevSep = 0; ImplRegionBandSep* pSep = mpFirstSep; @@ -385,7 +385,7 @@ sal_Bool ImplRegionBand::OptimizeBand() pSep = pSep->mpNextSep; } - return sal_True; + return true; } // ----------------------------------------------------------------------- @@ -400,7 +400,7 @@ void ImplRegionBand::Union( long nXLeft, long nXRight ) mpFirstSep = new ImplRegionBandSep; mpFirstSep->mnXLeft = nXLeft; mpFirstSep->mnXRight = nXRight; - mpFirstSep->mbRemoved = sal_False; + mpFirstSep->mbRemoved = false; mpFirstSep->mpNextSep = NULL; return; } @@ -421,7 +421,7 @@ void ImplRegionBand::Union( long nXLeft, long nXRight ) pNewSep = new ImplRegionBandSep; pNewSep->mnXLeft = nXLeft; pNewSep->mnXRight = nXRight; - pNewSep->mbRemoved = sal_False; + pNewSep->mbRemoved = false; pNewSep->mpNextSep = pSep; if ( pSep == mpFirstSep ) @@ -448,7 +448,7 @@ void ImplRegionBand::Union( long nXLeft, long nXRight ) pNewSep = new ImplRegionBandSep; pNewSep->mnXLeft = nXLeft; pNewSep->mnXRight = nXRight; - pNewSep->mbRemoved = sal_False; + pNewSep->mbRemoved = false; pSep->mpNextSep = pNewSep; pNewSep->mpNextSep = NULL; @@ -469,7 +469,7 @@ void ImplRegionBand::Intersect( long nXLeft, long nXRight ) DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Intersect(): nxLeft > nXRight" ); // band has been touched - mbTouched = sal_True; + mbTouched = true; // band empty? -> nothing to do if ( !mpFirstSep ) @@ -482,7 +482,7 @@ void ImplRegionBand::Intersect( long nXLeft, long nXRight ) // new separation completly outside? -> remove separation if ( (nXRight < pSep->mnXLeft) || (nXLeft > pSep->mnXRight) ) // will be removed from the optimizer - pSep->mbRemoved = sal_True; + pSep->mbRemoved = true; // new separation overlaping from left? -> reduce right boundary if ( (nXLeft <= pSep->mnXLeft) && @@ -516,7 +516,7 @@ void ImplRegionBand::Exclude( long nXLeft, long nXRight ) DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Exclude(): nxLeft > nXRight" ); // band has been touched - mbTouched = sal_True; + mbTouched = true; // band empty? -> nothing to do if ( !mpFirstSep ) @@ -528,14 +528,14 @@ void ImplRegionBand::Exclude( long nXLeft, long nXRight ) ImplRegionBandSep* pSep = mpFirstSep; while ( pSep ) { - sal_Bool bSepProcessed = sal_False; + bool bSepProcessed = false; // new separation completely overlapping? -> remove separation if ( (nXLeft <= pSep->mnXLeft) && (nXRight >= pSep->mnXRight) ) { // will be removed from the optimizer - pSep->mbRemoved = sal_True; - bSepProcessed = sal_True; + pSep->mbRemoved = true; + bSepProcessed = true; } // new separation overlaping from left? -> reduce boundary @@ -544,7 +544,7 @@ void ImplRegionBand::Exclude( long nXLeft, long nXRight ) if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) ) { pSep->mnXLeft = nXRight+1; - bSepProcessed = sal_True; + bSepProcessed = true; } } @@ -554,7 +554,7 @@ void ImplRegionBand::Exclude( long nXLeft, long nXRight ) if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) ) { pSep->mnXRight = nXLeft-1; - bSepProcessed = sal_True; + bSepProcessed = true; } } @@ -567,7 +567,7 @@ void ImplRegionBand::Exclude( long nXLeft, long nXRight ) pNewSep = new ImplRegionBandSep; pNewSep->mnXLeft = pSep->mnXLeft; pNewSep->mnXRight = nXLeft-1; - pNewSep->mbRemoved = sal_False; + pNewSep->mbRemoved = false; pSep->mnXLeft = nXRight+1; @@ -647,7 +647,7 @@ void ImplRegionBand::XOr( long nXLeft, long nXRight ) mpFirstSep = new ImplRegionBandSep; mpFirstSep->mnXLeft = nXLeft; mpFirstSep->mnXRight = nXRight; - mpFirstSep->mbRemoved = sal_False; + mpFirstSep->mbRemoved = false; mpFirstSep->mpNextSep = NULL; return; } @@ -676,7 +676,7 @@ void ImplRegionBand::XOr( long nXLeft, long nXRight ) pNewSep->mnXLeft = nXLeft; pNewSep->mnXRight = nXRight; pNewSep->mpNextSep = pSep; - pNewSep->mbRemoved = sal_False; + pNewSep->mbRemoved = false; // connections from the new separation pNewSep->mpNextSep = pSep; @@ -692,7 +692,7 @@ void ImplRegionBand::XOr( long nXLeft, long nXRight ) else if( nXLeft == nOldLeft && nXRight == nOldRight ) { // #3 - pSep->mbRemoved = sal_True; + pSep->mbRemoved = true; pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop break; } @@ -725,7 +725,7 @@ void ImplRegionBand::XOr( long nXLeft, long nXRight ) // cannot break here, simply mark segment as removed, // and go on with adapted nXLeft/nXRight - pSep->mbRemoved = sal_True; + pSep->mbRemoved = true; } else { @@ -805,7 +805,7 @@ void ImplRegionBand::XOr( long nXLeft, long nXRight ) pNewSep->mnXLeft = nXLeft; pNewSep->mnXRight = nXRight; pNewSep->mpNextSep = pSep->mpNextSep; - pNewSep->mbRemoved = sal_False; + pNewSep->mbRemoved = false; // connections from the new separation pSep->mpNextSep = pNewSep; @@ -827,7 +827,7 @@ void ImplRegionBand::XOr( long nXLeft, long nXRight ) pNewSep->mnXLeft = nXLeft; pNewSep->mnXRight = nXRight; pNewSep->mpNextSep = NULL; - pNewSep->mbRemoved = sal_False; + pNewSep->mbRemoved = false; // connections from the new separation pPrevSep->mpNextSep = pNewSep; @@ -838,50 +838,50 @@ void ImplRegionBand::XOr( long nXLeft, long nXRight ) // ----------------------------------------------------------------------- -sal_Bool ImplRegionBand::IsInside( long nX ) +bool ImplRegionBand::IsInside( long nX ) { ImplRegionBandSep* pSep = mpFirstSep; while ( pSep ) { if ( (pSep->mnXLeft <= nX) && (pSep->mnXRight >= nX) ) - return sal_True; + return true; pSep = pSep->mpNextSep; } - return sal_False; + return false; } // ----------------------------------------------------------------------- -sal_Bool ImplRegionBand::IsOver( long nLeft, long nRight ) +bool ImplRegionBand::IsOver( long nLeft, long nRight ) { ImplRegionBandSep* pSep = mpFirstSep; while ( pSep ) { if ( (pSep->mnXLeft < nRight) && (pSep->mnXRight > nLeft) ) - return sal_True; + return true; pSep = pSep->mpNextSep; } - return sal_False; + return false; } // ----------------------------------------------------------------------- -sal_Bool ImplRegionBand::IsInside( long nLeft, long nRight ) +bool ImplRegionBand::IsInside( long nLeft, long nRight ) { ImplRegionBandSep* pSep = mpFirstSep; while ( pSep ) { if ( (pSep->mnXLeft >= nLeft) && (nRight <= pSep->mnXRight) ) - return sal_True; + return true; pSep = pSep->mpNextSep; } - return sal_False; + return false; } // ----------------------------------------------------------------------- @@ -908,7 +908,7 @@ long ImplRegionBand::GetXRightBoundary() const // ----------------------------------------------------------------------- -sal_Bool ImplRegionBand::operator==( const ImplRegionBand& rRegionBand ) const +bool ImplRegionBand::operator==( const ImplRegionBand& rRegionBand ) const { ImplRegionBandSep* pOwnRectBandSep = mpFirstSep; ImplRegionBandSep* pSecondRectBandSep = rRegionBand.mpFirstSep; @@ -918,12 +918,12 @@ sal_Bool ImplRegionBand::operator==( const ImplRegionBand& rRegionBand ) const long nOwnXLeft = pOwnRectBandSep->mnXLeft; long nSecondXLeft = pSecondRectBandSep->mnXLeft; if ( nOwnXLeft != nSecondXLeft ) - return sal_False; + return false; long nOwnXRight = pOwnRectBandSep->mnXRight; long nSecondXRight = pSecondRectBandSep->mnXRight; if ( nOwnXRight != nSecondXRight ) - return sal_False; + return false; // get next separation from current band pOwnRectBandSep = pOwnRectBandSep->mpNextSep; @@ -934,9 +934,9 @@ sal_Bool ImplRegionBand::operator==( const ImplRegionBand& rRegionBand ) const // differnt number of separations? if ( pOwnRectBandSep || pSecondRectBandSep ) - return sal_False; + return false; - return sal_True; + return true; } // ----------------------------------------------------------------------- diff --git a/vcl/source/gdi/region.cxx b/vcl/source/gdi/region.cxx index 1e82b2f7090b..054ee5ed80b6 100644 --- a/vcl/source/gdi/region.cxx +++ b/vcl/source/gdi/region.cxx @@ -19,23 +19,14 @@ * *************************************************************/ - - // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #include <limits.h> - #include <tools/vcompat.hxx> #include <tools/stream.hxx> -#include <tools/debug.hxx> - #include <vcl/region.hxx> -#include <vcl/regband.hxx> -#include <vcl/salbtype.hxx> - -#include <region.h> - +#include <regionband.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> @@ -44,2078 +35,1237 @@ #include <basegfx/range/b2drange.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> -// ======================================================================= -// -// ImplRegionBand -// -// Die Klassen RegionBand/ImplRegionBand speichert Regionen in Form von -// Rechtecken ab. Die Region ist in Y-Richtung in Baendern unterteilt, die -// wiederum ein oder mehrere Rechtecke mit der Hoehe des Bandes enthalten. -// -// Leere Baender werden entfernt. -// -// Polygone und PolyPolygone werden ebenfalls in Rechtecke zerlegt und in -// der Baendern abgelegt. Hierzu werden alle Punkte der einzelnen Polygone -// mit dem Bresenham-Algorithmus berechnet und in die Baender eingetragen. -// Nach der vollstaendigen Berechung aller Kanten werden die entsprechenden -// Rechntecke berechnet - -// ======================================================================= - -static ImplRegionBase aImplNullRegion( 0 ); -static ImplRegionBase aImplEmptyRegion( 0 ); - -// ======================================================================= +////////////////////////////////////////////////////////////////////////////// DBG_NAME( Region ) DBG_NAMEEX( Polygon ) DBG_NAMEEX( PolyPolygon ) -namespace { +////////////////////////////////////////////////////////////////////////////// -/** Return <TRUE/> when the given polygon is rectiliner and oriented so that - all sides are either horizontal or vertical. -*/ -bool ImplIsPolygonRectilinear (const PolyPolygon& rPolyPoly) +namespace { - // Iterate over all polygons. - const sal_uInt16 nPolyCount = rPolyPoly.Count(); - for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly) + /** Return <TRUE/> when the given polygon is rectiliner and oriented so that + all sides are either horizontal or vertical. + */ + bool ImplIsPolygonRectilinear (const PolyPolygon& rPolyPoly) { - const Polygon& aPoly = rPolyPoly.GetObject(nPoly); - - // Iterate over all edges of the current polygon. - const sal_uInt16 nSize = aPoly.GetSize(); - - if (nSize < 2) - continue; - Point aPoint (aPoly.GetPoint(0)); - const Point aLastPoint (aPoint); - for (sal_uInt16 nPoint = 1; nPoint < nSize; ++nPoint) + // Iterate over all polygons. + const sal_uInt16 nPolyCount = rPolyPoly.Count(); + for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly) { - const Point aNextPoint (aPoly.GetPoint(nPoint)); - // When there is at least one edge that is neither vertical nor - // horizontal then the entire polygon is not rectilinear (and - // oriented along primary axes.) - if (aPoint.X() != aNextPoint.X() && aPoint.Y() != aNextPoint.Y()) - return false; + const Polygon& aPoly = rPolyPoly.GetObject(nPoly); - aPoint = aNextPoint; - } - // Compare closing edge. - if (aLastPoint.X() != aPoint.X() && aLastPoint.Y() != aPoint.Y()) - return false; - } - return true; -} + // Iterate over all edges of the current polygon. + const sal_uInt16 nSize = aPoly.GetSize(); - - -/** This function is similar to the ImplRegion::InsertBands() method. - It creates a minimal set of missing bands so that the entire vertical - interval from nTop to nBottom is covered by bands. -*/ -void ImplAddMissingBands ( - ImplRegion* pImplRegion, - const long nTop, - const long nBottom) -{ - // Iterate over already existing bands and add missing bands atop the - // first and between two bands. - ImplRegionBand* pPreviousBand = NULL; - ImplRegionBand* pBand = pImplRegion->ImplGetFirstRegionBand(); - long nCurrentTop (nTop); - while (pBand != NULL && nCurrentTop<nBottom) - { - if (nCurrentTop < pBand->mnYTop) - { - // Create new band above the current band. - ImplRegionBand* pAboveBand = new ImplRegionBand( - nCurrentTop, - ::std::min(nBottom,pBand->mnYTop-1)); - pImplRegion->InsertBand(pPreviousBand, pAboveBand); - } - - // Adapt the top of the interval to prevent overlapping bands. - nCurrentTop = ::std::max(nTop, pBand->mnYBottom+1); - - // Advance to next band. - pPreviousBand = pBand; - pBand = pBand->mpNextBand; - } - - // We still have to cover two cases: - // 1. The region does not yet contain any bands. - // 2. The intervall nTop->nBottom extends past the bottom most band. - if (nCurrentTop <= nBottom - && (pBand==NULL || nBottom>pBand->mnYBottom)) - { - // When there is no previous band then the new one will be the - // first. Otherwise the new band is inserted behind the last band. - pImplRegion->InsertBand( - pPreviousBand, - new ImplRegionBand( - nCurrentTop, - nBottom)); - } -} - - - -/** Convert a rectilinear polygon (that is oriented along the primary axes) - to a list of bands. For this special form of polygon we can use an - optimization that prevents the creation of one band per y value. - However, it still is possible that some temporary bands are created that - later can be optimized away. - @param rPolyPolygon - A set of zero, one, or more polygons, nested or not, that are - converted into a list of bands. - @return - A new ImplRegion object is returned that contains the bands that - represent the given poly-polygon. -*/ -ImplRegion* ImplRectilinearPolygonToBands (const PolyPolygon& rPolyPoly) -{ - OSL_ASSERT(ImplIsPolygonRectilinear (rPolyPoly)); - - // Create a new ImplRegion object as container of the bands. - ImplRegion* pImplRegion = new ImplRegion(); - long nLineId = 0L; - - // Iterate over all polygons. - const sal_uInt16 nPolyCount = rPolyPoly.Count(); - for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly) - { - const Polygon& aPoly = rPolyPoly.GetObject(nPoly); - - // Iterate over all edges of the current polygon. - const sal_uInt16 nSize = aPoly.GetSize(); - if (nSize < 2) - continue; - // Avoid fetching every point twice (each point is the start point - // of one and the end point of another edge.) - Point aStart (aPoly.GetPoint(0)); - Point aEnd; - for (sal_uInt16 nPoint = 1; nPoint <= nSize; ++nPoint, aStart=aEnd) - { - // We take the implicit closing edge into account by mapping - // index nSize to 0. - aEnd = aPoly.GetPoint(nPoint%nSize); - if (aStart.Y() == aEnd.Y()) - { - // Horizontal lines are ignored. + if (nSize < 2) continue; - } - - // At this point the line has to be vertical. - OSL_ASSERT(aStart.X() == aEnd.X()); - - // Sort y-coordinates to simplify the algorithm and store the - // direction seperately. The direction is calculated as it is - // in other places (but seems to be the wrong way.) - const long nTop (::std::min(aStart.Y(), aEnd.Y())); - const long nBottom (::std::max(aStart.Y(), aEnd.Y())); - const LineType eLineType (aStart.Y() > aEnd.Y() ? LINE_DESCENDING : LINE_ASCENDING); - - // Make sure that the current line is covered by bands. - ImplAddMissingBands(pImplRegion, nTop,nBottom); - - // Find top-most band that may contain nTop. - ImplRegionBand* pBand = pImplRegion->ImplGetFirstRegionBand(); - while (pBand!=NULL && pBand->mnYBottom < nTop) - pBand = pBand->mpNextBand; - ImplRegionBand* pTopBand = pBand; - // If necessary split the band at nTop so that nTop is contained - // in the lower band. - if (pBand!=NULL - // Prevent the current band from becoming 0 pixel high - && pBand->mnYTop<nTop - // this allows the lowest pixel of the band to be split off - && pBand->mnYBottom>=nTop - // do not split a band that is just one pixel high - && pBand->mnYTop<pBand->mnYBottom) - { - // Split the top band. - pTopBand = pBand->SplitBand(nTop); - } - - // Advance to band that may contain nBottom. - while (pBand!=NULL && pBand->mnYBottom < nBottom) - pBand = pBand->mpNextBand; - // The lowest band may have to be split at nBottom so that - // nBottom itself remains in the upper band. - if (pBand!=NULL - // allow the current band becoming 1 pixel high - && pBand->mnYTop<=nBottom - // prevent splitting off a band that is 0 pixel high - && pBand->mnYBottom>nBottom - // do not split a band that is just one pixel high - && pBand->mnYTop<pBand->mnYBottom) + Point aPoint (aPoly.GetPoint(0)); + const Point aLastPoint (aPoint); + for (sal_uInt16 nPoint = 1; nPoint < nSize; ++nPoint) { - // Split the bottom band. - pBand->SplitBand(nBottom+1); + const Point aNextPoint (aPoly.GetPoint(nPoint)); + // When there is at least one edge that is neither vertical nor + // horizontal then the entire polygon is not rectilinear (and + // oriented along primary axes.) + if (aPoint.X() != aNextPoint.X() && aPoint.Y() != aNextPoint.Y()) + return false; + + aPoint = aNextPoint; } - - // Note that we remember the top band (in pTopBand) but not the - // bottom band. The later can be determined by comparing y - // coordinates. - - // Add the x-value as point to all bands in the nTop->nBottom range. - for (pBand=pTopBand; pBand!=NULL&&pBand->mnYTop<=nBottom; pBand=pBand->mpNextBand) - pBand->InsertPoint(aStart.X(), nLineId++, sal_True, eLineType); + // Compare closing edge. + if (aLastPoint.X() != aPoint.X() && aLastPoint.Y() != aPoint.Y()) + return false; } + return true; } - return pImplRegion; -} - - - - -/** Convert a general polygon (one for which ImplIsPolygonRectilinear() - returns <FALSE/>) to bands. -*/ -ImplRegion* ImplGeneralPolygonToBands ( - const PolyPolygon& rPolyPoly, - const Rectangle& rPolygonBoundingBox) -{ - long nLineID = 0L; - - // initialisation and creation of Bands - ImplRegion* pImplRegion = new ImplRegion(); - pImplRegion->CreateBandRange( rPolygonBoundingBox.Top(), rPolygonBoundingBox.Bottom() ); - - // insert polygons - const sal_uInt16 nPolyCount = rPolyPoly.Count(); - for ( sal_uInt16 nPoly = 0; nPoly < nPolyCount; nPoly++ ) - { - // get reference to current polygon - const Polygon& aPoly = rPolyPoly.GetObject( nPoly ); - const sal_uInt16 nSize = aPoly.GetSize(); - - // not enough points ( <= 2 )? -> nothing to do! - if ( nSize <= 2 ) - continue; - - // band the polygon - for ( sal_uInt16 nPoint = 1; nPoint < nSize; nPoint++ ) - pImplRegion->InsertLine( aPoly.GetPoint(nPoint-1), aPoly.GetPoint(nPoint), nLineID++ ); - - // close polygon with line from first point to last point, if neccesary - const Point rLastPoint = aPoly.GetPoint(nSize-1); - const Point rFirstPoint = aPoly.GetPoint(0); - if ( rLastPoint != rFirstPoint ) - pImplRegion->InsertLine( rLastPoint, rFirstPoint, nLineID++ ); - } - - return pImplRegion; -} - - -} // end of anonymous namespace - - -// ----------------------------------------------------------------------- - -#ifdef DBG_UTIL -const char* ImplDbgTestRegion( const void* pObj ) -{ - Region* pRegion = (Region*)pObj; - ImplRegion* pImplRegion = pRegion->ImplGetImplRegion(); - - if ( aImplNullRegion.mnRefCount ) - return "Null-Region-RefCount modified"; - if ( aImplNullRegion.mnRectCount ) - return "Null-Region-RectCount modified"; - if ( aImplNullRegion.mpPolyPoly ) - return "Null-Region-PolyPoly modified"; - if ( aImplEmptyRegion.mnRefCount ) - return "Emptry-Region-RefCount modified"; - if ( aImplEmptyRegion.mnRectCount ) - return "Emptry-Region-RectCount modified"; - if ( aImplEmptyRegion.mpPolyPoly ) - return "Emptry-Region-PolyPoly modified"; - - if ( (pImplRegion != &aImplEmptyRegion) && (pImplRegion != &aImplNullRegion) ) - { - sal_uLong nCount = 0; - const ImplRegionBand* pBand = pImplRegion->ImplGetFirstRegionBand(); - while ( pBand ) + /** Convert a rectilinear polygon (that is oriented along the primary axes) + to a list of bands. For this special form of polygon we can use an + optimization that prevents the creation of one band per y value. + However, it still is possible that some temporary bands are created that + later can be optimized away. + @param rPolyPolygon + A set of zero, one, or more polygons, nested or not, that are + converted into a list of bands. + @return + A new RegionBand object is returned that contains the bands that + represent the given poly-polygon. + */ + RegionBand* ImplRectilinearPolygonToBands(const PolyPolygon& rPolyPoly) + { + OSL_ASSERT(ImplIsPolygonRectilinear (rPolyPoly)); + + // Create a new RegionBand object as container of the bands. + RegionBand* pRegionBand = new RegionBand(); + long nLineId = 0L; + + // Iterate over all polygons. + const sal_uInt16 nPolyCount = rPolyPoly.Count(); + for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly) { - if ( pBand->mnYBottom < pBand->mnYTop ) - return "YBottom < YTop"; - if ( pBand->mpNextBand ) - { - if ( pBand->mnYBottom >= pBand->mpNextBand->mnYTop ) - return "overlapping bands in region"; - } - if ( pBand->mbTouched > 1 ) - return "Band-mbTouched overwrite"; + const Polygon& aPoly = rPolyPoly.GetObject(nPoly); - ImplRegionBandSep* pSep = pBand->mpFirstSep; - while ( pSep ) + // Iterate over all edges of the current polygon. + const sal_uInt16 nSize = aPoly.GetSize(); + if (nSize < 2) + continue; + // Avoid fetching every point twice (each point is the start point + // of one and the end point of another edge.) + Point aStart (aPoly.GetPoint(0)); + Point aEnd; + for (sal_uInt16 nPoint = 1; nPoint <= nSize; ++nPoint, aStart=aEnd) { - if ( pSep->mnXRight < pSep->mnXLeft ) - return "XLeft < XRight"; - if ( pSep->mpNextSep ) + // We take the implicit closing edge into account by mapping + // index nSize to 0. + aEnd = aPoly.GetPoint(nPoint%nSize); + if (aStart.Y() == aEnd.Y()) { - if ( pSep->mnXRight >= pSep->mpNextSep->mnXLeft ) - return "overlapping separations in region"; + // Horizontal lines are ignored. + continue; } - if ( pSep->mbRemoved > 1 ) - return "Sep-mbRemoved overwrite"; - nCount++; - pSep = pSep->mpNextSep; - } + // At this point the line has to be vertical. + OSL_ASSERT(aStart.X() == aEnd.X()); - pBand = pBand->mpNextBand; - } + // Sort y-coordinates to simplify the algorithm and store the + // direction seperately. The direction is calculated as it is + // in other places (but seems to be the wrong way.) + const long nTop (::std::min(aStart.Y(), aEnd.Y())); + const long nBottom (::std::max(aStart.Y(), aEnd.Y())); + const LineType eLineType (aStart.Y() > aEnd.Y() ? LINE_DESCENDING : LINE_ASCENDING); - if ( pImplRegion->mnRectCount != nCount ) - return "mnRetCount is not valid"; - } + // Make sure that the current line is covered by bands. + pRegionBand->ImplAddMissingBands(nTop,nBottom); - return NULL; -} + // Find top-most band that may contain nTop. + ImplRegionBand* pBand = pRegionBand->ImplGetFirstRegionBand(); + while (pBand!=NULL && pBand->mnYBottom < nTop) + pBand = pBand->mpNextBand; + ImplRegionBand* pTopBand = pBand; + // If necessary split the band at nTop so that nTop is contained + // in the lower band. + if (pBand!=NULL + // Prevent the current band from becoming 0 pixel high + && pBand->mnYTop<nTop + // this allows the lowest pixel of the band to be split off + && pBand->mnYBottom>=nTop + // do not split a band that is just one pixel high + && pBand->mnYTop<pBand->mnYBottom) + { + // Split the top band. + pTopBand = pBand->SplitBand(nTop); + } -void TraceBands (const ImplRegionBand* pFirstBand) -{ - int nBandIndex (0); - const ImplRegionBand* pBand = pFirstBand; - while (pBand != NULL) - { - OSL_TRACE(" band %d %d->%d : ", nBandIndex++, - pBand->mnYTop, pBand->mnYBottom); + // Advance to band that may contain nBottom. + while (pBand!=NULL && pBand->mnYBottom < nBottom) + pBand = pBand->mpNextBand; + // The lowest band may have to be split at nBottom so that + // nBottom itself remains in the upper band. + if (pBand!=NULL + // allow the current band becoming 1 pixel high + && pBand->mnYTop<=nBottom + // prevent splitting off a band that is 0 pixel high + && pBand->mnYBottom>nBottom + // do not split a band that is just one pixel high + && pBand->mnYTop<pBand->mnYBottom) + { + // Split the bottom band. + pBand->SplitBand(nBottom+1); + } - ImplRegionBandPoint* pPoint = pBand->mpFirstBandPoint; - while (pPoint != NULL) - { - OSL_TRACE(" %d ", pPoint->mnX); - pPoint = pPoint->mpNextBandPoint; - } - OSL_TRACE(" | "); + // Note that we remember the top band (in pTopBand) but not the + // bottom band. The later can be determined by comparing y + // coordinates. - ImplRegionBandSep* pSep = pBand->mpFirstSep; - while (pSep != NULL) - { - OSL_TRACE(" %d->%d ", pSep->mnXLeft, pSep->mnXRight); - pSep = pSep->mpNextSep; + // Add the x-value as point to all bands in the nTop->nBottom range. + for (pBand=pTopBand; pBand!=NULL&&pBand->mnYTop<=nBottom; pBand=pBand->mpNextBand) + pBand->InsertPoint(aStart.X(), nLineId++, true, eLineType); + } } - OSL_TRACE("\n"); - - pBand = pBand->mpNextBand; - } -} -#endif - -// ======================================================================= - -inline void Region::ImplPolyPolyRegionToBandRegion() -{ - if( mpImplRegion->mpPolyPoly || mpImplRegion->mpB2DPolyPoly ) - ImplPolyPolyRegionToBandRegionFunc(); -} - -// ======================================================================= - -ImplRegionBase::ImplRegionBase( int nRefCount ) -: mnRefCount( nRefCount ) -, mnRectCount( 0 ) -, mpPolyPoly( NULL ) -, mpB2DPolyPoly( NULL ) -{} - -// ------------------------------------------------------------------------ - -ImplRegion::ImplRegion() -{ - mpFirstBand = NULL; - mpLastCheckedBand = NULL; -} - -// ------------------------------------------------------------------------ - -ImplRegion::ImplRegion( const PolyPolygon& rPolyPoly ) -{ - mpFirstBand = NULL; - mpLastCheckedBand = NULL; - mpPolyPoly = new PolyPolygon( rPolyPoly ); -} - -// ------------------------------------------------------------------------ - -ImplRegion::ImplRegion( const basegfx::B2DPolyPolygon& rPolyPoly ) -{ - mpFirstBand = NULL; - mpLastCheckedBand = NULL; - mpB2DPolyPoly = new basegfx::B2DPolyPolygon( rPolyPoly ); -} - -// ----------------------------------------------------------------------- - -ImplRegion::ImplRegion( const ImplRegion& rImplRegion ) -: ImplRegionBase() -{ - mpFirstBand = NULL; - mpLastCheckedBand = NULL; - mnRectCount = rImplRegion.mnRectCount; - - if ( rImplRegion.mpPolyPoly ) - mpPolyPoly = new PolyPolygon( *rImplRegion.mpPolyPoly ); - else if( rImplRegion.mpB2DPolyPoly ) - mpB2DPolyPoly = new basegfx::B2DPolyPolygon( *rImplRegion.mpB2DPolyPoly ); - - // insert band(s) into the list - ImplRegionBand* pNewBand; - ImplRegionBand* pPrevBand = 0; - ImplRegionBand* pBand = rImplRegion.mpFirstBand; - while ( pBand ) - { - pNewBand = new ImplRegionBand( *pBand ); - - // first element? -> set as first into the list - if ( pBand == rImplRegion.mpFirstBand ) - mpFirstBand = pNewBand; - else - pPrevBand->mpNextBand = pNewBand; - - pPrevBand = pNewBand; - pBand = pBand->mpNextBand; - } -} - -// ----------------------------------------------------------------------- - -ImplRegion::~ImplRegion() -{ - DBG_ASSERT( (this != &aImplEmptyRegion) && (this != &aImplNullRegion), - "ImplRegion::~ImplRegion() - Empty oder NULL-Region" ); - ImplRegionBand* pBand = mpFirstBand; - while ( pBand ) - { - ImplRegionBand* pTempBand = pBand->mpNextBand; - delete pBand; - pBand = pTempBand; + return pRegionBand; } -} - -// ----------------------------------------------------------------------- - -ImplRegionBase::~ImplRegionBase() -{ - delete mpPolyPoly; - delete mpB2DPolyPoly; -} - -// ----------------------------------------------------------------------- -// -// create complete range of bands in single steps - -void ImplRegion::CreateBandRange( long nYTop, long nYBottom ) -{ - // add top band - mpFirstBand = new ImplRegionBand( nYTop-1, nYTop-1 ); - - // begin first search from the first element - mpLastCheckedBand = mpFirstBand; - - ImplRegionBand* pBand = mpFirstBand; - for ( int i = nYTop; i <= nYBottom+1; i++ ) - { - // create new band - ImplRegionBand* pNewBand = new ImplRegionBand( i, i ); - pBand->mpNextBand = pNewBand; - if ( pBand != mpFirstBand ) - pNewBand->mpPrevBand = pBand; - - pBand = pBand->mpNextBand; - } -} -// ----------------------------------------------------------------------- - -sal_Bool ImplRegion::InsertLine( const Point& rStartPt, const Point& rEndPt, - long nLineId ) -{ - long nX, nY; - - // lines consisting of a single point do not interest here - if ( rStartPt == rEndPt ) - return sal_True; - - LineType eLineType = (rStartPt.Y() > rEndPt.Y()) ? LINE_DESCENDING : LINE_ASCENDING; - if ( rStartPt.X() == rEndPt.X() ) + /** Convert a general polygon (one for which ImplIsPolygonRectilinear() + returns <FALSE/>) to bands. + */ + RegionBand* ImplGeneralPolygonToBands(const PolyPolygon& rPolyPoly, const Rectangle& rPolygonBoundingBox) { - // vertical line - const long nEndY = rEndPt.Y(); + long nLineID = 0L; - nX = rStartPt.X(); - nY = rStartPt.Y(); + // initialisation and creation of Bands + RegionBand* pRegionBand = new RegionBand(); + pRegionBand->CreateBandRange(rPolygonBoundingBox.Top(), rPolygonBoundingBox.Bottom()); - if( nEndY > nY ) - { - for ( ; nY <= nEndY; nY++ ) - { - Point aNewPoint( nX, nY ); - InsertPoint( aNewPoint, nLineId, - (aNewPoint == rEndPt) || (aNewPoint == rStartPt), - eLineType ); - } - } - else - { - for ( ; nY >= nEndY; nY-- ) - { - Point aNewPoint( nX, nY ); - InsertPoint( aNewPoint, nLineId, - (aNewPoint == rEndPt) || (aNewPoint == rStartPt), - eLineType ); - } - } - } - else if ( rStartPt.Y() != rEndPt.Y() ) - { - const long nDX = labs( rEndPt.X() - rStartPt.X() ); - const long nDY = labs( rEndPt.Y() - rStartPt.Y() ); - const long nStartX = rStartPt.X(); - const long nStartY = rStartPt.Y(); - const long nEndX = rEndPt.X(); - const long nEndY = rEndPt.Y(); - const long nXInc = ( nStartX < nEndX ) ? 1L : -1L; - const long nYInc = ( nStartY < nEndY ) ? 1L : -1L; + // insert polygons + const sal_uInt16 nPolyCount = rPolyPoly.Count(); - if ( nDX >= nDY ) + for ( sal_uInt16 nPoly = 0; nPoly < nPolyCount; nPoly++ ) { - const long nDYX = ( nDY - nDX ) << 1; - const long nDY2 = nDY << 1; - long nD = nDY2 - nDX; - - for ( nX = nStartX, nY = nStartY; nX != nEndX; nX += nXInc ) - { - InsertPoint( Point( nX, nY ), nLineId, nStartX == nX, eLineType ); + // get reference to current polygon + const Polygon& aPoly = rPolyPoly.GetObject( nPoly ); + const sal_uInt16 nSize = aPoly.GetSize(); - if ( nD < 0L ) - nD += nDY2; - else - nD += nDYX, nY += nYInc; - } - } - else - { - const long nDYX = ( nDX - nDY ) << 1; - const long nDY2 = nDX << 1; - long nD = nDY2 - nDY; - - for ( nX = nStartX, nY = nStartY; nY != nEndY; nY += nYInc ) - { - InsertPoint( Point( nX, nY ), nLineId, nStartY == nY, eLineType ); - - if ( nD < 0L ) - nD += nDY2; - else - nD += nDYX, nX += nXInc; - } - } - - // last point - InsertPoint( Point( nEndX, nEndY ), nLineId, sal_True, eLineType ); - } - - return sal_True; -} - -// ----------------------------------------------------------------------- -// -// search for appropriate place for the new point - -sal_Bool ImplRegion::InsertPoint( const Point &rPoint, long nLineID, - sal_Bool bEndPoint, LineType eLineType ) -{ - DBG_ASSERT( mpFirstBand != NULL, "ImplRegion::InsertPoint - no bands available!" ); - - if ( rPoint.Y() == mpLastCheckedBand->mnYTop ) - { - mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType ); - return sal_True; - } + // not enough points ( <= 2 )? -> nothing to do! + if ( nSize <= 2 ) + continue; - if ( rPoint.Y() > mpLastCheckedBand->mnYTop ) - { - // Search ascending - while ( mpLastCheckedBand ) - { - // Insert point if possible - if ( rPoint.Y() == mpLastCheckedBand->mnYTop ) + // band the polygon + for ( sal_uInt16 nPoint = 1; nPoint < nSize; nPoint++ ) { - mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType ); - return sal_True; + pRegionBand->InsertLine( aPoly.GetPoint(nPoint-1), aPoly.GetPoint(nPoint), nLineID++ ); } - mpLastCheckedBand = mpLastCheckedBand->mpNextBand; - } + // close polygon with line from first point to last point, if neccesary + const Point rLastPoint = aPoly.GetPoint(nSize-1); + const Point rFirstPoint = aPoly.GetPoint(0); - DBG_ERROR( "ImplRegion::InsertPoint reached the end of the list!" ); - } - else - { - // Search descending - while ( mpLastCheckedBand ) - { - // Insert point if possible - if ( rPoint.Y() == mpLastCheckedBand->mnYTop ) + if ( rLastPoint != rFirstPoint ) { - mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType ); - return sal_True; + pRegionBand->InsertLine( rLastPoint, rFirstPoint, nLineID++ ); } - - mpLastCheckedBand = mpLastCheckedBand->mpPrevBand; } - DBG_ERROR( "ImplRegion::InsertPoint reached the beginning of the list!" ); + return pRegionBand; } +} // end of anonymous namespace - DBG_ERROR( "ImplRegion::InsertPoint point not inserted!" ); - - // reinitialize pointer (should never be reached!) - mpLastCheckedBand = mpFirstBand; - - return sal_False; -} - -// ----------------------------------------------------------------------- -// -// search for appropriate places for the new bands +////////////////////////////////////////////////////////////////////////////// -void ImplRegion::InsertBands( long nTop, long nBottom ) +bool Region::IsEmpty() const { - // region empty? -> set rectagle as first entry! - if ( !mpFirstBand ) - { - // add band with boundaries of the rectangle - mpFirstBand = new ImplRegionBand( nTop, nBottom ); - return; - } - - // find/insert bands for the boundaries of the rectangle - sal_Bool bTopBoundaryInserted = sal_False; - sal_Bool bTop2BoundaryInserted = sal_False; - sal_Bool bBottomBoundaryInserted = sal_False; - - // special case: top boundary is above the first band - ImplRegionBand* pNewBand; - if ( nTop < mpFirstBand->mnYTop ) - { - // create new band above the first in the list - pNewBand = new ImplRegionBand( nTop, mpFirstBand->mnYTop ); - if ( nBottom < mpFirstBand->mnYTop ) - pNewBand->mnYBottom = nBottom; - - // insert band into the list - pNewBand->mpNextBand = mpFirstBand; - mpFirstBand = pNewBand; - - bTopBoundaryInserted = sal_True; - } - - // insert band(s) into the list - ImplRegionBand* pBand = mpFirstBand; - while ( pBand ) - { - // Insert Bands if possible - if ( !bTopBoundaryInserted ) - bTopBoundaryInserted = InsertSingleBand( pBand, nTop - 1 ); - - if ( !bTop2BoundaryInserted ) - bTop2BoundaryInserted = InsertSingleBand( pBand, nTop ); - - if ( !bBottomBoundaryInserted && (nTop != nBottom) ) - bBottomBoundaryInserted = InsertSingleBand( pBand, nBottom ); - - // both boundaries inserted? -> nothing more to do - if ( bTopBoundaryInserted && bTop2BoundaryInserted && bBottomBoundaryInserted ) - break; - - // insert bands between two bands if neccessary - if ( pBand->mpNextBand ) - { - if ( (pBand->mnYBottom + 1) < pBand->mpNextBand->mnYTop ) - { - // copy band with list and set new boundary - pNewBand = new ImplRegionBand( pBand->mnYBottom+1, - pBand->mpNextBand->mnYTop-1 ); - - // insert band into the list - pNewBand->mpNextBand = pBand->mpNextBand; - pBand->mpNextBand = pNewBand; - } - } - - pBand = pBand->mpNextBand; - } + return !mbIsNull && !mpB2DPolyPolygon.get() && !mpPolyPolygon.get() && !mpRegionBand.get(); } -// ----------------------------------------------------------------------- -// -// create new band and insert it into the list - -sal_Bool ImplRegion::InsertSingleBand( ImplRegionBand* pBand, - long nYBandPosition ) +bool Region::IsNull() const { - // boundary already included in band with height 1? -> nothing to do! - if ( (pBand->mnYTop == pBand->mnYBottom) && - (nYBandPosition == pBand->mnYTop) ) - return sal_True; - - // insert single height band on top? - ImplRegionBand* pNewBand; - if ( nYBandPosition == pBand->mnYTop ) - { - // copy band with list and set new boundary - pNewBand = new ImplRegionBand( *pBand ); - pNewBand->mnYTop = nYBandPosition+1; - - // insert band into the list - pNewBand->mpNextBand = pBand->mpNextBand; - pBand->mnYBottom = nYBandPosition; - pBand->mpNextBand = pNewBand; - - return sal_True; - } - - // top of new rectangle within the current band? -> insert new band and copy data - if ( (nYBandPosition > pBand->mnYTop) && - (nYBandPosition < pBand->mnYBottom) ) - { - // copy band with list and set new boundary - pNewBand = new ImplRegionBand( *pBand ); - pNewBand->mnYTop = nYBandPosition; - - // insert band into the list - pNewBand->mpNextBand = pBand->mpNextBand; - pBand->mnYBottom = nYBandPosition; - pBand->mpNextBand = pNewBand; - - // copy band with list and set new boundary - pNewBand = new ImplRegionBand( *pBand ); - pNewBand->mnYTop = nYBandPosition; - - // insert band into the list - pBand->mpNextBand->mnYTop = nYBandPosition+1; - - pNewBand->mpNextBand = pBand->mpNextBand; - pBand->mnYBottom = nYBandPosition - 1; - pBand->mpNextBand = pNewBand; - - return sal_True; - } - - // create new band behind the current in the list - if ( !pBand->mpNextBand ) - { - if ( nYBandPosition == pBand->mnYBottom ) - { - // copy band with list and set new boundary - pNewBand = new ImplRegionBand( *pBand ); - pNewBand->mnYTop = pBand->mnYBottom; - pNewBand->mnYBottom = nYBandPosition; - - pBand->mnYBottom = nYBandPosition-1; - - // append band to the list - pBand->mpNextBand = pNewBand; - return sal_True; - } - - if ( nYBandPosition > pBand->mnYBottom ) - { - // create new band - pNewBand = new ImplRegionBand( pBand->mnYBottom + 1, nYBandPosition ); - - // append band to the list - pBand->mpNextBand = pNewBand; - return sal_True; - } - } - - return sal_False; + return mbIsNull; } -// ------------------------------------------------------------------------ - -void ImplRegion::InsertBand (ImplRegionBand* pPreviousBand, ImplRegionBand* pBandToInsert) +RegionBand* ImplCreateRegionBandFromPolyPolygon(const PolyPolygon& rPolyPolygon) { - OSL_ASSERT(pBandToInsert!=NULL); + RegionBand* pRetval = 0; - if (pPreviousBand == NULL) + if(rPolyPolygon.Count()) { - // Insert band before all others. - if (mpFirstBand != NULL) - mpFirstBand->mpPrevBand = pBandToInsert; - pBandToInsert->mpNextBand = mpFirstBand; - mpFirstBand = pBandToInsert; - } - else - { - // Insert band directly after pPreviousBand. - pBandToInsert->mpNextBand = pPreviousBand->mpNextBand; - pPreviousBand->mpNextBand = pBandToInsert; - pBandToInsert->mpPrevBand = pPreviousBand; - } -} + // ensure to subdivide when bezier segemnts are used, it's going to + // be expanded to rectangles + PolyPolygon aPolyPolygon; -// ------------------------------------------------------------------------ + rPolyPolygon.AdaptiveSubdivide(aPolyPolygon); -void ImplRegion::Union( long nLeft, long nTop, long nRight, long nBottom ) -{ - DBG_ASSERT( nLeft <= nRight, "ImplRegion::Union() - nLeft > nRight" ); - DBG_ASSERT( nTop <= nBottom, "ImplRegion::Union() - nTop > nBottom" ); - - // process union - ImplRegionBand* pBand = mpFirstBand; - while ( pBand ) - { - if ( pBand->mnYTop >= nTop ) + if(aPolyPolygon.Count()) { - if ( pBand->mnYBottom <= nBottom ) - pBand->Union( nLeft, nRight ); - else + const Rectangle aRect(aPolyPolygon.GetBoundRect()); + + if(!aRect.IsEmpty()) { -#ifdef DBG_UTIL - long nCurY = pBand->mnYBottom; - pBand = pBand->mpNextBand; - while ( pBand ) + if(ImplIsPolygonRectilinear(aPolyPolygon)) { - if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) ) - { - DBG_ERROR( "ImplRegion::Union() - Bands not sorted!" ); - } - pBand = pBand->mpNextBand; + // For rectilinear polygons there is an optimized band conversion. + pRetval = ImplRectilinearPolygonToBands(aPolyPolygon); } -#endif - break; - } - } - - pBand = pBand->mpNextBand; - } -} - -// ----------------------------------------------------------------------- - -void ImplRegion::Exclude( long nLeft, long nTop, long nRight, long nBottom ) -{ - DBG_ASSERT( nLeft <= nRight, "ImplRegion::Exclude() - nLeft > nRight" ); - DBG_ASSERT( nTop <= nBottom, "ImplRegion::Exclude() - nTop > nBottom" ); - - // process exclude - ImplRegionBand* pBand = mpFirstBand; - while ( pBand ) - { - if ( pBand->mnYTop >= nTop ) - { - if ( pBand->mnYBottom <= nBottom ) - pBand->Exclude( nLeft, nRight ); - else - { -#ifdef DBG_UTIL - long nCurY = pBand->mnYBottom; - pBand = pBand->mpNextBand; - while ( pBand ) + else { - if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) ) - { - DBG_ERROR( "ImplRegion::Exclude() - Bands not sorted!" ); - } - pBand = pBand->mpNextBand; + pRetval = ImplGeneralPolygonToBands(aPolyPolygon, aRect); } -#endif - break; - } - } - - pBand = pBand->mpNextBand; - } -} - -// ----------------------------------------------------------------------- -void ImplRegion::XOr( long nLeft, long nTop, long nRight, long nBottom ) -{ - DBG_ASSERT( nLeft <= nRight, "ImplRegion::Exclude() - nLeft > nRight" ); - DBG_ASSERT( nTop <= nBottom, "ImplRegion::Exclude() - nTop > nBottom" ); - - // process xor - ImplRegionBand* pBand = mpFirstBand; - while ( pBand ) - { - if ( pBand->mnYTop >= nTop ) - { - if ( pBand->mnYBottom <= nBottom ) - pBand->XOr( nLeft, nRight ); - else - { -#ifdef DBG_UTIL - long nCurY = pBand->mnYBottom; - pBand = pBand->mpNextBand; - while ( pBand ) + // Convert points into seps. + if(pRetval) { - if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) ) + pRetval->processPoints(); + + // Optimize list of bands. Adjacent bands with identical lists + // of seps are joined. + if(!pRetval->OptimizeBandList()) { - DBG_ERROR( "ImplRegion::XOr() - Bands not sorted!" ); + delete pRetval; + pRetval = 0; } - pBand = pBand->mpNextBand; } -#endif - break; } } - - pBand = pBand->mpNextBand; } -} -// ----------------------------------------------------------------------- -// -// remove empty bands + return pRetval; +} -sal_Bool ImplRegion::OptimizeBandList() +PolyPolygon Region::ImplCreatePolyPolygonFromRegionBand() const { - DBG_ASSERT( (this != &aImplNullRegion) && (this != &aImplEmptyRegion), - "ImplRegion::OptimizeBandList() - Empty oder NULL-Region" ); - - mnRectCount = 0; + PolyPolygon aRetval; - ImplRegionBand* pPrevBand = 0; - ImplRegionBand* pBand = mpFirstBand; - while ( pBand ) + if(getRegionBand()) { - const sal_Bool bBTEqual = pBand->mpNextBand && - (pBand->mnYBottom == pBand->mpNextBand->mnYTop); + RectangleVector aRectangles; + GetRegionRectangles(aRectangles); - // no separation? -> remove! - if ( pBand->IsEmpty() || (bBTEqual && (pBand->mnYBottom == pBand->mnYTop)) ) + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - // save pointer - ImplRegionBand* pOldBand = pBand; - - // previous element of the list - if ( pBand == mpFirstBand ) - mpFirstBand = pBand->mpNextBand; - else - pPrevBand->mpNextBand = pBand->mpNextBand; - - pBand = pBand->mpNextBand; - delete pOldBand; - } - else - { - // fixup - if ( bBTEqual ) - pBand->mnYBottom = pBand->mpNextBand->mnYTop-1; - - // this and next band with equal separations? -> combine! - if ( pBand->mpNextBand && - ((pBand->mnYBottom+1) == pBand->mpNextBand->mnYTop) && - (*pBand == *pBand->mpNextBand) ) - { - // expand current height - pBand->mnYBottom = pBand->mpNextBand->mnYBottom; - - // remove next band from list - ImplRegionBand* pDeletedBand = pBand->mpNextBand; - pBand->mpNextBand = pDeletedBand->mpNextBand; - delete pDeletedBand; - - // check band again! - } - else - { - // count rectangles within band - ImplRegionBandSep* pSep = pBand->mpFirstSep; - while ( pSep ) - { - mnRectCount++; - pSep = pSep->mpNextSep; - } - - pPrevBand = pBand; - pBand = pBand->mpNextBand; - } + aRetval.Insert(Polygon(*aRectIter)); } } - -#ifdef DBG_UTIL - pBand = mpFirstBand; - while ( pBand ) + else { - DBG_ASSERT( pBand->mpFirstSep != NULL, - "Exiting ImplRegion::OptimizeBandList(): empty band in region!" ); - - if ( pBand->mnYBottom < pBand->mnYTop ) - DBG_ERROR( "ImplRegion::OptimizeBandList(): YBottomBoundary < YTopBoundary" ); - - if ( pBand->mpNextBand ) - { - if ( pBand->mnYBottom >= pBand->mpNextBand->mnYTop ) - DBG_ERROR( "ImplRegion::OptimizeBandList(): overlapping bands in region!" ); - } - - pBand = pBand->mpNextBand; + OSL_ENSURE(false, "Called with no local RegionBand (!)"); } -#endif - - return (mnRectCount != 0); -} -// ======================================================================= - -void Region::ImplCopyData() -{ - mpImplRegion->mnRefCount--; - mpImplRegion = new ImplRegion( *mpImplRegion ); + return aRetval; } -// ======================================================================= - -Region::Region() +basegfx::B2DPolyPolygon Region::ImplCreateB2DPolyPolygonFromRegionBand() const { - DBG_CTOR( Region, ImplDbgTestRegion ); + PolyPolygon aPoly(ImplCreatePolyPolygonFromRegionBand()); - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + return aPoly.getB2DPolyPolygon(); } -// ----------------------------------------------------------------------- - -Region::Region( RegionType eType ) +Region::Region(bool bIsNull) +: mpB2DPolyPolygon(), + mpPolyPolygon(), + mpRegionBand(), + mbIsNull(bIsNull) { - DBG_CTOR( Region, ImplDbgTestRegion ); - DBG_ASSERT( (eType == REGION_NULL) || (eType == REGION_EMPTY), - "Region( RegionType ) - RegionType != EMPTY/NULL" ); - - if ( eType == REGION_NULL ) - mpImplRegion = (ImplRegion*)(&aImplNullRegion); - else - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); } -// ----------------------------------------------------------------------- - -Region::Region( const Rectangle& rRect ) +Region::Region(const Rectangle& rRect) +: mpB2DPolyPolygon(), + mpPolyPolygon(), + mpRegionBand(), + mbIsNull(false) { - DBG_CTOR( Region, ImplDbgTestRegion ); - - ImplCreateRectRegion( rRect ); + mpRegionBand.reset(rRect.IsEmpty() ? 0 : new RegionBand(rRect)); } -// ----------------------------------------------------------------------- - -Region::Region( const Polygon& rPolygon ) +Region::Region(const Polygon& rPolygon) +: mpB2DPolyPolygon(), + mpPolyPolygon(), + mpRegionBand(), + mbIsNull(false) { - DBG_CTOR( Region, ImplDbgTestRegion ); DBG_CHKOBJ( &rPolygon, Polygon, NULL ); - ImplCreatePolyPolyRegion( rPolygon ); + if(rPolygon.GetSize()) + { + ImplCreatePolyPolyRegion(rPolygon); + } } -// ----------------------------------------------------------------------- - -Region::Region( const PolyPolygon& rPolyPoly ) +Region::Region(const PolyPolygon& rPolyPoly) +: mpB2DPolyPolygon(), + mpPolyPolygon(), + mpRegionBand(), + mbIsNull(false) { - DBG_CTOR( Region, ImplDbgTestRegion ); DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL ); - ImplCreatePolyPolyRegion( rPolyPoly ); + if(rPolyPoly.Count()) + { + ImplCreatePolyPolyRegion(rPolyPoly); + } } -// ----------------------------------------------------------------------- - -Region::Region( const basegfx::B2DPolyPolygon& rPolyPoly ) +Region::Region(const basegfx::B2DPolyPolygon& rPolyPoly) +: mpB2DPolyPolygon(), + mpPolyPolygon(), + mpRegionBand(), + mbIsNull(false) { - DBG_CTOR( Region, ImplDbgTestRegion ); DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL ); - ImplCreatePolyPolyRegion( rPolyPoly ); + if(rPolyPoly.count()) + { + ImplCreatePolyPolyRegion(rPolyPoly); + } } -// ----------------------------------------------------------------------- - -Region::Region( const Region& rRegion ) +Region::Region(const Region& rRegion) +: mpB2DPolyPolygon(rRegion.mpB2DPolyPolygon), + mpPolyPolygon(rRegion.mpPolyPolygon), + mpRegionBand(rRegion.mpRegionBand), + mbIsNull(rRegion.mbIsNull) { - DBG_CTOR( Region, ImplDbgTestRegion ); - DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); - DBG_ASSERT( rRegion.mpImplRegion->mnRefCount < 0xFFFFFFFE, "Region: RefCount overflow" ); - - // copy pointer to instance of implementation - mpImplRegion = rRegion.mpImplRegion; - if ( mpImplRegion->mnRefCount ) - mpImplRegion->mnRefCount++; } -// ----------------------------------------------------------------------- - Region::~Region() { - DBG_DTOR( Region, ImplDbgTestRegion ); - - // statische Object haben RefCount von 0 - if ( mpImplRegion->mnRefCount ) - { - if ( mpImplRegion->mnRefCount > 1 ) - mpImplRegion->mnRefCount--; - else - delete mpImplRegion; - } -} - -// ----------------------------------------------------------------------- - -void Region::ImplCreateRectRegion( const Rectangle& rRect ) -{ - if ( rRect.IsEmpty() ) - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); - else - { - // get justified rectangle - long nTop = Min( rRect.Top(), rRect.Bottom() ); - long nBottom = Max( rRect.Top(), rRect.Bottom() ); - long nLeft = Min( rRect.Left(), rRect.Right() ); - long nRight = Max( rRect.Left(), rRect.Right() ); - - // create instance of implementation class - mpImplRegion = new ImplRegion(); - - // add band with boundaries of the rectangle - mpImplRegion->mpFirstBand = new ImplRegionBand( nTop, nBottom ); - - // Set left and right boundaries of the band - mpImplRegion->mpFirstBand->Union( nLeft, nRight ); - mpImplRegion->mnRectCount = 1; - } } -// ----------------------------------------------------------------------- - void Region::ImplCreatePolyPolyRegion( const PolyPolygon& rPolyPoly ) { const sal_uInt16 nPolyCount = rPolyPoly.Count(); - if ( nPolyCount ) + + if(nPolyCount) { // polypolygon empty? -> empty region - const Rectangle aRect( rPolyPoly.GetBoundRect() ); + const Rectangle aRect(rPolyPoly.GetBoundRect()); - if ( !aRect.IsEmpty() ) + if(!aRect.IsEmpty()) { // width OR height == 1 ? => Rectangular region - if ( (aRect.GetWidth() == 1) - || (aRect.GetHeight() == 1) - || rPolyPoly.IsRect() ) + if((1 == aRect.GetWidth()) || (1 == aRect.GetHeight()) || rPolyPoly.IsRect()) { - ImplCreateRectRegion( aRect ); + mpRegionBand.reset(new RegionBand(aRect)); } else - mpImplRegion = new ImplRegion( rPolyPoly ); + { + mpPolyPolygon.reset(new PolyPolygon(rPolyPoly)); + } + + mbIsNull = false; } - else - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); } - else - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); } -// ----------------------------------------------------------------------- - void Region::ImplCreatePolyPolyRegion( const basegfx::B2DPolyPolygon& rPolyPoly ) { - if (rPolyPoly.count()==0 || rPolyPoly.getB2DRange().isEmpty()) - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); - else - mpImplRegion = new ImplRegion( rPolyPoly ); -} - -// ----------------------------------------------------------------------- - -void Region::ImplPolyPolyRegionToBandRegionFunc() -{ - // ensure to subdivide when bezier segemnts are used, it's going to - // be expanded to rectangles - PolyPolygon aPolyPoly; - GetPolyPolygon().AdaptiveSubdivide(aPolyPoly); - - if ( mpImplRegion->mnRefCount > 1 ) - mpImplRegion->mnRefCount--; - else - delete mpImplRegion; - - if ( aPolyPoly.Count() ) + if(rPolyPoly.count() && !rPolyPoly.getB2DRange().isEmpty()) { - // polypolygon empty? -> empty region - const Rectangle aRect( aPolyPoly.GetBoundRect() ); - - if ( !aRect.IsEmpty() ) - { - if (ImplIsPolygonRectilinear(aPolyPoly)) - { - // For rectilinear polygons there is an optimized band conversion. - mpImplRegion = ImplRectilinearPolygonToBands(aPolyPoly); - } - else - { - mpImplRegion = ImplGeneralPolygonToBands(aPolyPoly, aRect); - } - - // Convert points into seps. - ImplRegionBand* pRegionBand = mpImplRegion->mpFirstBand; - while ( pRegionBand ) - { - // generate separations from the lines and process union - pRegionBand->ProcessPoints(); - pRegionBand = pRegionBand->mpNextBand; - } - - // Optimize list of bands. Adjacent bands with identical lists - // of seps are joined. - if ( !mpImplRegion->OptimizeBandList() ) - { - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); - } - } - else - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + mpB2DPolyPolygon.reset(new basegfx::B2DPolyPolygon(rPolyPoly)); + mbIsNull = false; } - else - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); } -// ----------------------------------------------------------------------- - void Region::Move( long nHorzMove, long nVertMove ) { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - // no region data? -> nothing to do - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + if(IsNull() || IsEmpty()) + { + // empty or null need no move return; + } - // no own instance data? -> make own copy! - if ( mpImplRegion->mnRefCount > 1 ) - ImplCopyData(); + if(!nHorzMove && !nVertMove) + { + // no move defined + return; + } - if ( mpImplRegion->mpPolyPoly ) - mpImplRegion->mpPolyPoly->Move( nHorzMove, nVertMove ); - else if( mpImplRegion->mpB2DPolyPoly ) + if(getB2DPolyPolygon()) { - mpImplRegion->mpB2DPolyPoly->transform(basegfx::tools::createTranslateB2DHomMatrix(nHorzMove, nVertMove)); + basegfx::B2DPolyPolygon aPoly(*getB2DPolyPolygon()); + + aPoly.transform(basegfx::tools::createTranslateB2DHomMatrix(nHorzMove, nVertMove)); + mpB2DPolyPolygon.reset(aPoly.count() ? new basegfx::B2DPolyPolygon(aPoly) : 0); + mpPolyPolygon.reset(); + mpRegionBand.reset(); } - else + else if(getPolyPolygon()) { - ImplRegionBand* pBand = mpImplRegion->mpFirstBand; - while ( pBand ) - { - // process the vertical move - if ( nVertMove != 0) - { - pBand->mnYTop = pBand->mnYTop + nVertMove; - pBand->mnYBottom = pBand->mnYBottom + nVertMove; - } + PolyPolygon aPoly(*getPolyPolygon()); - // process the horizontal move - if ( nHorzMove != 0) - pBand->MoveX( nHorzMove ); + aPoly.Move(nHorzMove, nVertMove); + mpB2DPolyPolygon.reset(); + mpPolyPolygon.reset(aPoly.Count() ? new PolyPolygon(aPoly) : 0); + mpRegionBand.reset(); + } + else if(getRegionBand()) + { + RegionBand* pNew = new RegionBand(*getRegionBand()); - pBand = pBand->mpNextBand; - } + pNew->Move(nHorzMove, nVertMove); + mpB2DPolyPolygon.reset(); + mpPolyPolygon.reset(); + mpRegionBand.reset(pNew); + } + else + { + OSL_ENSURE(false, "Region::Move error: impossible combination (!)"); } } -// ----------------------------------------------------------------------- - void Region::Scale( double fScaleX, double fScaleY ) { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - // no region data? -> nothing to do - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + if(IsNull() || IsEmpty()) + { + // empty or null need no scale return; + } - // no own instance data? -> make own copy! - if ( mpImplRegion->mnRefCount > 1 ) - ImplCopyData(); + if(basegfx::fTools::equalZero(fScaleX) && basegfx::fTools::equalZero(fScaleY)) + { + // no scale defined + return; + } - if ( mpImplRegion->mpPolyPoly ) - mpImplRegion->mpPolyPoly->Scale( fScaleX, fScaleY ); - else if( mpImplRegion->mpB2DPolyPoly ) + if(getB2DPolyPolygon()) { - mpImplRegion->mpB2DPolyPoly->transform(basegfx::tools::createScaleB2DHomMatrix(fScaleX, fScaleY)); + basegfx::B2DPolyPolygon aPoly(*getB2DPolyPolygon()); + + aPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fScaleX, fScaleY)); + mpB2DPolyPolygon.reset(aPoly.count() ? new basegfx::B2DPolyPolygon(aPoly) : 0); + mpPolyPolygon.reset(); + mpRegionBand.reset(); } - else + else if(getPolyPolygon()) { - ImplRegionBand* pBand = mpImplRegion->mpFirstBand; - while ( pBand ) - { - // process the vertical move - if ( fScaleY != 0.0 ) - { - pBand->mnYTop = FRound( pBand->mnYTop * fScaleY ); - pBand->mnYBottom = FRound( pBand->mnYBottom * fScaleY ); - } + PolyPolygon aPoly(*getPolyPolygon()); - // process the horizontal move - if ( fScaleX != 0.0 ) - pBand->ScaleX( fScaleX ); + aPoly.Scale(fScaleX, fScaleY); + mpB2DPolyPolygon.reset(); + mpPolyPolygon.reset(aPoly.Count() ? new PolyPolygon(aPoly) : 0); + mpRegionBand.reset(); + } + else if(getRegionBand()) + { + RegionBand* pNew = new RegionBand(*getRegionBand()); - pBand = pBand->mpNextBand; - } + pNew->Scale(fScaleX, fScaleY); + mpB2DPolyPolygon.reset(); + mpPolyPolygon.reset(); + mpRegionBand.reset(pNew); + } + else + { + OSL_ENSURE(false, "Region::Scale error: impossible combination (!)"); } } -// ----------------------------------------------------------------------- - -sal_Bool Region::Union( const Rectangle& rRect ) +bool Region::Union( const Rectangle& rRect ) { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); + if(rRect.IsEmpty()) + { + // empty rectangle will not expand the existing union, nothing to do + return true; + } - // is rectangle empty? -> nothing to do - if ( rRect.IsEmpty() ) - return sal_True; + if(IsEmpty()) + { + // no local data, the union will be equal to source. Create using rectangle + *this = rRect; + return true; + } - if( HasPolyPolygon() ) + if(HasPolyPolygonOrB2DPolyPolygon()) { - // get this B2DPolyPolygon - basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); - aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); + // get this B2DPolyPolygon, solve on polygon base + basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon()); - if( aThisPolyPoly.count() == 0 ) + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation(aThisPolyPoly); + + if(!aThisPolyPoly.count()) { + // no local polygon, use the rectangle as new region *this = rRect; - return true; + } + else + { + // get the other B2DPolyPolygon and use logical Or-Operation + const basegfx::B2DPolygon aRectPoly( + basegfx::tools::createPolygonFromRect( + basegfx::B2DRectangle( + rRect.Left(), + rRect.Top(), + rRect.Right(), + rRect.Bottom()))); + const basegfx::B2DPolyPolygon aClip( + basegfx::tools::solvePolygonOperationOr( + aThisPolyPoly, + basegfx::B2DPolyPolygon(aRectPoly))); + *this = Region(aClip); } - // get the other B2DPolyPolygon - basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) ); - basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly ); - - basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationOr( aThisPolyPoly, aOtherPolyPoly ); - *this = Region( aClip ); - - return sal_True; + return true; } - ImplPolyPolyRegionToBandRegion(); + // only region band mode possibility left here or null/empty + const RegionBand* pCurrent = getRegionBand(); - // no instance data? -> create! - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - mpImplRegion = new ImplRegion(); + if(!pCurrent) + { + // no region band, create using the rectangle + *this = rRect; + return true; + } - // no own instance data? -> make own copy! - if ( mpImplRegion->mnRefCount > 1 ) - ImplCopyData(); + RegionBand* pNew = new RegionBand(*pCurrent); // get justified rectangle - long nLeft = Min( rRect.Left(), rRect.Right() ); - long nTop = Min( rRect.Top(), rRect.Bottom() ); - long nRight = Max( rRect.Left(), rRect.Right() ); - long nBottom = Max( rRect.Top(), rRect.Bottom() ); + const long nLeft(std::min(rRect.Left(), rRect.Right())); + const long nTop(std::min(rRect.Top(), rRect.Bottom())); + const long nRight(std::max(rRect.Left(), rRect.Right())); + const long nBottom(std::max(rRect.Top(), rRect.Bottom())); // insert bands if the boundaries are not allready in the list - mpImplRegion->InsertBands( nTop, nBottom ); + pNew->InsertBands(nTop, nBottom); // process union - mpImplRegion->Union( nLeft, nTop, nRight, nBottom ); + pNew->Union(nLeft, nTop, nRight, nBottom); // cleanup - if ( !mpImplRegion->OptimizeBandList() ) + if(!pNew->OptimizeBandList()) { - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + delete pNew; + pNew = 0; } - return sal_True; + mpRegionBand.reset(pNew); + return true; } -// ----------------------------------------------------------------------- - -sal_Bool Region::Intersect( const Rectangle& rRect ) +bool Region::Intersect( const Rectangle& rRect ) { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - // is rectangle empty? -> nothing to do if ( rRect.IsEmpty() ) { - // statische Object haben RefCount von 0 - if ( mpImplRegion->mnRefCount ) - { - if ( mpImplRegion->mnRefCount > 1 ) - mpImplRegion->mnRefCount--; - else - delete mpImplRegion; - } - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); - return sal_True; + // empty rectangle will create empty region + SetEmpty(); + return true; } - // #103137# Avoid banding for special cases - if ( mpImplRegion->mpPolyPoly ) + if(IsNull()) { - // #127431# make ImplRegion unique, if not already. - if( mpImplRegion->mnRefCount > 1 ) - { - mpImplRegion->mnRefCount--; - mpImplRegion = new ImplRegion( *mpImplRegion->mpPolyPoly ); - } - - // use the PolyPolygon::Clip method for rectangles, this is - // fairly simple (does not even use GPC) and saves us from - // unnecessary banding - mpImplRegion->mpPolyPoly->Clip( rRect ); - - // The clipping above may lead to empty ClipRegion - if(!mpImplRegion->mpPolyPoly->Count()) - { - // react on empty ClipRegion; ImplRegion already is unique (see above) - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); - } + // null region (everything) intersect with rect will give rect + *this = rRect; + return true; + } - return sal_True; + if(IsEmpty()) + { + // no content, cannot get more empty + return true; } - else if( mpImplRegion->mpB2DPolyPoly ) + + if(HasPolyPolygonOrB2DPolyPolygon()) { - // #127431# make ImplRegion unique, if not already. - if( mpImplRegion->mnRefCount > 1 ) + // if polygon data prefer double precision, the other will be lost (if buffered) + if(getB2DPolyPolygon()) { - mpImplRegion->mnRefCount--; - mpImplRegion = new ImplRegion( *mpImplRegion->mpB2DPolyPoly ); + const basegfx::B2DPolyPolygon aPoly( + basegfx::tools::clipPolyPolygonOnRange( + *getB2DPolyPolygon(), + basegfx::B2DRange( + rRect.Left(), + rRect.Top(), + rRect.Right() + 1, + rRect.Bottom() + 1), + true, + false)); + + mpB2DPolyPolygon.reset(aPoly.count() ? new basegfx::B2DPolyPolygon(aPoly) : 0); + mpPolyPolygon.reset(); + mpRegionBand.reset(); } + else // if(getPolyPolygon()) + { + PolyPolygon aPoly(*getPolyPolygon()); - *mpImplRegion->mpB2DPolyPoly = - basegfx::tools::clipPolyPolygonOnRange( - *mpImplRegion->mpB2DPolyPoly, - basegfx::B2DRange( - rRect.Left(), - rRect.Top(), - rRect.Right() + 1, - rRect.Bottom() + 1), - true, - false); + // use the PolyPolygon::Clip method for rectangles, this is + // fairly simple (does not even use GPC) and saves us from + // unnecessary banding + aPoly.Clip(rRect); - // The clipping above may lead to empty ClipRegion - if(!mpImplRegion->mpB2DPolyPoly->count()) - { - // react on empty ClipRegion; ImplRegion already is unique (see above) - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + mpB2DPolyPolygon.reset(); + mpPolyPolygon.reset(aPoly.Count() ? new PolyPolygon(aPoly) : 0); + mpRegionBand.reset(); } - return sal_True; + return true; } - else - ImplPolyPolyRegionToBandRegion(); - - // is region empty? -> nothing to do! - if ( mpImplRegion == &aImplEmptyRegion ) - return sal_True; - // get justified rectangle - long nLeft = Min( rRect.Left(), rRect.Right() ); - long nTop = Min( rRect.Top(), rRect.Bottom() ); - long nRight = Max( rRect.Left(), rRect.Right() ); - long nBottom = Max( rRect.Top(), rRect.Bottom() ); + // only region band mode possibility left here or null/empty + const RegionBand* pCurrent = getRegionBand(); - // is own region NULL-region? -> copy data! - if ( mpImplRegion == &aImplNullRegion ) + if(!pCurrent) { - // create instance of implementation class - mpImplRegion = new ImplRegion(); - - // add band with boundaries of the rectangle - mpImplRegion->mpFirstBand = new ImplRegionBand( nTop, nBottom ); - - // Set left and right boundaries of the band - mpImplRegion->mpFirstBand->Union( nLeft, nRight ); - mpImplRegion->mnRectCount = 1; - - return sal_True; + // region is empty -> nothing to do! + return true; } - // no own instance data? -> make own copy! - if ( mpImplRegion->mnRefCount > 1 ) - ImplCopyData(); + RegionBand* pNew = new RegionBand(*pCurrent); - // insert bands if the boundaries are not allready in the list - mpImplRegion->InsertBands( nTop, nBottom ); + // get justified rectangle + const long nLeft(std::min(rRect.Left(), rRect.Right())); + const long nTop(std::min(rRect.Top(), rRect.Bottom())); + const long nRight(std::max(rRect.Left(), rRect.Right())); + const long nBottom(std::max(rRect.Top(), rRect.Bottom())); - // process intersections - ImplRegionBand* pPrevBand = 0; - ImplRegionBand* pBand = mpImplRegion->mpFirstBand; - while ( pBand ) - { - // band within intersection boundary? -> process. otherwise remove - if ( (pBand->mnYTop >= nTop) && - (pBand->mnYBottom <= nBottom) ) - { - // process intersection - pBand->Intersect( nLeft, nRight ); + // insert bands if the boundaries are not allready in the list + pNew->InsertBands(nTop, nBottom); - pPrevBand = pBand; - pBand = pBand->mpNextBand; - } - else - { - ImplRegionBand* pOldBand = pBand; - if ( pBand == mpImplRegion->mpFirstBand ) - mpImplRegion->mpFirstBand = pBand->mpNextBand; - else - pPrevBand->mpNextBand = pBand->mpNextBand; - pBand = pBand->mpNextBand; - delete pOldBand; - } - } + // process intersect + pNew->Intersect(nLeft, nTop, nRight, nBottom); // cleanup - if ( !mpImplRegion->OptimizeBandList() ) + if(!pNew->OptimizeBandList()) { - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + delete pNew; + pNew = 0; } - return sal_True; + mpRegionBand.reset(pNew); + return true; } -// ----------------------------------------------------------------------- - -sal_Bool Region::Exclude( const Rectangle& rRect ) +bool Region::Exclude( const Rectangle& rRect ) { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - // is rectangle empty? -> nothing to do if ( rRect.IsEmpty() ) - return sal_True; + { + // excluding nothing will do no change + return true; + } + + if(IsEmpty()) + { + // cannot exclude from empty, done + return true; + } - if( HasPolyPolygon() ) + if(IsNull()) + { + // error; cannnot exclude from null region since this is not representable + // in the data + OSL_ENSURE(false, "Region::Exclude error: Cannot exclude from null region (!)"); + return true; + } + + if( HasPolyPolygonOrB2DPolyPolygon() ) { // get this B2DPolyPolygon - basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); - aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); + basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon()); - if( aThisPolyPoly.count() == 0 ) - return sal_True; + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation(aThisPolyPoly); + + if(!aThisPolyPoly.count()) + { + // when local polygon is empty, nothing can be excluded + return true; + } // get the other B2DPolyPolygon - basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) ); - basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly ); + const basegfx::B2DPolygon aRectPoly( + basegfx::tools::createPolygonFromRect( + basegfx::B2DRectangle(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom()))); + const basegfx::B2DPolyPolygon aOtherPolyPoly(aRectPoly); + const basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff(aThisPolyPoly, aOtherPolyPoly); - basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly ); - *this = Region( aClip ); + *this = Region(aClip); - return sal_True; + return true; } - ImplPolyPolyRegionToBandRegion(); + // only region band mode possibility left here or null/empty + const RegionBand* pCurrent = getRegionBand(); - // no instance data? -> create! - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - return sal_True; + if(!pCurrent) + { + // empty? -> done! + return true; + } - // no own instance data? -> make own copy! - if ( mpImplRegion->mnRefCount > 1 ) - ImplCopyData(); + RegionBand* pNew = new RegionBand(*pCurrent); // get justified rectangle - long nLeft = Min( rRect.Left(), rRect.Right() ); - long nTop = Min( rRect.Top(), rRect.Bottom() ); - long nRight = Max( rRect.Left(), rRect.Right() ); - long nBottom = Max( rRect.Top(), rRect.Bottom() ); + const long nLeft(std::min(rRect.Left(), rRect.Right())); + const long nTop(std::min(rRect.Top(), rRect.Bottom())); + const long nRight(std::max(rRect.Left(), rRect.Right())); + const long nBottom(std::max(rRect.Top(), rRect.Bottom())); // insert bands if the boundaries are not allready in the list - mpImplRegion->InsertBands( nTop, nBottom ); + pNew->InsertBands(nTop, nBottom); // process exclude - mpImplRegion->Exclude( nLeft, nTop, nRight, nBottom ); + pNew->Exclude(nLeft, nTop, nRight, nBottom); // cleanup - if ( !mpImplRegion->OptimizeBandList() ) + if(!pNew->OptimizeBandList()) { - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + delete pNew; + pNew = 0; } - return sal_True; + mpRegionBand.reset(pNew); + return true; } -// ----------------------------------------------------------------------- - -sal_Bool Region::XOr( const Rectangle& rRect ) +bool Region::XOr( const Rectangle& rRect ) { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - // is rectangle empty? -> nothing to do if ( rRect.IsEmpty() ) - return sal_True; + { + // empty rectangle will not change local content + return true; + } + + if(IsEmpty()) + { + // rRect will be the xored-form (local off, rect on) + *this = rRect; + return true; + } - if( HasPolyPolygon() ) + if(IsNull()) + { + // error; cannnot exclude from null region since this is not representable + // in the data + OSL_ENSURE(false, "Region::XOr error: Cannot XOr with null region (!)"); + return true; + } + + if( HasPolyPolygonOrB2DPolyPolygon() ) { // get this B2DPolyPolygon - basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); + basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon()); + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); - if( aThisPolyPoly.count() == 0 ) + if(!aThisPolyPoly.count()) { + // no local content, XOr will be equal to rectangle *this = rRect; - return sal_True; + return true; } // get the other B2DPolyPolygon - basegfx::B2DPolygon aRectPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) ); - basegfx::B2DPolyPolygon aOtherPolyPoly( aRectPoly ); + const basegfx::B2DPolygon aRectPoly( + basegfx::tools::createPolygonFromRect( + basegfx::B2DRectangle(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom()))); + const basegfx::B2DPolyPolygon aOtherPolyPoly(aRectPoly); + const basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor(aThisPolyPoly, aOtherPolyPoly); - basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly ); - *this = Region( aClip ); + *this = Region(aClip); - return sal_True; + return true; } - ImplPolyPolyRegionToBandRegion(); + // only region band mode possibility left here or null/empty + const RegionBand* pCurrent = getRegionBand(); - // no instance data? -> create! - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - mpImplRegion = new ImplRegion(); + if(!pCurrent) + { + // rRect will be the xored-form (local off, rect on) + *this = rRect; + return true; + } - // no own instance data? -> make own copy! - if ( mpImplRegion->mnRefCount > 1 ) - ImplCopyData(); + // only region band mode possibility left here or null/empty + RegionBand* pNew = new RegionBand(*getRegionBand()); // get justified rectangle - long nLeft = Min( rRect.Left(), rRect.Right() ); - long nTop = Min( rRect.Top(), rRect.Bottom() ); - long nRight = Max( rRect.Left(), rRect.Right() ); - long nBottom = Max( rRect.Top(), rRect.Bottom() ); + const long nLeft(std::min(rRect.Left(), rRect.Right())); + const long nTop(std::min(rRect.Top(), rRect.Bottom())); + const long nRight(std::max(rRect.Left(), rRect.Right())); + const long nBottom(std::max(rRect.Top(), rRect.Bottom())); // insert bands if the boundaries are not allready in the list - mpImplRegion->InsertBands( nTop, nBottom ); + pNew->InsertBands(nTop, nBottom); // process xor - mpImplRegion->XOr( nLeft, nTop, nRight, nBottom ); + pNew->XOr(nLeft, nTop, nRight, nBottom); // cleanup - if ( !mpImplRegion->OptimizeBandList() ) + if(!pNew->OptimizeBandList()) { - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + delete pNew; + pNew = 0; } - return sal_True; + mpRegionBand.reset(pNew); + return true; } -// ----------------------------------------------------------------------- -void Region::ImplUnionPolyPolygon( const Region& i_rRegion ) +bool Region::Union( const Region& rRegion ) { - // get this B2DPolyPolygon - basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); - aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); - - if( aThisPolyPoly.count() == 0 ) + if(rRegion.IsEmpty()) { - *this = i_rRegion; - return; + // no extension at all + return true; } - // get the other B2DPolyPolygon - basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() ); - aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly ); + if(rRegion.IsNull()) + { + // extending with null region -> null region + *this = Region(true); + return true; + } + if(IsEmpty()) + { + // local is empty, union will give source region + *this = rRegion; + return true; + } - basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationOr( aThisPolyPoly, aOtherPolyPoly ); + if(IsNull()) + { + // already fully expanded (is null region), cannot be extended + return true; + } - *this = Region( aClip ); -} + if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() ) + { + // get this B2DPolyPolygon + basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon()); -sal_Bool Region::Union( const Region& rRegion ) -{ - DBG_CHKTHIS( Region, ImplDbgTestRegion ); + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation(aThisPolyPoly); - if( rRegion.HasPolyPolygon() || HasPolyPolygon() ) - { - ImplUnionPolyPolygon( rRegion ); - return sal_True; - } + if(!aThisPolyPoly.count()) + { + // when no local content, union will be equal to rRegion + *this = rRegion; + return true; + } - ImplPolyPolyRegionToBandRegion(); - ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); + // get the other B2DPolyPolygon + basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon()); + aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation(aOtherPolyPoly); - // is region empty or null? -> nothing to do - if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) ) - return sal_True; + // use logical OR operation + basegfx::B2DPolyPolygon aClip(basegfx::tools::solvePolygonOperationOr(aThisPolyPoly, aOtherPolyPoly)); - // no instance data? -> create! - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - mpImplRegion = new ImplRegion(); + *this = Region( aClip ); + return true; + } - // no own instance data? -> make own copy! - if ( mpImplRegion->mnRefCount > 1 ) - ImplCopyData(); + // only region band mode possibility left here or null/empty + const RegionBand* pCurrent = getRegionBand(); - // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden - ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand; - while ( pBand ) + if(!pCurrent) { - // insert bands if the boundaries are not allready in the list - mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom ); + // local is empty, union will give source region + *this = rRegion; + return true; + } - // process all elements of the list - ImplRegionBandSep* pSep = pBand->mpFirstSep; - while ( pSep ) - { - mpImplRegion->Union( pSep->mnXLeft, pBand->mnYTop, - pSep->mnXRight, pBand->mnYBottom ); - pSep = pSep->mpNextSep; - } + const RegionBand* pSource = rRegion.getRegionBand(); - pBand = pBand->mpNextBand; + if(!pSource) + { + // no extension at all + return true; } + // prepare source and target + RegionBand* pNew = new RegionBand(*pCurrent); + + // union with source + pNew->Union(*pSource); + // cleanup - if ( !mpImplRegion->OptimizeBandList() ) + if(!pNew->OptimizeBandList()) { - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + delete pNew; + pNew = 0; } - return sal_True; + mpRegionBand.reset(pNew); + return true; } -// ----------------------------------------------------------------------- -void Region::ImplIntersectWithPolyPolygon( const Region& i_rRegion ) +bool Region::Intersect( const Region& rRegion ) { - // get this B2DPolyPolygon - basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); - if( aThisPolyPoly.count() == 0 ) + // same instance data? -> nothing to do! + if(getB2DPolyPolygon() && getB2DPolyPolygon() == rRegion.getB2DPolyPolygon()) { - *this = i_rRegion; - return; + return true; } - // get the other B2DPolyPolygon - basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() ); + if(getPolyPolygon() && getPolyPolygon() == rRegion.getPolyPolygon()) + { + return true; + } - basegfx::B2DPolyPolygon aClip = basegfx::tools::clipPolyPolygonOnPolyPolygon( aOtherPolyPoly, aThisPolyPoly, true, false ); - *this = Region( aClip ); -} + if(getRegionBand() && getRegionBand() == rRegion.getRegionBand()) + { + return true; + } -sal_Bool Region::Intersect( const Region& rRegion ) -{ - DBG_CHKTHIS( Region, ImplDbgTestRegion ); + if(rRegion.IsNull()) + { + // source region is null-region, intersect will not change local region + return true; + } - // same instance data? -> nothing to do! - if ( mpImplRegion == rRegion.mpImplRegion ) - return sal_True; + if(IsNull()) + { + // when local region is null-region, intersect will be equal to source + *this = rRegion; + return true; + } - if( rRegion.HasPolyPolygon() || HasPolyPolygon() ) + if(rRegion.IsEmpty()) { - ImplIntersectWithPolyPolygon( rRegion ); - return sal_True; + // source region is empty, intersection will always be empty + SetEmpty(); + return true; } - ImplPolyPolyRegionToBandRegion(); - ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); + if(IsEmpty()) + { + // local region is empty, cannot get more emty than that. Nothing to do + return true; + } - if ( mpImplRegion == &aImplEmptyRegion ) - return sal_True; + if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() ) + { + // get this B2DPolyPolygon + basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon()); - // is region null? -> nothing to do - if ( rRegion.mpImplRegion == &aImplNullRegion ) - return sal_True; + if(!aThisPolyPoly.count()) + { + // local region is empty, cannot get more emty than that. Nothing to do + return true; + } - // is rectangle empty? -> nothing to do - if ( rRegion.mpImplRegion == &aImplEmptyRegion ) - { - // statische Object haben RefCount von 0 - if ( mpImplRegion->mnRefCount ) + // get the other B2DPolyPolygon + basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon()); + + if(!aOtherPolyPoly.count()) { - if ( mpImplRegion->mnRefCount > 1 ) - mpImplRegion->mnRefCount--; - else - delete mpImplRegion; + // source region is empty, intersection will always be empty + SetEmpty(); + return true; } - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); - return sal_True; + + const basegfx::B2DPolyPolygon aClip( + basegfx::tools::clipPolyPolygonOnPolyPolygon( + aOtherPolyPoly, + aThisPolyPoly, + true, + false)); + *this = Region( aClip ); + return true; + } + + // only region band mode possibility left here or null/empty + const RegionBand* pCurrent = getRegionBand(); + + if(!pCurrent) + { + // local region is empty, cannot get more emty than that. Nothing to do + return true; } - // is own region NULL-region? -> copy data! - if ( mpImplRegion == &aImplNullRegion) + const RegionBand* pSource = rRegion.getRegionBand(); + + if(!pSource) { - mpImplRegion = rRegion.mpImplRegion; - rRegion.mpImplRegion->mnRefCount++; - return sal_True; + // source region is empty, intersection will always be empty + SetEmpty(); + return true; } - // Wenn wir weniger Rechtecke haben, drehen wir den Intersect-Aufruf um - if ( mpImplRegion->mnRectCount+2 < rRegion.mpImplRegion->mnRectCount ) + // both RegionBands exist and are not empty + if(pCurrent->getRectangleCount() + 2 < pSource->getRectangleCount()) { + // when we have less rectangles, turn around the call Region aTempRegion = rRegion; aTempRegion.Intersect( *this ); *this = aTempRegion; } else { - // no own instance data? -> make own copy! - if ( mpImplRegion->mnRefCount > 1 ) - ImplCopyData(); + // prepare new regionBand + RegionBand* pNew = pCurrent ? new RegionBand(*pCurrent) : new RegionBand(); - // mark all bands as untouched - ImplRegionBand* pBand = mpImplRegion->mpFirstBand; - while ( pBand ) - { - pBand->mbTouched = sal_False; - pBand = pBand->mpNextBand; - } + // intersect with source + pNew->Intersect(*pSource); - pBand = rRegion.mpImplRegion->mpFirstBand; - while ( pBand ) + // cleanup + if(!pNew->OptimizeBandList()) { - // insert bands if the boundaries are not allready in the list - mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom ); + delete pNew; + pNew = 0; + } - // process all elements of the list - ImplRegionBandSep* pSep = pBand->mpFirstSep; - while ( pSep ) - { - // left boundary? - if ( pSep == pBand->mpFirstSep ) - { - // process intersection and do not remove untouched bands - mpImplRegion->Exclude( LONG_MIN+1, pBand->mnYTop, - pSep->mnXLeft-1, pBand->mnYBottom ); - } + mpRegionBand.reset(pNew); + } - // right boundary? - if ( pSep->mpNextSep == NULL ) - { - // process intersection and do not remove untouched bands - mpImplRegion->Exclude( pSep->mnXRight+1, pBand->mnYTop, - LONG_MAX-1, pBand->mnYBottom ); - } - else - { - // process intersection and do not remove untouched bands - mpImplRegion->Exclude( pSep->mnXRight+1, pBand->mnYTop, - pSep->mpNextSep->mnXLeft-1, pBand->mnYBottom ); - } + return true; +} - pSep = pSep->mpNextSep; - } +bool Region::Exclude( const Region& rRegion ) +{ + if ( rRegion.IsEmpty() ) + { + // excluding nothing will do no change + return true; + } - pBand = pBand->mpNextBand; - } + if ( rRegion.IsNull() ) + { + // excluding everything will create empty region + SetEmpty(); + return true; + } - // remove all untouched bands if bands allready left - ImplRegionBand* pPrevBand = 0; - pBand = mpImplRegion->mpFirstBand; - while ( pBand ) - { - if ( !pBand->mbTouched ) - { - // save pointer - ImplRegionBand* pOldBand = pBand; + if(IsEmpty()) + { + // cannot exclude from empty, done + return true; + } - // previous element of the list - if ( pBand == mpImplRegion->mpFirstBand ) - mpImplRegion->mpFirstBand = pBand->mpNextBand; - else - pPrevBand->mpNextBand = pBand->mpNextBand; + if(IsNull()) + { + // error; cannnot exclude from null region since this is not representable + // in the data + OSL_ENSURE(false, "Region::Exclude error: Cannot exclude from null region (!)"); + return true; + } - pBand = pBand->mpNextBand; - delete pOldBand; - } - else - { - pPrevBand = pBand; - pBand = pBand->mpNextBand; - } - } + if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() ) + { + // get this B2DPolyPolygon + basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon()); - // cleanup - if ( !mpImplRegion->OptimizeBandList() ) + if(!aThisPolyPoly.count()) { - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + // cannot exclude from empty, done + return true; } - } - - return sal_True; -} -// ----------------------------------------------------------------------- -void Region::ImplExcludePolyPolygon( const Region& i_rRegion ) -{ - // get this B2DPolyPolygon - basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); - if( aThisPolyPoly.count() == 0 ) - return; - aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); - // get the other B2DPolyPolygon - basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() ); - aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly ); + // get the other B2DPolyPolygon + basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon()); + aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly ); - basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly ); - *this = Region( aClip ); -} + basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly ); + *this = Region( aClip ); + return true; + } -sal_Bool Region::Exclude( const Region& rRegion ) -{ - DBG_CHKTHIS( Region, ImplDbgTestRegion ); + // only region band mode possibility left here or null/empty + const RegionBand* pCurrent = getRegionBand(); - if( rRegion.HasPolyPolygon() || HasPolyPolygon() ) + if(!pCurrent) { - ImplExcludePolyPolygon( rRegion ); - return sal_True; + // cannot exclude from empty, done + return true; } - ImplPolyPolyRegionToBandRegion(); - ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); - - // is region empty or null? -> nothing to do - if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) ) - return sal_True; - - // no instance data? -> nothing to do - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - return sal_True; + const RegionBand* pSource = rRegion.getRegionBand(); - // no own instance data? -> make own copy! - if ( mpImplRegion->mnRefCount > 1 ) - ImplCopyData(); - - // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden - ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand; - while ( pBand ) + if(!pSource) { - // insert bands if the boundaries are not allready in the list - mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom ); + // excluding nothing will do no change + return true; + } - // process all elements of the list - ImplRegionBandSep* pSep = pBand->mpFirstSep; - while ( pSep ) - { - mpImplRegion->Exclude( pSep->mnXLeft, pBand->mnYTop, - pSep->mnXRight, pBand->mnYBottom ); - pSep = pSep->mpNextSep; - } + // prepare source and target + RegionBand* pNew = new RegionBand(*pCurrent); - // Wir optimieren schon in der Schleife, da wir davon - // ausgehen, das wir insgesammt weniger Baender ueberpruefen - // muessen - if ( !mpImplRegion->OptimizeBandList() ) - { - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); - break; - } + // union with source + const bool bSuccess(pNew->Exclude(*pSource)); - pBand = pBand->mpNextBand; + // cleanup + if(!bSuccess) + { + delete pNew; + pNew = 0; } - return sal_True; + mpRegionBand.reset(pNew); + return true; } -// ----------------------------------------------------------------------- -void Region::ImplXOrPolyPolygon( const Region& i_rRegion ) +bool Region::XOr( const Region& rRegion ) { - // get this B2DPolyPolygon - basegfx::B2DPolyPolygon aThisPolyPoly( ConvertToB2DPolyPolygon() ); - if( aThisPolyPoly.count() == 0 ) + if ( rRegion.IsEmpty() ) { - *this = i_rRegion; - return; + // empty region will not change local content + return true; } - aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); - // get the other B2DPolyPolygon - basegfx::B2DPolyPolygon aOtherPolyPoly( const_cast<Region&>(i_rRegion).ConvertToB2DPolyPolygon() ); - aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly ); - - basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly ); - *this = Region( aClip ); -} + if ( rRegion.IsNull() ) + { + // error; cannnot exclude null region from local since this is not representable + // in the data + OSL_ENSURE(false, "Region::XOr error: Cannot XOr with null region (!)"); + return true; + } -sal_Bool Region::XOr( const Region& rRegion ) -{ - DBG_CHKTHIS( Region, ImplDbgTestRegion ); + if(IsEmpty()) + { + // rRect will be the xored-form (local off, rect on) + *this = rRegion; + return true; + } - if( rRegion.HasPolyPolygon() || HasPolyPolygon() ) + if(IsNull()) { - ImplXOrPolyPolygon( rRegion ); - return sal_True; + // error; cannnot exclude from null region since this is not representable + // in the data + OSL_ENSURE(false, "Region::XOr error: Cannot XOr with null region (!)"); + return false; } - ImplPolyPolyRegionToBandRegion(); - ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); + if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() ) + { + // get this B2DPolyPolygon + basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon()); - // is region empty or null? -> nothing to do - if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) ) - return sal_True; + if(!aThisPolyPoly.count()) + { + // rRect will be the xored-form (local off, rect on) + *this = rRegion; + return true; + } - // no own instance data? -> XOr = copy - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly ); + + // get the other B2DPolyPolygon + basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon()); + aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly ); + + basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly ); + *this = Region( aClip ); + return true; + } + + // only region band mode possibility left here or null/empty + const RegionBand* pCurrent = getRegionBand(); + + if(!pCurrent) { + // rRect will be the xored-form (local off, rect on) *this = rRegion; - return sal_True; + return true; } - // no own instance data? -> make own copy! - if ( mpImplRegion->mnRefCount > 1 ) - ImplCopyData(); + const RegionBand* pSource = rRegion.getRegionBand(); - // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden - ImplRegionBand* pBand = rRegion.mpImplRegion->mpFirstBand; - while ( pBand ) + if(!pSource) { - // insert bands if the boundaries are not allready in the list - mpImplRegion->InsertBands( pBand->mnYTop, pBand->mnYBottom ); + // empty region will not change local content + return true; + } - // process all elements of the list - ImplRegionBandSep* pSep = pBand->mpFirstSep; - while ( pSep ) - { - mpImplRegion->XOr( pSep->mnXLeft, pBand->mnYTop, - pSep->mnXRight, pBand->mnYBottom ); - pSep = pSep->mpNextSep; - } + // prepare source and target + RegionBand* pNew = new RegionBand(*pCurrent); - pBand = pBand->mpNextBand; - } + // union with source + pNew->XOr(*pSource); // cleanup - if ( !mpImplRegion->OptimizeBandList() ) + if(!pNew->OptimizeBandList()) { - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + delete pNew; + pNew = 0; } - return sal_True; -} + mpRegionBand.reset(pNew); -// ----------------------------------------------------------------------- + return true; +} Rectangle Region::GetBoundRect() const { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - Rectangle aRect; + if(IsEmpty()) + { + // no internal data? -> region is empty! + return Rectangle(); + } - // no internal data? -> region is empty! - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - return aRect; + if(IsNull()) + { + // error; null region has no BoundRect + // OSL_ENSURE(false, "Region::GetBoundRect error: null region has unlimitied bound rect, not representable (!)"); + return Rectangle(); + } - // PolyPolygon data im Imp structure? - if ( mpImplRegion->mpPolyPoly ) - return mpImplRegion->mpPolyPoly->GetBoundRect(); - if( mpImplRegion->mpB2DPolyPoly ) + // prefer double precision source + if(getB2DPolyPolygon()) { - const basegfx::B2DRange aRange(basegfx::tools::getRange(*mpImplRegion->mpB2DPolyPoly)); + const basegfx::B2DRange aRange(basegfx::tools::getRange(*getB2DPolyPolygon())); if(aRange.isEmpty()) { @@ -2130,268 +1280,149 @@ Rectangle Region::GetBoundRect() const } } - // no band in the list? -> region is empty! - if ( !mpImplRegion->mpFirstBand ) - return aRect; - - // get the boundaries of the first band - long nYTop = mpImplRegion->mpFirstBand->mnYTop; - long nYBottom = mpImplRegion->mpFirstBand->mnYBottom; - long nXLeft = mpImplRegion->mpFirstBand->GetXLeftBoundary(); - long nXRight = mpImplRegion->mpFirstBand->GetXRightBoundary(); - - // look in the band list (don't test first band again!) - ImplRegionBand* pBand = mpImplRegion->mpFirstBand->mpNextBand; - while ( pBand ) + if(getPolyPolygon()) { - nYBottom = pBand->mnYBottom; - nXLeft = Min( nXLeft, pBand->GetXLeftBoundary() ); - nXRight = Max( nXRight, pBand->GetXRightBoundary() ); + return getPolyPolygon()->GetBoundRect(); + } - pBand = pBand->mpNextBand; + if(getRegionBand()) + { + return getRegionBand()->GetBoundRect(); } - // set rectangle - aRect = Rectangle( nXLeft, nYTop, nXRight, nYBottom ); - return aRect; + return Rectangle(); } -// ----------------------------------------------------------------------- - -sal_Bool Region::HasPolyPolygon() const +const PolyPolygon Region::GetAsPolyPolygon() const { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - if( !mpImplRegion ) - return false; - if( mpImplRegion->mpPolyPoly ) - return true; - if( mpImplRegion->mpB2DPolyPoly ) - return true; - return false; -} - -// ----------------------------------------------------------------------- + if(getPolyPolygon()) + { + return *getPolyPolygon(); + } -PolyPolygon Region::GetPolyPolygon() const -{ - DBG_CHKTHIS( Region, ImplDbgTestRegion ); + if(getB2DPolyPolygon()) + { + // the polygon needs to be converted, buffer the down converion + const PolyPolygon aPolyPolgon(*getB2DPolyPolygon()); + const_cast< Region* >(this)->mpPolyPolygon.reset(new PolyPolygon(aPolyPolgon)); - PolyPolygon aRet; + return *getPolyPolygon(); + } - if( mpImplRegion->mpPolyPoly ) - aRet = *mpImplRegion->mpPolyPoly; - else if( mpImplRegion->mpB2DPolyPoly ) + if(getRegionBand()) { - // the polygon needs to be converted - aRet = PolyPolygon( *mpImplRegion->mpB2DPolyPoly ); - // TODO: cache the converted polygon? - // mpImplRegion->mpB2DPolyPoly = aRet; + // the BandRegion needs to be converted, buffer the converion + const PolyPolygon aPolyPolgon(ImplCreatePolyPolygonFromRegionBand()); + const_cast< Region* >(this)->mpPolyPolygon.reset(new PolyPolygon(aPolyPolgon)); + + return *getPolyPolygon(); } - return aRet; + return PolyPolygon(); } -// ----------------------------------------------------------------------- - -const basegfx::B2DPolyPolygon Region::GetB2DPolyPolygon() const +const basegfx::B2DPolyPolygon Region::GetAsB2DPolyPolygon() const { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); + if(getB2DPolyPolygon()) + { + return *getB2DPolyPolygon(); + } - basegfx::B2DPolyPolygon aRet; + if(getPolyPolygon()) + { + // the polygon needs to be converted, buffer the up conversion. This will be preferred from now. + const basegfx::B2DPolyPolygon aB2DPolyPolygon(getPolyPolygon()->getB2DPolyPolygon()); + const_cast< Region* >(this)->mpB2DPolyPolygon.reset(new basegfx::B2DPolyPolygon(aB2DPolyPolygon)); + + return *getB2DPolyPolygon(); + } - if( mpImplRegion->mpB2DPolyPoly ) - aRet = *mpImplRegion->mpB2DPolyPoly; - else if( mpImplRegion->mpPolyPoly ) + if(getRegionBand()) { - // the polygon needs to be converted - aRet = mpImplRegion->mpPolyPoly->getB2DPolyPolygon(); - // TODO: cache the converted polygon? - // mpImplRegion->mpB2DPolyPoly = aRet; + // the BandRegion needs to be converted, buffer the converion + const basegfx::B2DPolyPolygon aB2DPolyPolygon(ImplCreateB2DPolyPolygonFromRegionBand()); + const_cast< Region* >(this)->mpB2DPolyPolygon.reset(new basegfx::B2DPolyPolygon(aB2DPolyPolygon)); + + return *getB2DPolyPolygon(); } - return aRet; + return basegfx::B2DPolyPolygon(); } -// ----------------------------------------------------------------------- - -basegfx::B2DPolyPolygon Region::ConvertToB2DPolyPolygon() +const RegionBand* Region::GetAsRegionBand() const { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - basegfx::B2DPolyPolygon aRet; - - if( HasPolyPolygon() ) - aRet = GetB2DPolyPolygon(); - else + if(!getRegionBand()) { - RegionHandle aHdl = BeginEnumRects(); - Rectangle aSubRect; - while( GetNextEnumRect( aHdl, aSubRect ) ) + if(getB2DPolyPolygon()) + { + // convert B2DPolyPolygon to RegionBand, buffer it and return it + const_cast< Region* >(this)->mpRegionBand.reset(ImplCreateRegionBandFromPolyPolygon(PolyPolygon(*getB2DPolyPolygon()))); + } + else if(getPolyPolygon()) { - basegfx::B2DPolygon aPoly( basegfx::tools::createPolygonFromRect( - basegfx::B2DRectangle( aSubRect.Left(), aSubRect.Top(), aSubRect.Right(), aSubRect.Bottom() ) ) ); - aRet.append( aPoly ); + // convert B2DPolyPolygon to RegionBand, buffer it and return it + const_cast< Region* >(this)->mpRegionBand.reset(ImplCreateRegionBandFromPolyPolygon(*getPolyPolygon())); } - EndEnumRects( aHdl ); } - return aRet; -} - -// ----------------------------------------------------------------------- - -bool Region::ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo, - long& rX, long& rY, - long& rWidth, long& rHeight ) const -{ - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - ((Region*)this)->ImplPolyPolyRegionToBandRegion(); - - // no internal data? -> region is empty! - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - return false; - - // no band in the list? -> region is empty! - if ( mpImplRegion->mpFirstBand == NULL ) - return false; - - // initialise pointer for first access - ImplRegionBand* pCurrRectBand = mpImplRegion->mpFirstBand; - ImplRegionBandSep* pCurrRectBandSep = pCurrRectBand->mpFirstSep; - - DBG_ASSERT( pCurrRectBandSep != NULL, "Erstes Band wurde nicht optimiert." ); - if ( !pCurrRectBandSep ) - return false; - - // get boundaries of current rectangle - rX = pCurrRectBandSep->mnXLeft; - rY = pCurrRectBand->mnYTop; - rWidth = pCurrRectBandSep->mnXRight - pCurrRectBandSep->mnXLeft + 1; - rHeight = pCurrRectBand->mnYBottom - pCurrRectBand->mnYTop + 1; - - // save pointers - rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand; - rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep; - - return true; + return getRegionBand(); } -// ----------------------------------------------------------------------- - -bool Region::ImplGetNextRect( ImplRegionInfo& rImplRegionInfo, - long& rX, long& rY, - long& rWidth, long& rHeight ) const +bool Region::IsInside( const Point& rPoint ) const { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - // no internal data? -> region is empty! - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) + if(IsEmpty()) + { + // no point can be in empty region return false; + } - // get last pointers - ImplRegionBand* pCurrRectBand = (ImplRegionBand*)rImplRegionInfo.mpVoidCurrRectBand; - ImplRegionBandSep* pCurrRectBandSep = (ImplRegionBandSep*)rImplRegionInfo.mpVoidCurrRectBandSep; - - // get next separation from current band - pCurrRectBandSep = pCurrRectBandSep->mpNextSep; - - // no separation found? -> go to next band! - if ( !pCurrRectBandSep ) + if(IsNull()) { - // get next band - pCurrRectBand = pCurrRectBand->mpNextBand; - - // no band found? -> not further rectangles! - if( !pCurrRectBand ) - return false; - - // get first separation in current band - pCurrRectBandSep = pCurrRectBand->mpFirstSep; + // all points are inside null-region + return true; } - // get boundaries of current rectangle - rX = pCurrRectBandSep->mnXLeft; - rY = pCurrRectBand->mnYTop; - rWidth = pCurrRectBandSep->mnXRight - pCurrRectBandSep->mnXLeft + 1; - rHeight = pCurrRectBand->mnYBottom - pCurrRectBand->mnYTop + 1; - - // save new pointers - rImplRegionInfo.mpVoidCurrRectBand = (void*)pCurrRectBand; - rImplRegionInfo.mpVoidCurrRectBandSep = (void*)pCurrRectBandSep; + // Too expensive (?) + //if(mpImplRegion->getRegionPolyPoly()) + //{ + // return mpImplRegion->getRegionPolyPoly()->IsInside( rPoint ); + //} - return true; -} + // ensure RegionBand existance + const_cast< Region* >(this)->GetAsRegionBand(); + const RegionBand* pRegionBand = getRegionBand(); -// ----------------------------------------------------------------------- + if(pRegionBand) + { + return pRegionBand->IsInside(rPoint); + } -RegionType Region::GetType() const -{ - if ( mpImplRegion == &aImplEmptyRegion ) - return REGION_EMPTY; - else if ( mpImplRegion == &aImplNullRegion ) - return REGION_NULL; - else if ( mpImplRegion->mnRectCount == 1 ) - return REGION_RECTANGLE; - else - return REGION_COMPLEX; + return false; } -// ----------------------------------------------------------------------- - -sal_Bool Region::IsInside( const Point& rPoint ) const +bool Region::IsInside( const Rectangle& rRect ) const { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - // PolyPolygon data im Imp structure? - ((Region*)this)->ImplPolyPolyRegionToBandRegion(); -/* - if ( mpImplRegion->mpPolyPoly ) - return mpImplRegion->mpPolyPoly->IsInside( rPoint ); -*/ - - // no instance data? -> not inside - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - return sal_False; - - // search band list - ImplRegionBand* pBand = mpImplRegion->mpFirstBand; - while ( pBand ) - { - // is point within band? - if ( (pBand->mnYTop <= rPoint.Y()) && - (pBand->mnYBottom >= rPoint.Y()) ) - { - // is point within separation of the band? - if ( pBand->IsInside( rPoint.X() ) ) - return sal_True; - else - return sal_False; - } - - pBand = pBand->mpNextBand; + if(IsEmpty()) + { + // no rectangle can be in empty region + return false; } - return sal_False; -} - -// ----------------------------------------------------------------------- - -sal_Bool Region::IsInside( const Rectangle& rRect ) const -{ - DBG_CHKTHIS( Region, ImplDbgTestRegion ); + if(IsNull()) + { + // rectangle always inside null-region + return true; + } - // is rectangle empty? -> not inside if ( rRect.IsEmpty() ) - return sal_False; - - // no instance data? -> not inside - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - return sal_False; + { + // is rectangle empty? -> not inside + return false; + } // create region from rectangle and intersect own region - Region aRegion = rRect; - aRegion.Exclude( *this ); + Region aRegion(rRect); + aRegion.Exclude(*this); // rectangle is inside if exclusion is empty return aRegion.IsEmpty(); @@ -2399,227 +1430,151 @@ sal_Bool Region::IsInside( const Rectangle& rRect ) const // ----------------------------------------------------------------------- -sal_Bool Region::IsOver( const Rectangle& rRect ) const +bool Region::IsOver( const Rectangle& rRect ) const { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); + if(IsEmpty()) + { + // nothing can be over something empty + return false; + } - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - return sal_False; + if(IsNull()) + { + // everything is over null region + return true; + } // Can we optimize this ??? - is used in StarDraw for brushes pointers // Why we have no IsOver for Regions ??? // create region from rectangle and intersect own region - Region aRegion = rRect; + Region aRegion(rRect); aRegion.Intersect( *this ); // rectangle is over if include is not empty return !aRegion.IsEmpty(); } -// ----------------------------------------------------------------------- - void Region::SetNull() { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - // statische Object haben RefCount von 0 - if ( mpImplRegion->mnRefCount ) - { - if ( mpImplRegion->mnRefCount > 1 ) - mpImplRegion->mnRefCount--; - else - delete mpImplRegion; - } - - // set new type - mpImplRegion = (ImplRegion*)(&aImplNullRegion); + // reset all content + mpB2DPolyPolygon.reset(); + mpPolyPolygon.reset(); + mpRegionBand.reset(); + mbIsNull = true; } -// ----------------------------------------------------------------------- - void Region::SetEmpty() { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - // statische Object haben RefCount von 0 - if ( mpImplRegion->mnRefCount ) - { - if ( mpImplRegion->mnRefCount > 1 ) - mpImplRegion->mnRefCount--; - else - delete mpImplRegion; - } - - // set new type - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + // reset all content + mpB2DPolyPolygon.reset(); + mpPolyPolygon.reset(); + mpRegionBand.reset(); + mbIsNull = false; } -// ----------------------------------------------------------------------- - Region& Region::operator=( const Region& rRegion ) { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); - DBG_ASSERT( rRegion.mpImplRegion->mnRefCount < 0xFFFFFFFE, "Region: RefCount overflow" ); + // reset all content + mpB2DPolyPolygon = rRegion.mpB2DPolyPolygon; + mpPolyPolygon = rRegion.mpPolyPolygon; + mpRegionBand = rRegion.mpRegionBand; + mbIsNull = rRegion.mbIsNull; - // Zuerst Referenzcounter erhoehen, damit man sich selbst zuweisen kann - // RefCount == 0 fuer statische Objekte - if ( rRegion.mpImplRegion->mnRefCount ) - rRegion.mpImplRegion->mnRefCount++; - - // statische Object haben RefCount von 0 - if ( mpImplRegion->mnRefCount ) - { - if ( mpImplRegion->mnRefCount > 1 ) - mpImplRegion->mnRefCount--; - else - delete mpImplRegion; - } - - mpImplRegion = rRegion.mpImplRegion; return *this; } -// ----------------------------------------------------------------------- - Region& Region::operator=( const Rectangle& rRect ) { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - // statische Object haben RefCount von 0 - if ( mpImplRegion->mnRefCount ) - { - if ( mpImplRegion->mnRefCount > 1 ) - mpImplRegion->mnRefCount--; - else - delete mpImplRegion; - } + mpB2DPolyPolygon.reset(); + mpPolyPolygon.reset(); + mpRegionBand.reset(rRect.IsEmpty() ? 0 : new RegionBand(rRect)); + mbIsNull = false; - ImplCreateRectRegion( rRect ); return *this; } -// ----------------------------------------------------------------------- - -sal_Bool Region::operator==( const Region& rRegion ) const +bool Region::operator==( const Region& rRegion ) const { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); - - // reference to same object? -> equal! - if ( mpImplRegion == rRegion.mpImplRegion ) - return sal_True; - - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - return sal_False; - - if ( (rRegion.mpImplRegion == &aImplEmptyRegion) || (rRegion.mpImplRegion == &aImplNullRegion) ) - return sal_False; - - if ( rRegion.mpImplRegion->mpPolyPoly && mpImplRegion->mpPolyPoly ) - return *rRegion.mpImplRegion->mpPolyPoly == *mpImplRegion->mpPolyPoly; - else + if(IsNull() && rRegion.IsNull()) { - ((Region*)this)->ImplPolyPolyRegionToBandRegion(); - ((Region*)&rRegion)->ImplPolyPolyRegionToBandRegion(); - - // Eine der beiden Regions kann jetzt Empty sein - if ( mpImplRegion == rRegion.mpImplRegion ) - return sal_True; - - if ( mpImplRegion == &aImplEmptyRegion ) - return sal_False; - - if ( rRegion.mpImplRegion == &aImplEmptyRegion ) - return sal_False; + // both are null region + return true; } - // initialise pointers - ImplRegionBand* pOwnRectBand = mpImplRegion->mpFirstBand; - ImplRegionBandSep* pOwnRectBandSep = pOwnRectBand->mpFirstSep; - ImplRegionBand* pSecondRectBand = rRegion.mpImplRegion->mpFirstBand; - ImplRegionBandSep* pSecondRectBandSep = pSecondRectBand->mpFirstSep; - while ( pOwnRectBandSep && pSecondRectBandSep ) + if(IsEmpty() && rRegion.IsEmpty()) { - // get boundaries of current rectangle - long nOwnXLeft = pOwnRectBandSep->mnXLeft; - long nSecondXLeft = pSecondRectBandSep->mnXLeft; - if ( nOwnXLeft != nSecondXLeft ) - return sal_False; - - long nOwnYTop = pOwnRectBand->mnYTop; - long nSecondYTop = pSecondRectBand->mnYTop; - if ( nOwnYTop != nSecondYTop ) - return sal_False; + // both are empty + return true; + } - long nOwnXRight = pOwnRectBandSep->mnXRight; - long nSecondXRight = pSecondRectBandSep->mnXRight; - if ( nOwnXRight != nSecondXRight ) - return sal_False; + if(getB2DPolyPolygon() && getB2DPolyPolygon() == rRegion.getB2DPolyPolygon()) + { + // same instance data? -> equal + return true; + } - long nOwnYBottom = pOwnRectBand->mnYBottom; - long nSecondYBottom = pSecondRectBand->mnYBottom; - if ( nOwnYBottom != nSecondYBottom ) - return sal_False; + if(getPolyPolygon() && getPolyPolygon() == rRegion.getPolyPolygon()) + { + // same instance data? -> equal + return true; + } - // get next separation from current band - pOwnRectBandSep = pOwnRectBandSep->mpNextSep; + if(getRegionBand() && getRegionBand() == rRegion.getRegionBand()) + { + // same instance data? -> equal + return true; + } - // no separation found? -> go to next band! - if ( !pOwnRectBandSep ) - { - // get next band - pOwnRectBand = pOwnRectBand->mpNextBand; + if(IsNull() || IsEmpty()) + { + return false; + } - // get first separation in current band - if( pOwnRectBand ) - pOwnRectBandSep = pOwnRectBand->mpFirstSep; - } + if(rRegion.IsNull() || rRegion.IsEmpty()) + { + return false; + } - // get next separation from current band - pSecondRectBandSep = pSecondRectBandSep->mpNextSep; + if(rRegion.getB2DPolyPolygon() || getB2DPolyPolygon()) + { + // one of both has a B2DPolyPolygon based region, ensure both have it + // by evtl. conversion + const_cast< Region* >(this)->GetAsB2DPolyPolygon(); + const_cast< Region& >(rRegion).GetAsB2DPolyPolygon(); - // no separation found? -> go to next band! - if ( !pSecondRectBandSep ) - { - // get next band - pSecondRectBand = pSecondRectBand->mpNextBand; + return *rRegion.getB2DPolyPolygon() == *getB2DPolyPolygon(); + } - // get first separation in current band - if( pSecondRectBand ) - pSecondRectBandSep = pSecondRectBand->mpFirstSep; - } + if(rRegion.getPolyPolygon() || getPolyPolygon()) + { + // one of both has a B2DPolyPolygon based region, ensure both have it + // by evtl. conversion + const_cast< Region* >(this)->GetAsPolyPolygon(); + const_cast< Region& >(rRegion).GetAsPolyPolygon(); - if ( pOwnRectBandSep && !pSecondRectBandSep ) - return sal_False; + return *rRegion.getPolyPolygon() == *getPolyPolygon(); + } - if ( !pOwnRectBandSep && pSecondRectBandSep ) - return sal_False; + // both are not empty or null (see above) and if content supported polygon + // data the comparison is already done. Only both on RegionBand base can be left, + // but better check + if(rRegion.getRegionBand() && getRegionBand()) + { + return *rRegion.getRegionBand() == *getRegionBand(); } - return sal_True; + // should not happen, but better deny equality + return false; } -// ----------------------------------------------------------------------- - -enum StreamEntryType { STREAMENTRY_BANDHEADER, STREAMENTRY_SEPARATION, STREAMENTRY_END }; - -SvStream& operator>>( SvStream& rIStrm, Region& rRegion ) +SvStream& operator>>(SvStream& rIStrm, Region& rRegion) { - DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); + VersionCompat aCompat(rIStrm, STREAM_READ); + sal_uInt16 nVersion(0); + sal_uInt16 nTmp16(0); - VersionCompat aCompat( rIStrm, STREAM_READ ); - sal_uInt16 nVersion; - sal_uInt16 nTmp16; - - // statische Object haben RefCount von 0 - if ( rRegion.mpImplRegion->mnRefCount ) - { - if ( rRegion.mpImplRegion->mnRefCount > 1 ) - rRegion.mpImplRegion->mnRefCount--; - else - delete rRegion.mpImplRegion; - } + // clear region to be loaded + rRegion.SetEmpty(); // get version of streamed region rIStrm >> nVersion; @@ -2627,475 +1582,173 @@ SvStream& operator>>( SvStream& rIStrm, Region& rRegion ) // get type of region rIStrm >> nTmp16; + enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX }; RegionType meStreamedType = (RegionType)nTmp16; - switch( meStreamedType ) + switch(meStreamedType) { case REGION_NULL: - rRegion.mpImplRegion = (ImplRegion*)&aImplNullRegion; - break; + { + rRegion.SetNull(); + break; + } case REGION_EMPTY: - rRegion.mpImplRegion = (ImplRegion*)&aImplEmptyRegion; - break; + { + rRegion.SetEmpty(); + break; + } default: { - // create instance of implementation class - rRegion.mpImplRegion = new ImplRegion(); + RegionBand* pNewRegionBand = new RegionBand(); + pNewRegionBand->load(rIStrm); + rRegion.mpRegionBand.reset(pNewRegionBand); - // get header from first element - rIStrm >> nTmp16; - - // get all bands - rRegion.mpImplRegion->mnRectCount = 0; - ImplRegionBand* pCurrBand = NULL; - while ( (StreamEntryType)nTmp16 != STREAMENTRY_END ) - { - // insert new band or new separation? - if ( (StreamEntryType)nTmp16 == STREAMENTRY_BANDHEADER ) - { - long nYTop; - long nYBottom; - - rIStrm >> nYTop; - rIStrm >> nYBottom; - - // create band - ImplRegionBand* pNewBand = new ImplRegionBand( nYTop, nYBottom ); - - // first element? -> set as first into the list - if ( !pCurrBand ) - rRegion.mpImplRegion->mpFirstBand = pNewBand; - else - pCurrBand->mpNextBand = pNewBand; - - // save pointer for next creation - pCurrBand = pNewBand; - } - else - { - long nXLeft; - long nXRight; - - rIStrm >> nXLeft; - rIStrm >> nXRight; - - // add separation - if ( pCurrBand ) - { - pCurrBand->Union( nXLeft, nXRight ); - rRegion.mpImplRegion->mnRectCount++; - } - } - - if( rIStrm.IsEof() ) - { - DBG_ERROR( "premature end of region stream" ); - delete rRegion.mpImplRegion; - rRegion.mpImplRegion = (ImplRegion*)&aImplEmptyRegion; - return rIStrm; - } - - // get next header - rIStrm >> nTmp16; - } - - if( aCompat.GetVersion() >= 2 ) + if(aCompat.GetVersion() >= 2) { - sal_Bool bHasPolyPolygon; + sal_Bool bHasPolyPolygon(sal_False); rIStrm >> bHasPolyPolygon; - if( bHasPolyPolygon ) + if(bHasPolyPolygon) { - delete rRegion.mpImplRegion->mpPolyPoly; - rRegion.mpImplRegion->mpPolyPoly = new PolyPolygon; - rIStrm >> *( rRegion.mpImplRegion->mpPolyPoly ); + PolyPolygon* pNewPoly = new PolyPolygon(); + rIStrm >> *pNewPoly; + rRegion.mpPolyPolygon.reset(pNewPoly); } } + + break; } - break; } return rIStrm; } -// ----------------------------------------------------------------------- - SvStream& operator<<( SvStream& rOStrm, const Region& rRegion ) { - DBG_CHKOBJ( &rRegion, Region, ImplDbgTestRegion ); - - sal_uInt16 nVersion = 2; - VersionCompat aCompat( rOStrm, STREAM_WRITE, nVersion ); - Region aTmpRegion( rRegion ); - - // use tmp region to avoid destruction of internal region (polypolygon) of rRegion - aTmpRegion.ImplPolyPolyRegionToBandRegion(); + const sal_uInt16 nVersion(2); + VersionCompat aCompat(rOStrm, STREAM_WRITE, nVersion); + const RegionBand* pSourceRegionBand = rRegion.GetAsRegionBand(); // put version rOStrm << nVersion; // put type - rOStrm << (sal_uInt16)aTmpRegion.GetType(); - - // put all bands if not null or empty - if ( (aTmpRegion.mpImplRegion != &aImplEmptyRegion) && (aTmpRegion.mpImplRegion != &aImplNullRegion) ) - { - ImplRegionBand* pBand = aTmpRegion.mpImplRegion->mpFirstBand; - while ( pBand ) - { - // put boundaries - rOStrm << (sal_uInt16) STREAMENTRY_BANDHEADER; - rOStrm << pBand->mnYTop; - rOStrm << pBand->mnYBottom; - - // put separations of current band - ImplRegionBandSep* pSep = pBand->mpFirstSep; - while ( pSep ) - { - // put separation - rOStrm << (sal_uInt16) STREAMENTRY_SEPARATION; - rOStrm << pSep->mnXLeft; - rOStrm << pSep->mnXRight; - - // next separation from current band - pSep = pSep->mpNextSep; - } - - pBand = pBand->mpNextBand; - } - - // put endmarker - rOStrm << (sal_uInt16) STREAMENTRY_END; - - // write polypolygon if available - const sal_Bool bHasPolyPolygon = rRegion.HasPolyPolygon(); - rOStrm << bHasPolyPolygon; - - if( bHasPolyPolygon ) - { - // #i105373# - PolyPolygon aNoCurvePolyPolygon; - rRegion.GetPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon); - - rOStrm << aNoCurvePolyPolygon; - } - } - - return rOStrm; -} + enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX }; + RegionType aRegionType(REGION_COMPLEX); + bool bEmpty(rRegion.IsEmpty()); -// ----------------------------------------------------------------------- - -void Region::ImplBeginAddRect() -{ - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - // statische Object haben RefCount von 0 - if ( mpImplRegion->mnRefCount ) + if(!bEmpty && rRegion.getB2DPolyPolygon() && 0 == rRegion.getB2DPolyPolygon()->count()) { - if ( mpImplRegion->mnRefCount > 1 ) - mpImplRegion->mnRefCount--; - else - delete mpImplRegion; + OSL_ENSURE(false, "Region with empty B2DPolyPolygon, should not be created (!)"); + bEmpty = true; } - // create fresh region - mpImplRegion = new ImplRegion(); -} - -// ----------------------------------------------------------------------- - -sal_Bool Region::ImplAddRect( const Rectangle& rRect ) -{ - // Hier kein CheckThis, da nicht alle Daten auf Stand - - if ( rRect.IsEmpty() ) - return sal_True; - - // get justified rectangle - long nTop; - long nBottom; - long nLeft; - long nRight; - if ( rRect.Top() <= rRect.Bottom() ) + if(!bEmpty && rRegion.getPolyPolygon() && 0 == rRegion.getPolyPolygon()->Count()) { - nTop = rRect.Top(); - nBottom = rRect.Bottom(); - } - else - { - nTop = rRect.Bottom(); - nBottom = rRect.Top(); - } - if ( rRect.Left() <= rRect.Right() ) - { - nLeft = rRect.Left(); - nRight = rRect.Right(); - } - else - { - nLeft = rRect.Right(); - nRight = rRect.Left(); + OSL_ENSURE(false, "Region with empty PolyPolygon, should not be created (!)"); + bEmpty = true; } - if ( !mpImplRegion->mpLastCheckedBand ) + if(bEmpty) { - // create new band - mpImplRegion->mpLastCheckedBand = new ImplRegionBand( nTop, nBottom ); - - // set band as current - mpImplRegion->mpFirstBand = mpImplRegion->mpLastCheckedBand; - mpImplRegion->mpLastCheckedBand->Union( nLeft, nRight ); + aRegionType = REGION_EMPTY; } - else + else if(rRegion.IsNull()) { - DBG_ASSERT( nTop >= mpImplRegion->mpLastCheckedBand->mnYTop, - "Region::ImplAddRect() - nTopY < nLastTopY" ); - - // new band? create it! - if ( (nTop != mpImplRegion->mpLastCheckedBand->mnYTop) || - (nBottom != mpImplRegion->mpLastCheckedBand->mnYBottom) ) - { - // create new band - ImplRegionBand* pNewRegionBand = new ImplRegionBand( nTop, nBottom ); - - // append band to the end - mpImplRegion->mpLastCheckedBand->mpNextBand = pNewRegionBand; - - // skip to the new band - mpImplRegion->mpLastCheckedBand = mpImplRegion->mpLastCheckedBand->mpNextBand; - } - - // Insert Sep - mpImplRegion->mpLastCheckedBand->Union( nLeft, nRight ); + aRegionType = REGION_NULL; } - - return sal_True; -} - -// ----------------------------------------------------------------------- - -void Region::ImplEndAddRect() -{ - // check if we are empty - if ( !mpImplRegion->mpFirstBand ) - { - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); - return; - } - - // check if we have somthing to optimize - if ( !mpImplRegion->mpFirstBand->mpNextBand ) + else if(rRegion.getRegionBand() && rRegion.getRegionBand()->isSingleRectangle()) { - // update mpImplRegion->mnRectCount, because no OptimizeBandList is called - ImplRegionBandSep* pSep = mpImplRegion->mpFirstBand->mpFirstSep; - mpImplRegion->mnRectCount = 0; - while( pSep ) - { - mpImplRegion->mnRectCount++; - pSep = pSep->mpNextSep; - } - - // Erst hier testen, da hier die Daten wieder stimmen - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - return; + aRegionType = REGION_RECTANGLE; } - // have to revert list? -> do it now! - if ( mpImplRegion->mpFirstBand->mnYTop > - mpImplRegion->mpFirstBand->mpNextBand->mnYTop ) - { - ImplRegionBand * pNewFirstRegionBand; - - // initialize temp list with first element - pNewFirstRegionBand = mpImplRegion->mpFirstBand; - mpImplRegion->mpFirstBand = mpImplRegion->mpFirstBand->mpNextBand; - pNewFirstRegionBand->mpNextBand = NULL; + rOStrm << (sal_uInt16)aRegionType; - // insert elements to the temp list - while ( mpImplRegion->mpFirstBand ) - { - ImplRegionBand * pSavedRegionBand = pNewFirstRegionBand; - pNewFirstRegionBand = mpImplRegion->mpFirstBand; - mpImplRegion->mpFirstBand = mpImplRegion->mpFirstBand->mpNextBand; - pNewFirstRegionBand->mpNextBand = pSavedRegionBand; - } - - // set temp list as new list - mpImplRegion->mpFirstBand = pNewFirstRegionBand; - } + // get RegionBand + const RegionBand* pRegionBand = rRegion.getRegionBand(); - // cleanup - if ( !mpImplRegion->OptimizeBandList() ) + if(pRegionBand) { - delete mpImplRegion; - mpImplRegion = (ImplRegion*)(&aImplEmptyRegion); + pRegionBand->save(rOStrm); } - // Erst hier testen, da hier die Daten wieder stimmen - DBG_CHKTHIS( Region, ImplDbgTestRegion ); -} - -// ----------------------------------------------------------------------- - -sal_uLong Region::GetRectCount() const -{ - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - ((Region*)this)->ImplPolyPolyRegionToBandRegion(); - -#ifdef DBG_UTIL - sal_uLong nCount = 0; + // write polypolygon if available + const sal_Bool bHasPolyPolygon(rRegion.HasPolyPolygonOrB2DPolyPolygon()); + rOStrm << bHasPolyPolygon; - // all bands if not null or empty - if ( (mpImplRegion != &aImplEmptyRegion) && (mpImplRegion != &aImplNullRegion) ) + if(bHasPolyPolygon) { - ImplRegionBand* pBand = mpImplRegion->mpFirstBand; - while ( pBand ) - { - ImplRegionBandSep* pSep = pBand->mpFirstSep; - while( pSep ) - { - nCount++; - pSep = pSep->mpNextSep; - } + // #i105373# + PolyPolygon aNoCurvePolyPolygon; + rRegion.GetAsPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon); - pBand = pBand->mpNextBand; - } + rOStrm << aNoCurvePolyPolygon; } - DBG_ASSERT( mpImplRegion->mnRectCount == nCount, "Region: invalid mnRectCount!" ); -#endif - - return mpImplRegion->mnRectCount; -} - -// ----------------------------------------------------------------------- - -RegionHandle Region::BeginEnumRects() -{ - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - ImplPolyPolyRegionToBandRegion(); - - // no internal data? -> region is empty! - if ( (mpImplRegion == &aImplEmptyRegion) || (mpImplRegion == &aImplNullRegion) ) - return 0; - - // no band in the list? -> region is empty! - if ( mpImplRegion->mpFirstBand == NULL ) - { - DBG_ASSERT( mpImplRegion->mpFirstBand, "Region::BeginEnumRects() First Band is Empty!" ); - return 0; - } - - ImplRegionHandle* pData = new ImplRegionHandle; - pData->mpRegion = new Region( *this ); - pData->mbFirst = sal_True; - - // save pointers - pData->mpCurrRectBand = pData->mpRegion->mpImplRegion->mpFirstBand; - pData->mpCurrRectBandSep = pData->mpCurrRectBand->mpFirstSep; - - return (RegionHandle)pData; + return rOStrm; } -// ----------------------------------------------------------------------- - -sal_Bool Region::GetEnumRects( RegionHandle pVoidData, Rectangle& rRect ) +void Region::GetRegionRectangles(RectangleVector& rTarget) const { - DBG_CHKTHIS( Region, ImplDbgTestRegion ); + // clear returnvalues + rTarget.clear(); - ImplRegionHandle* pData = (ImplRegionHandle*)pVoidData; - if ( !pData ) - return sal_False; + // ensure RegionBand existance + const_cast< Region* >(this)->GetAsRegionBand(); + const RegionBand* pRegionBand = getRegionBand(); - if ( pData->mbFirst ) - pData->mbFirst = sal_False; - else + if(pRegionBand) { - // get next separation from current band - pData->mpCurrRectBandSep = pData->mpCurrRectBandSep->mpNextSep; - - // no separation found? -> go to next band! - if ( !pData->mpCurrRectBandSep ) - { - // get next band - pData->mpCurrRectBand = pData->mpCurrRectBand->mpNextBand; - - // no band found? -> not further rectangles! - if ( !pData->mpCurrRectBand ) - return sal_False; - - // get first separation in current band - pData->mpCurrRectBandSep = pData->mpCurrRectBand->mpFirstSep; - } + pRegionBand->GetRegionRectangles(rTarget); } - - // get boundaries of current rectangle - rRect.Top() = pData->mpCurrRectBand->mnYTop; - rRect.Bottom() = pData->mpCurrRectBand->mnYBottom; - rRect.Left() = pData->mpCurrRectBandSep->mnXLeft; - rRect.Right() = pData->mpCurrRectBandSep->mnXRight; - return sal_True; -} - -// ----------------------------------------------------------------------- - -void Region::EndEnumRects( RegionHandle pVoidData ) -{ - DBG_CHKTHIS( Region, ImplDbgTestRegion ); - - ImplRegionHandle* pData = (ImplRegionHandle*)pVoidData; - if ( !pData ) - return; - - // cleanup - delete pData->mpRegion; - delete pData; } -// ----------------------------------------------------------------------- - static inline bool ImplPolygonRectTest( const Polygon& rPoly, Rectangle* pRectOut = NULL ) { bool bIsRect = false; const Point* pPoints = rPoly.GetConstPointAry(); sal_uInt16 nPoints = rPoly.GetSize(); + if( nPoints == 4 || (nPoints == 5 && pPoints[0] == pPoints[4]) ) { - long nX1 = pPoints[0].X(), nX2 = pPoints[2].X(), - nY1 = pPoints[0].Y(), nY2 = pPoints[2].Y(); - if( ( (pPoints[1].X() == nX1 && pPoints[3].X() == nX2) && - (pPoints[1].Y() == nY2 && pPoints[3].Y() == nY1) ) - || - ( (pPoints[1].X() == nX2 && pPoints[3].X() == nX1) && - (pPoints[1].Y() == nY1 && pPoints[3].Y() == nY2) ) ) + long nX1 = pPoints[0].X(), nX2 = pPoints[2].X(), nY1 = pPoints[0].Y(), nY2 = pPoints[2].Y(); + + if( ( (pPoints[1].X() == nX1 && pPoints[3].X() == nX2) && (pPoints[1].Y() == nY2 && pPoints[3].Y() == nY1) ) + || ( (pPoints[1].X() == nX2 && pPoints[3].X() == nX1) && (pPoints[1].Y() == nY1 && pPoints[3].Y() == nY2) ) ) { bIsRect = true; + if( pRectOut ) { long nSwap; + if( nX2 < nX1 ) { nSwap = nX2; nX2 = nX1; nX1 = nSwap; } + if( nY2 < nY1 ) { nSwap = nY2; nY2 = nY1; nY1 = nSwap; } + if( nX2 != nX1 ) + { nX2--; + } + if( nY2 != nY1 ) + { nY2--; + } + pRectOut->Left() = nX1; pRectOut->Right() = nX2; pRectOut->Top() = nY1; @@ -3103,6 +1756,7 @@ static inline bool ImplPolygonRectTest( const Polygon& rPoly, Rectangle* pRectOu } } } + return bIsRect; } @@ -3112,30 +1766,48 @@ Region Region::GetRegionFromPolyPolygon( const PolyPolygon& rPolyPoly ) // check if it's worth extracting the XOr'ing the Rectangles // empiricism shows that break even between XOr'ing rectangles separately - // and ImplPolyPolyRegionToBandRegion is at half rectangles/half polygons + // and ImplCreateRegionBandFromPolyPolygon is at half rectangles/half polygons int nPolygonRects = 0, nPolygonPolygons = 0; int nPolygons = rPolyPoly.Count(); for( sal_uInt16 i = 0; i < nPolygons; i++ ) { const Polygon& rPoly = rPolyPoly[i]; + if( ImplPolygonRectTest( rPoly ) ) + { nPolygonRects++; + } else + { nPolygonPolygons++; + } } + if( nPolygonPolygons > nPolygonRects ) + { return Region( rPolyPoly ); + } Region aResult; Rectangle aRect; + for( sal_uInt16 i = 0; i < nPolygons; i++ ) { const Polygon& rPoly = rPolyPoly[i]; + if( ImplPolygonRectTest( rPoly, &aRect ) ) + { aResult.XOr( aRect ); + } else + { aResult.XOr( Region(rPoly) ); + } } + return aResult; } + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/vcl/source/gdi/regionband.cxx b/vcl/source/gdi/regionband.cxx new file mode 100755 index 000000000000..1375d73a8166 --- /dev/null +++ b/vcl/source/gdi/regionband.cxx @@ -0,0 +1,1384 @@ +/************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + *************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <tools/stream.hxx> +#include <tools/debug.hxx> +#include <regionband.hxx> + +////////////////////////////////////////////////////////////////////////////// + +DBG_NAME( RegionBand ) +DBG_NAMEEX( Polygon ) +DBG_NAMEEX( PolyPolygon ) + +////////////////////////////////////////////////////////////////////////////// + +RegionBand::RegionBand() +: mpFirstBand(0), + mpLastCheckedBand(0) +{ + DBG_CTOR(RegionBand, ImplDbgTestRegionBand); +} + +RegionBand::RegionBand(const RegionBand& rRef) +: mpFirstBand(0), + mpLastCheckedBand(0) +{ + *this = rRef; + DBG_CTOR(RegionBand, ImplDbgTestRegionBand); +} + +RegionBand& RegionBand::operator=(const RegionBand& rRef) +{ + ImplRegionBand* pPrevBand = 0; + ImplRegionBand* pBand = rRef.mpFirstBand; + + while(pBand) + { + ImplRegionBand* pNewBand = new ImplRegionBand(*pBand); + + // first element? -> set as first into the list + if(pBand == rRef.mpFirstBand) + { + mpFirstBand = pNewBand; + } + else + { + pPrevBand->mpNextBand = pNewBand; + } + + pPrevBand = pNewBand; + pBand = pBand->mpNextBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + DBG_CHKOBJ(&rRef, RegionBand, ImplDbgTestRegionBand); + + return *this; +} + +RegionBand::RegionBand(const Rectangle& rRect) +: mpFirstBand(0), + mpLastCheckedBand(0) +{ + const long nTop(std::min(rRect.Top(), rRect.Bottom())); + const long nBottom(std::max(rRect.Top(), rRect.Bottom())); + const long nLeft(std::min(rRect.Left(), rRect.Right())); + const long nRight(std::max(rRect.Left(), rRect.Right())); + + // add band with boundaries of the rectangle + mpFirstBand = new ImplRegionBand(nTop, nBottom); + + // Set left and right boundaries of the band + mpFirstBand->Union(nLeft, nRight); + + DBG_CTOR(RegionBand, ImplDbgTestRegionBand); +} + +void RegionBand::implReset() +{ + ImplRegionBand* pBand = mpFirstBand; + + while(pBand) + { + ImplRegionBand* pTempBand = pBand->mpNextBand; + delete pBand; + pBand = pTempBand; + } + + mpLastCheckedBand = 0; + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +RegionBand::~RegionBand() +{ + implReset(); + DBG_DTOR(RegionBand, ImplDbgTestRegionBand); +} + +bool RegionBand::operator==( const RegionBand& rRegionBand ) const +{ + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + DBG_CHKOBJ(&rRegionBand, RegionBand, ImplDbgTestRegionBand); + + // initialise pointers + ImplRegionBand* pOwnRectBand = mpFirstBand; + ImplRegionBandSep* pOwnRectBandSep = pOwnRectBand->mpFirstSep; + ImplRegionBand* pSecondRectBand = rRegionBand.mpFirstBand; + ImplRegionBandSep* pSecondRectBandSep = pSecondRectBand->mpFirstSep; + + while ( pOwnRectBandSep && pSecondRectBandSep ) + { + // get boundaries of current rectangle + long nOwnXLeft = pOwnRectBandSep->mnXLeft; + long nSecondXLeft = pSecondRectBandSep->mnXLeft; + + if ( nOwnXLeft != nSecondXLeft ) + { + return false; + } + + long nOwnYTop = pOwnRectBand->mnYTop; + long nSecondYTop = pSecondRectBand->mnYTop; + + if ( nOwnYTop != nSecondYTop ) + { + return false; + } + + long nOwnXRight = pOwnRectBandSep->mnXRight; + long nSecondXRight = pSecondRectBandSep->mnXRight; + + if ( nOwnXRight != nSecondXRight ) + { + return false; + } + + long nOwnYBottom = pOwnRectBand->mnYBottom; + long nSecondYBottom = pSecondRectBand->mnYBottom; + + if ( nOwnYBottom != nSecondYBottom ) + { + return false; + } + + // get next separation from current band + pOwnRectBandSep = pOwnRectBandSep->mpNextSep; + + // no separation found? -> go to next band! + if ( !pOwnRectBandSep ) + { + // get next band + pOwnRectBand = pOwnRectBand->mpNextBand; + + // get first separation in current band + if( pOwnRectBand ) + { + pOwnRectBandSep = pOwnRectBand->mpFirstSep; + } + } + + // get next separation from current band + pSecondRectBandSep = pSecondRectBandSep->mpNextSep; + + // no separation found? -> go to next band! + if ( !pSecondRectBandSep ) + { + // get next band + pSecondRectBand = pSecondRectBand->mpNextBand; + + // get first separation in current band + if( pSecondRectBand ) + { + pSecondRectBandSep = pSecondRectBand->mpFirstSep; + } + } + + if ( pOwnRectBandSep && !pSecondRectBandSep ) + { + return false; + } + + if ( !pOwnRectBandSep && pSecondRectBandSep ) + { + return false; + } + } + + return true; +} + +enum StreamEntryType { STREAMENTRY_BANDHEADER, STREAMENTRY_SEPARATION, STREAMENTRY_END }; + +void RegionBand::load(SvStream& rIStrm) +{ + // clear this nstance's data + implReset(); + + // get all bands + ImplRegionBand* pCurrBand = 0; + + // get header from first element + sal_uInt16 nTmp16(0); + rIStrm >> nTmp16; + + while(STREAMENTRY_END != (StreamEntryType)nTmp16) + { + // insert new band or new separation? + if(STREAMENTRY_BANDHEADER == (StreamEntryType)nTmp16) + { + long nYTop; + long nYBottom; + + rIStrm >> nYTop; + rIStrm >> nYBottom; + + // create band + ImplRegionBand* pNewBand = new ImplRegionBand( nYTop, nYBottom ); + + // first element? -> set as first into the list + if ( !pCurrBand ) + { + mpFirstBand = pNewBand; + } + else + { + pCurrBand->mpNextBand = pNewBand; + } + + // save pointer for next creation + pCurrBand = pNewBand; + } + else + { + long nXLeft; + long nXRight; + + rIStrm >> nXLeft; + rIStrm >> nXRight; + + // add separation + if ( pCurrBand ) + { + pCurrBand->Union( nXLeft, nXRight ); + } + } + + if( rIStrm.IsEof() ) + { + DBG_ERROR( "premature end of region stream" ); + implReset(); + return; + } + + // get next header + rIStrm >> nTmp16; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +void RegionBand::save(SvStream& rOStrm) const +{ + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + ImplRegionBand* pBand = mpFirstBand; + + while(pBand) + { + // put boundaries + rOStrm << (sal_uInt16)STREAMENTRY_BANDHEADER; + rOStrm << pBand->mnYTop; + rOStrm << pBand->mnYBottom; + + // put separations of current band + ImplRegionBandSep* pSep = pBand->mpFirstSep; + + while(pSep) + { + // put separation + rOStrm << (sal_uInt16)STREAMENTRY_SEPARATION; + rOStrm << pSep->mnXLeft; + rOStrm << pSep->mnXRight; + + // next separation from current band + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } + + // put endmarker + rOStrm << (sal_uInt16)STREAMENTRY_END; +} + +bool RegionBand::isSingleRectangle() const +{ + // just one band? + if(mpFirstBand && !mpFirstBand->mpNextBand) + { + // just one sep? + if(mpFirstBand->mpFirstSep && !mpFirstBand->mpFirstSep->mpNextSep) + { + return true; + } + } + + return false; +} + +void RegionBand::InsertBand(ImplRegionBand* pPreviousBand, ImplRegionBand* pBandToInsert) +{ + OSL_ASSERT(pBandToInsert!=NULL); + + if(!pPreviousBand) + { + // Insert band before all others. + if(mpFirstBand) + { + mpFirstBand->mpPrevBand = pBandToInsert; + } + + pBandToInsert->mpNextBand = mpFirstBand; + mpFirstBand = pBandToInsert; + } + else + { + // Insert band directly after pPreviousBand. + pBandToInsert->mpNextBand = pPreviousBand->mpNextBand; + pPreviousBand->mpNextBand = pBandToInsert; + pBandToInsert->mpPrevBand = pPreviousBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +void RegionBand::processPoints() +{ + ImplRegionBand* pRegionBand = mpFirstBand; + + while(pRegionBand) + { + // generate separations from the lines and process union + pRegionBand->ProcessPoints(); + pRegionBand = pRegionBand->mpNextBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +/** This function is similar to the RegionBand::InsertBands() method. + It creates a minimal set of missing bands so that the entire vertical + interval from nTop to nBottom is covered by bands. +*/ +void RegionBand::ImplAddMissingBands(const long nTop, const long nBottom) +{ + // Iterate over already existing bands and add missing bands atop the + // first and between two bands. + ImplRegionBand* pPreviousBand = NULL; + ImplRegionBand* pBand = ImplGetFirstRegionBand(); + long nCurrentTop (nTop); + + while (pBand != NULL && nCurrentTop<nBottom) + { + if (nCurrentTop < pBand->mnYTop) + { + // Create new band above the current band. + ImplRegionBand* pAboveBand = new ImplRegionBand( + nCurrentTop, + ::std::min(nBottom,pBand->mnYTop-1)); + InsertBand(pPreviousBand, pAboveBand); + } + + // Adapt the top of the interval to prevent overlapping bands. + nCurrentTop = ::std::max(nTop, pBand->mnYBottom+1); + + // Advance to next band. + pPreviousBand = pBand; + pBand = pBand->mpNextBand; + } + + // We still have to cover two cases: + // 1. The region does not yet contain any bands. + // 2. The intervall nTop->nBottom extends past the bottom most band. + if (nCurrentTop <= nBottom + && (pBand==NULL || nBottom>pBand->mnYBottom)) + { + // When there is no previous band then the new one will be the + // first. Otherwise the new band is inserted behind the last band. + InsertBand( + pPreviousBand, + new ImplRegionBand( + nCurrentTop, + nBottom)); + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +void RegionBand::CreateBandRange(long nYTop, long nYBottom) +{ + // add top band + mpFirstBand = new ImplRegionBand( nYTop-1, nYTop-1 ); + + // begin first search from the first element + mpLastCheckedBand = mpFirstBand; + ImplRegionBand* pBand = mpFirstBand; + + for ( int i = nYTop; i <= nYBottom+1; i++ ) + { + // create new band + ImplRegionBand* pNewBand = new ImplRegionBand( i, i ); + pBand->mpNextBand = pNewBand; + + if ( pBand != mpFirstBand ) + { + pNewBand->mpPrevBand = pBand; + } + + pBand = pBand->mpNextBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +bool RegionBand::InsertLine(const Point& rStartPt, const Point& rEndPt, long nLineId) +{ + long nX, nY; + + // lines consisting of a single point do not interest here + if ( rStartPt == rEndPt ) + { + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return true; + } + + LineType eLineType = (rStartPt.Y() > rEndPt.Y()) ? LINE_DESCENDING : LINE_ASCENDING; + if ( rStartPt.X() == rEndPt.X() ) + { + // vertical line + const long nEndY = rEndPt.Y(); + + nX = rStartPt.X(); + nY = rStartPt.Y(); + + if( nEndY > nY ) + { + for ( ; nY <= nEndY; nY++ ) + { + Point aNewPoint( nX, nY ); + InsertPoint( aNewPoint, nLineId, + (aNewPoint == rEndPt) || (aNewPoint == rStartPt), + eLineType ); + } + } + else + { + for ( ; nY >= nEndY; nY-- ) + { + Point aNewPoint( nX, nY ); + InsertPoint( aNewPoint, nLineId, + (aNewPoint == rEndPt) || (aNewPoint == rStartPt), + eLineType ); + } + } + } + else if ( rStartPt.Y() != rEndPt.Y() ) + { + const long nDX = labs( rEndPt.X() - rStartPt.X() ); + const long nDY = labs( rEndPt.Y() - rStartPt.Y() ); + const long nStartX = rStartPt.X(); + const long nStartY = rStartPt.Y(); + const long nEndX = rEndPt.X(); + const long nEndY = rEndPt.Y(); + const long nXInc = ( nStartX < nEndX ) ? 1L : -1L; + const long nYInc = ( nStartY < nEndY ) ? 1L : -1L; + + if ( nDX >= nDY ) + { + const long nDYX = ( nDY - nDX ) << 1; + const long nDY2 = nDY << 1; + long nD = nDY2 - nDX; + + for ( nX = nStartX, nY = nStartY; nX != nEndX; nX += nXInc ) + { + InsertPoint( Point( nX, nY ), nLineId, nStartX == nX, eLineType ); + + if ( nD < 0L ) + nD += nDY2; + else + nD += nDYX, nY += nYInc; + } + } + else + { + const long nDYX = ( nDX - nDY ) << 1; + const long nDY2 = nDX << 1; + long nD = nDY2 - nDY; + + for ( nX = nStartX, nY = nStartY; nY != nEndY; nY += nYInc ) + { + InsertPoint( Point( nX, nY ), nLineId, nStartY == nY, eLineType ); + + if ( nD < 0L ) + nD += nDY2; + else + nD += nDYX, nX += nXInc; + } + } + + // last point + InsertPoint( Point( nEndX, nEndY ), nLineId, true, eLineType ); + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return true; +} + +bool RegionBand::InsertPoint(const Point &rPoint, long nLineID, bool bEndPoint, LineType eLineType) +{ + DBG_ASSERT( mpFirstBand != NULL, "RegionBand::InsertPoint - no bands available!" ); + + if ( rPoint.Y() == mpLastCheckedBand->mnYTop ) + { + mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType ); + return true; + } + + if ( rPoint.Y() > mpLastCheckedBand->mnYTop ) + { + // Search ascending + while ( mpLastCheckedBand ) + { + // Insert point if possible + if ( rPoint.Y() == mpLastCheckedBand->mnYTop ) + { + mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType ); + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return true; + } + + mpLastCheckedBand = mpLastCheckedBand->mpNextBand; + } + + DBG_ERROR( "RegionBand::InsertPoint reached the end of the list!" ); + } + else + { + // Search descending + while ( mpLastCheckedBand ) + { + // Insert point if possible + if ( rPoint.Y() == mpLastCheckedBand->mnYTop ) + { + mpLastCheckedBand->InsertPoint( rPoint.X(), nLineID, bEndPoint, eLineType ); + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return true; + } + + mpLastCheckedBand = mpLastCheckedBand->mpPrevBand; + } + + DBG_ERROR( "RegionBand::InsertPoint reached the beginning of the list!" ); + } + + DBG_ERROR( "RegionBand::InsertPoint point not inserted!" ); + + // reinitialize pointer (should never be reached!) + mpLastCheckedBand = mpFirstBand; + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return false; +} + +bool RegionBand::OptimizeBandList() +{ + ImplRegionBand* pPrevBand = 0; + ImplRegionBand* pBand = mpFirstBand; + + while ( pBand ) + { + const bool bBTEqual = pBand->mpNextBand && (pBand->mnYBottom == pBand->mpNextBand->mnYTop); + + // no separation? -> remove! + if ( pBand->IsEmpty() || (bBTEqual && (pBand->mnYBottom == pBand->mnYTop)) ) + { + // save pointer + ImplRegionBand* pOldBand = pBand; + + // previous element of the list + if ( pBand == mpFirstBand ) + mpFirstBand = pBand->mpNextBand; + else + pPrevBand->mpNextBand = pBand->mpNextBand; + + pBand = pBand->mpNextBand; + delete pOldBand; + } + else + { + // fixup + if ( bBTEqual ) + pBand->mnYBottom = pBand->mpNextBand->mnYTop-1; + + // this and next band with equal separations? -> combine! + if ( pBand->mpNextBand && + ((pBand->mnYBottom+1) == pBand->mpNextBand->mnYTop) && + (*pBand == *pBand->mpNextBand) ) + { + // expand current height + pBand->mnYBottom = pBand->mpNextBand->mnYBottom; + + // remove next band from list + ImplRegionBand* pDeletedBand = pBand->mpNextBand; + pBand->mpNextBand = pDeletedBand->mpNextBand; + delete pDeletedBand; + + // check band again! + } + else + { + // count rectangles within band + ImplRegionBandSep* pSep = pBand->mpFirstSep; + while ( pSep ) + { + pSep = pSep->mpNextSep; + } + + pPrevBand = pBand; + pBand = pBand->mpNextBand; + } + } + } + +#ifdef DBG_UTIL + pBand = mpFirstBand; + while ( pBand ) + { + DBG_ASSERT( pBand->mpFirstSep != NULL, "Exiting RegionBand::OptimizeBandList(): empty band in region!" ); + + if ( pBand->mnYBottom < pBand->mnYTop ) + DBG_ERROR( "RegionBand::OptimizeBandList(): YBottomBoundary < YTopBoundary" ); + + if ( pBand->mpNextBand ) + { + if ( pBand->mnYBottom >= pBand->mpNextBand->mnYTop ) + DBG_ERROR( "RegionBand::OptimizeBandList(): overlapping bands in region!" ); + } + + pBand = pBand->mpNextBand; + } +#endif + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return (0 != mpFirstBand); +} + +void RegionBand::Move(long nHorzMove, long nVertMove) +{ + ImplRegionBand* pBand = mpFirstBand; + + while(pBand) + { + // process the vertical move + if(nVertMove) + { + pBand->mnYTop = pBand->mnYTop + nVertMove; + pBand->mnYBottom = pBand->mnYBottom + nVertMove; + } + + // process the horizontal move + if(nHorzMove) + { + pBand->MoveX(nHorzMove); + } + + pBand = pBand->mpNextBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +void RegionBand::Scale(double fScaleX, double fScaleY) +{ + ImplRegionBand* pBand = mpFirstBand; + + while(pBand) + { + // process the vertical move + if(0.0 != fScaleY) + { + pBand->mnYTop = basegfx::fround(pBand->mnYTop * fScaleY); + pBand->mnYBottom = basegfx::fround(pBand->mnYBottom * fScaleY); + } + + // process the horizontal move + if(0.0 != fScaleX) + { + pBand->ScaleX(fScaleX); + } + + pBand = pBand->mpNextBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +void RegionBand::InsertBands(long nTop, long nBottom) +{ + // region empty? -> set rectagle as first entry! + if ( !mpFirstBand ) + { + // add band with boundaries of the rectangle + mpFirstBand = new ImplRegionBand( nTop, nBottom ); + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return; + } + + // find/insert bands for the boundaries of the rectangle + bool bTopBoundaryInserted = false; + bool bTop2BoundaryInserted = false; + bool bBottomBoundaryInserted = false; + + // special case: top boundary is above the first band + ImplRegionBand* pNewBand; + + if ( nTop < mpFirstBand->mnYTop ) + { + // create new band above the first in the list + pNewBand = new ImplRegionBand( nTop, mpFirstBand->mnYTop ); + + if ( nBottom < mpFirstBand->mnYTop ) + { + pNewBand->mnYBottom = nBottom; + } + + // insert band into the list + pNewBand->mpNextBand = mpFirstBand; + mpFirstBand = pNewBand; + + bTopBoundaryInserted = true; + } + + // insert band(s) into the list + ImplRegionBand* pBand = mpFirstBand; + + while ( pBand ) + { + // Insert Bands if possible + if ( !bTopBoundaryInserted ) + { + bTopBoundaryInserted = InsertSingleBand( pBand, nTop - 1 ); + } + + if ( !bTop2BoundaryInserted ) + { + bTop2BoundaryInserted = InsertSingleBand( pBand, nTop ); + } + + if ( !bBottomBoundaryInserted && (nTop != nBottom) ) + { + bBottomBoundaryInserted = InsertSingleBand( pBand, nBottom ); + } + + // both boundaries inserted? -> nothing more to do + if ( bTopBoundaryInserted && bTop2BoundaryInserted && bBottomBoundaryInserted ) + { + break; + } + + // insert bands between two bands if neccessary + if ( pBand->mpNextBand ) + { + if ( (pBand->mnYBottom + 1) < pBand->mpNextBand->mnYTop ) + { + // copy band with list and set new boundary + pNewBand = new ImplRegionBand( pBand->mnYBottom+1, pBand->mpNextBand->mnYTop-1 ); + + // insert band into the list + pNewBand->mpNextBand = pBand->mpNextBand; + pBand->mpNextBand = pNewBand; + } + } + + pBand = pBand->mpNextBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +bool RegionBand::InsertSingleBand(ImplRegionBand* pBand, long nYBandPosition) +{ + // boundary already included in band with height 1? -> nothing to do! + if ( (pBand->mnYTop == pBand->mnYBottom) && (nYBandPosition == pBand->mnYTop) ) + { + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return true; + } + + // insert single height band on top? + ImplRegionBand* pNewBand; + + if ( nYBandPosition == pBand->mnYTop ) + { + // copy band with list and set new boundary + pNewBand = new ImplRegionBand( *pBand ); + pNewBand->mnYTop = nYBandPosition+1; + + // insert band into the list + pNewBand->mpNextBand = pBand->mpNextBand; + pBand->mnYBottom = nYBandPosition; + pBand->mpNextBand = pNewBand; + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return true; + } + + // top of new rectangle within the current band? -> insert new band and copy data + if ( (nYBandPosition > pBand->mnYTop) && (nYBandPosition < pBand->mnYBottom) ) + { + // copy band with list and set new boundary + pNewBand = new ImplRegionBand( *pBand ); + pNewBand->mnYTop = nYBandPosition; + + // insert band into the list + pNewBand->mpNextBand = pBand->mpNextBand; + pBand->mnYBottom = nYBandPosition; + pBand->mpNextBand = pNewBand; + + // copy band with list and set new boundary + pNewBand = new ImplRegionBand( *pBand ); + pNewBand->mnYTop = nYBandPosition; + + // insert band into the list + pBand->mpNextBand->mnYTop = nYBandPosition+1; + + pNewBand->mpNextBand = pBand->mpNextBand; + pBand->mnYBottom = nYBandPosition - 1; + pBand->mpNextBand = pNewBand; + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return true; + } + + // create new band behind the current in the list + if ( !pBand->mpNextBand ) + { + if ( nYBandPosition == pBand->mnYBottom ) + { + // copy band with list and set new boundary + pNewBand = new ImplRegionBand( *pBand ); + pNewBand->mnYTop = pBand->mnYBottom; + pNewBand->mnYBottom = nYBandPosition; + + pBand->mnYBottom = nYBandPosition-1; + + // append band to the list + pBand->mpNextBand = pNewBand; + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return true; + } + + if ( nYBandPosition > pBand->mnYBottom ) + { + // create new band + pNewBand = new ImplRegionBand( pBand->mnYBottom + 1, nYBandPosition ); + + // append band to the list + pBand->mpNextBand = pNewBand; + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return true; + } + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return false; +} + +void RegionBand::Union(long nLeft, long nTop, long nRight, long nBottom) +{ + DBG_ASSERT( nLeft <= nRight, "RegionBand::Union() - nLeft > nRight" ); + DBG_ASSERT( nTop <= nBottom, "RegionBand::Union() - nTop > nBottom" ); + + // process union + ImplRegionBand* pBand = mpFirstBand; + while ( pBand ) + { + if ( pBand->mnYTop >= nTop ) + { + if ( pBand->mnYBottom <= nBottom ) + pBand->Union( nLeft, nRight ); + else + { +#ifdef DBG_UTIL + long nCurY = pBand->mnYBottom; + pBand = pBand->mpNextBand; + while ( pBand ) + { + if ( (pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY) ) + { + DBG_ERROR( "RegionBand::Union() - Bands not sorted!" ); + } + pBand = pBand->mpNextBand; + } +#endif + break; + } + } + + pBand = pBand->mpNextBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +void RegionBand::Intersect(long nLeft, long nTop, long nRight, long nBottom) +{ + // process intersections + ImplRegionBand* pPrevBand = 0; + ImplRegionBand* pBand = mpFirstBand; + + while(pBand) + { + // band within intersection boundary? -> process. otherwise remove + if((pBand->mnYTop >= nTop) && (pBand->mnYBottom <= nBottom)) + { + // process intersection + pBand->Intersect(nLeft, nRight); + pPrevBand = pBand; + pBand = pBand->mpNextBand; + } + else + { + ImplRegionBand* pOldBand = pBand; + + if(pBand == mpFirstBand) + { + mpFirstBand = pBand->mpNextBand; + } + else + { + pPrevBand->mpNextBand = pBand->mpNextBand; + } + + pBand = pBand->mpNextBand; + delete pOldBand; + } + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +void RegionBand::Union(const RegionBand& rSource) +{ + // apply all rectangles from rSource to this + ImplRegionBand* pBand = rSource.mpFirstBand; + + while ( pBand ) + { + // insert bands if the boundaries are not allready in the list + InsertBands(pBand->mnYTop, pBand->mnYBottom); + + // process all elements of the list + ImplRegionBandSep* pSep = pBand->mpFirstSep; + + while(pSep) + { + Union(pSep->mnXLeft, pBand->mnYTop, pSep->mnXRight, pBand->mnYBottom); + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +void RegionBand::Exclude(long nLeft, long nTop, long nRight, long nBottom) +{ + DBG_ASSERT( nLeft <= nRight, "RegionBand::Exclude() - nLeft > nRight" ); + DBG_ASSERT( nTop <= nBottom, "RegionBand::Exclude() - nTop > nBottom" ); + + // process exclude + ImplRegionBand* pBand = mpFirstBand; + + while(pBand) + { + if(pBand->mnYTop >= nTop) + { + if(pBand->mnYBottom <= nBottom) + { + pBand->Exclude(nLeft, nRight); + } + else + { +#ifdef DBG_UTIL + long nCurY = pBand->mnYBottom; + pBand = pBand->mpNextBand; + + while(pBand) + { + if((pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY)) + { + DBG_ERROR( "RegionBand::Exclude() - Bands not sorted!" ); + } + + pBand = pBand->mpNextBand; + } +#endif + break; + } + } + + pBand = pBand->mpNextBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +void RegionBand::XOr(long nLeft, long nTop, long nRight, long nBottom) +{ + DBG_ASSERT( nLeft <= nRight, "RegionBand::Exclude() - nLeft > nRight" ); + DBG_ASSERT( nTop <= nBottom, "RegionBand::Exclude() - nTop > nBottom" ); + + // process xor + ImplRegionBand* pBand = mpFirstBand; + + while(pBand) + { + if(pBand->mnYTop >= nTop) + { + if(pBand->mnYBottom <= nBottom) + { + pBand->XOr(nLeft, nRight); + } + else + { +#ifdef DBG_UTIL + long nCurY = pBand->mnYBottom; + pBand = pBand->mpNextBand; + + while(pBand) + { + if((pBand->mnYTop < nCurY) || (pBand->mnYBottom < nCurY)) + { + DBG_ERROR( "RegionBand::XOr() - Bands not sorted!" ); + } + + pBand = pBand->mpNextBand; + } +#endif + break; + } + } + + pBand = pBand->mpNextBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +void RegionBand::Intersect(const RegionBand& rSource) +{ + // mark all bands as untouched + ImplRegionBand* pBand = mpFirstBand; + + while ( pBand ) + { + pBand->mbTouched = false; + pBand = pBand->mpNextBand; + } + + pBand = rSource.mpFirstBand; + + while ( pBand ) + { + // insert bands if the boundaries are not allready in the list + InsertBands( pBand->mnYTop, pBand->mnYBottom ); + + // process all elements of the list + ImplRegionBandSep* pSep = pBand->mpFirstSep; + + while ( pSep ) + { + // left boundary? + if ( pSep == pBand->mpFirstSep ) + { + // process intersection and do not remove untouched bands + Exclude( LONG_MIN+1, pBand->mnYTop, pSep->mnXLeft-1, pBand->mnYBottom ); + } + + // right boundary? + if ( pSep->mpNextSep == NULL ) + { + // process intersection and do not remove untouched bands + Exclude( pSep->mnXRight+1, pBand->mnYTop, LONG_MAX-1, pBand->mnYBottom ); + } + else + { + // process intersection and do not remove untouched bands + Exclude( pSep->mnXRight+1, pBand->mnYTop, pSep->mpNextSep->mnXLeft-1, pBand->mnYBottom ); + } + + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } + + // remove all untouched bands if bands allready left + ImplRegionBand* pPrevBand = 0; + pBand = mpFirstBand; + + while ( pBand ) + { + if ( !pBand->mbTouched ) + { + // save pointer + ImplRegionBand* pOldBand = pBand; + + // previous element of the list + if ( pBand == mpFirstBand ) + { + mpFirstBand = pBand->mpNextBand; + } + else + { + pPrevBand->mpNextBand = pBand->mpNextBand; + } + + pBand = pBand->mpNextBand; + delete pOldBand; + } + else + { + pPrevBand = pBand; + pBand = pBand->mpNextBand; + } + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); +} + +bool RegionBand::Exclude(const RegionBand& rSource) +{ + // Alle Rechtecke aus der uebergebenen Region auf diese Region anwenden + ImplRegionBand* pBand = rSource.mpFirstBand; + + while ( pBand ) + { + // insert bands if the boundaries are not allready in the list + InsertBands( pBand->mnYTop, pBand->mnYBottom ); + + // process all elements of the list + ImplRegionBandSep* pSep = pBand->mpFirstSep; + + while ( pSep ) + { + Exclude( pSep->mnXLeft, pBand->mnYTop, pSep->mnXRight, pBand->mnYBottom ); + pSep = pSep->mpNextSep; + } + + // to test less bands, already check in the loop + if ( !OptimizeBandList() ) + { + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return false; + } + + pBand = pBand->mpNextBand; + } + + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + return true; +} + +Rectangle RegionBand::GetBoundRect() const +{ + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + + // get the boundaries of the first band + long nYTop(mpFirstBand->mnYTop); + long nYBottom(mpFirstBand->mnYBottom); + long nXLeft(mpFirstBand->GetXLeftBoundary()); + long nXRight(mpFirstBand->GetXRightBoundary()); + + // look in the band list (don't test first band again!) + ImplRegionBand* pBand = mpFirstBand->mpNextBand; + + while ( pBand ) + { + nYBottom = pBand->mnYBottom; + nXLeft = std::min( nXLeft, pBand->GetXLeftBoundary() ); + nXRight = std::max( nXRight, pBand->GetXRightBoundary() ); + + pBand = pBand->mpNextBand; + } + + return Rectangle( nXLeft, nYTop, nXRight, nYBottom ); +} + +void RegionBand::XOr(const RegionBand& rSource) +{ + ImplRegionBand* pBand = rSource.mpFirstBand; + + while ( pBand ) + { + // insert bands if the boundaries are not allready in the list + InsertBands( pBand->mnYTop, pBand->mnYBottom ); + + // process all elements of the list + ImplRegionBandSep* pSep = pBand->mpFirstSep; + + while ( pSep ) + { + XOr( pSep->mnXLeft, pBand->mnYTop, pSep->mnXRight, pBand->mnYBottom ); + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } +} + +bool RegionBand::IsInside(const Point& rPoint) const +{ + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + + // search band list + ImplRegionBand* pBand = mpFirstBand; + + while(pBand) + { + // is point within band? + if((pBand->mnYTop <= rPoint.Y()) && (pBand->mnYBottom >= rPoint.Y())) + { + // is point within separation of the band? + DBG_CHKTHIS(RegionBand, ImplDbgTestRegionBand); + if(pBand->IsInside(rPoint.X())) + { + return true; + } + else + { + return false; + } + } + + pBand = pBand->mpNextBand; + } + + return false; +} + +void RegionBand::GetRegionRectangles(RectangleVector& rTarget) const +{ + // clear result vector + rTarget.clear(); + ImplRegionBand* mpCurrRectBand = mpFirstBand; + Rectangle aRectangle; + + while(mpCurrRectBand) + { + ImplRegionBandSep* mpCurrRectBandSep = mpCurrRectBand->mpFirstSep; + + aRectangle.Top() = mpCurrRectBand->mnYTop; + aRectangle.Bottom() = mpCurrRectBand->mnYBottom; + + while(mpCurrRectBandSep) + { + aRectangle.Left() = mpCurrRectBandSep->mnXLeft; + aRectangle.Right() = mpCurrRectBandSep->mnXRight; + rTarget.push_back(aRectangle); + mpCurrRectBandSep = mpCurrRectBandSep->mpNextSep; + } + + mpCurrRectBand = mpCurrRectBand->mpNextBand; + } +} + +sal_uInt32 RegionBand::getRectangleCount() const +{ + sal_uInt32 nCount = 0; + const ImplRegionBand* pBand = mpFirstBand; + + while(pBand) + { + ImplRegionBandSep* pSep = pBand->mpFirstSep; + + while(pSep) + { + nCount++; + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } + + return 0; +} + +#ifdef DBG_UTIL +const char* ImplDbgTestRegionBand(const void* pObj) +{ + const RegionBand* pRegionBand = reinterpret_cast< const RegionBand* >(pObj); + + if(pRegionBand) + { + const ImplRegionBand* pBand = pRegionBand->ImplGetFirstRegionBand(); + + while(pBand) + { + if(pBand->mnYBottom < pBand->mnYTop) + { + return "YBottom < YTop"; + } + + if(pBand->mpNextBand) + { + if(pBand->mnYBottom >= pBand->mpNextBand->mnYTop) + { + return "overlapping bands in region"; + } + } + + if(pBand->mbTouched) + { + return "Band-mbTouched overwrite"; + } + + ImplRegionBandSep* pSep = pBand->mpFirstSep; + + while(pSep) + { + if(pSep->mnXRight < pSep->mnXLeft) + { + return "XLeft < XRight"; + } + + if(pSep->mpNextSep) + { + if(pSep->mnXRight >= pSep->mpNextSep->mnXLeft) + { + return "overlapping separations in region"; + } + } + + if ( pSep->mbRemoved > 1 ) + { + return "Sep-mbRemoved overwrite"; + } + + pSep = pSep->mpNextSep; + } + + pBand = pBand->mpNextBand; + } + } + + return 0; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx index 416d97558c32..12ead6c91029 100644 --- a/vcl/source/gdi/salgdilayout.cxx +++ b/vcl/source/gdi/salgdilayout.cxx @@ -39,7 +39,6 @@ #include <vcl/unowrap.hxx> #include <window.h> -#include <region.h> #include <outdev.h> #include <sallayout.hxx> #include <salgdi.hxx> @@ -250,28 +249,38 @@ sal_Bool SalGraphics::mirror( sal_uInt32 nPoints, const SalPoint *pPtAry, SalPoi void SalGraphics::mirror( Region& rRgn, const OutputDevice *pOutDev, bool bBack ) const { - if( rRgn.HasPolyPolygon() ) + if( rRgn.HasPolyPolygonOrB2DPolyPolygon() ) { - basegfx::B2DPolyPolygon aPolyPoly( rRgn.ConvertToB2DPolyPolygon() ); - aPolyPoly = mirror( aPolyPoly, pOutDev, bBack ); - rRgn = Region( aPolyPoly ); + const basegfx::B2DPolyPolygon aPolyPoly(mirror(rRgn.GetAsB2DPolyPolygon(), pOutDev, bBack)); + + rRgn = Region(aPolyPoly); } else { - ImplRegionInfo aInfo; - bool bRegionRect; - Region aMirroredRegion; - long nX, nY, nWidth, nHeight; + RectangleVector aRectangles; + rRgn.GetRegionRectangles(aRectangles); + rRgn.SetEmpty(); - bRegionRect = rRgn.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); - while ( bRegionRect ) + for(RectangleVector::iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - Rectangle aRect( Point(nX, nY), Size(nWidth, nHeight) ); - mirror( aRect, pOutDev, bBack ); - aMirroredRegion.Union( aRect ); - bRegionRect = rRgn.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + mirror(*aRectIter, pOutDev, bBack); + rRgn.Union(*aRectIter); } - rRgn = aMirroredRegion; + + //ImplRegionInfo aInfo; + //bool bRegionRect; + //Region aMirroredRegion; + //long nX, nY, nWidth, nHeight; + // + //bRegionRect = rRgn.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); + //while ( bRegionRect ) + //{ + // Rectangle aRect( Point(nX, nY), Size(nWidth, nHeight) ); + // mirror( aRect, pOutDev, bBack ); + // aMirroredRegion.Union( aRect ); + // bRegionRect = rRgn.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + //} + //rRgn = aMirroredRegion; } } diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index 0d2cd17e6f2d..a17dcaa2755a 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -68,7 +68,6 @@ #include "window.h" #include "toolbox.h" #include "outdev.h" -#include "region.h" #include "brdwin.hxx" #include "helpwin.hxx" #include "sallayout.hxx" @@ -151,8 +150,8 @@ ImplAccessibleInfos::~ImplAccessibleInfos() WindowImpl::WindowImpl( WindowType nType ) { maZoom = Fraction( 1, 1 ); - maWinRegion = Region( REGION_NULL ); - maWinClipRegion = Region( REGION_NULL ); + maWinRegion = Region(true); + maWinClipRegion = Region(true); mpWinData = NULL; // Extra Window Data, that we dont need for all windows mpOverlapData = NULL; // Overlap Data mpFrameData = NULL; // Frame Data @@ -1809,23 +1808,38 @@ sal_Bool Window::ImplSysObjClip( const Region* pOldRegion ) aRegion.Move( -mnOutOffX, -mnOutOffY ); // ClipRegion setzen/updaten - long nX; - long nY; - long nWidth; - long nHeight; - sal_uLong nRectCount; - ImplRegionInfo aInfo; - sal_Bool bRegionRect; - - nRectCount = aRegion.GetRectCount(); - mpWindowImpl->mpSysObj->BeginSetClipRegion( nRectCount ); - bRegionRect = aRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); - while ( bRegionRect ) + RectangleVector aRectangles; + aRegion.GetRegionRectangles(aRectangles); + mpWindowImpl->mpSysObj->BeginSetClipRegion(aRectangles.size()); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - mpWindowImpl->mpSysObj->UnionClipRegion( nX, nY, nWidth, nHeight ); - bRegionRect = aRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + mpWindowImpl->mpSysObj->UnionClipRegion( + aRectIter->Left(), + aRectIter->Top(), + aRectIter->GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does + aRectIter->GetHeight()); // same for height } + mpWindowImpl->mpSysObj->EndSetClipRegion(); + + //long nX; + //long nY; + //long nWidth; + //long nHeight; + //sal_uLong nRectCount; + //ImplRegionInfo aInfo; + //sal_Bool bRegionRect; + // + //nRectCount = aRegion.GetRectCount(); + //mpWindowImpl->mpSysObj->BeginSetClipRegion( nRectCount ); + //bRegionRect = aRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); + //while ( bRegionRect ) + //{ + // mpWindowImpl->mpSysObj->UnionClipRegion( nX, nY, nWidth, nHeight ); + // bRegionRect = aRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + //} + //mpWindowImpl->mpSysObj->EndSetClipRegion(); } } else @@ -2348,6 +2362,9 @@ void Window::ImplCalcOverlapRegion( const Rectangle& rSourceRect, Region& rRegio void Window::ImplCallPaint( const Region* pRegion, sal_uInt16 nPaintFlags ) { + Exception aException; + bool bExceptionCaught(false); + // call PrePaint. PrePaint may add to the invalidate region as well as // other parameters used below. PrePaint(); @@ -2441,7 +2458,19 @@ void Window::ImplCallPaint( const Region* pRegion, sal_uInt16 nPaintFlags ) if( mpWindowImpl->mbDrawSelectionBackground ) aSelectionRect = aPaintRect; - Paint( aPaintRect ); + // Paint can throw exceptions; to not have a situation where + // mpWindowImpl->mbInPaint keeps to be on true (and other + // settings, too) better catch here to avoid to go completely out of + // this method without executing the after-paint stuff + try + { + Paint( aPaintRect ); + } + catch(Exception& rException) + { + aException = rException; + bExceptionCaught = true; + } if ( mpWindowImpl->mpWinData ) { @@ -2482,6 +2511,11 @@ void Window::ImplCallPaint( const Region* pRegion, sal_uInt16 nPaintFlags ) if ( pChildRegion ) delete pChildRegion; + + if(bExceptionCaught) + { + throw(aException); + } } // ----------------------------------------------------------------------- @@ -6023,7 +6057,7 @@ void Window::SetWindowRegionPixel() mpWindowImpl->mpBorderWindow->SetWindowRegionPixel(); else if( mpWindowImpl->mbFrame ) { - mpWindowImpl->maWinRegion = Region( REGION_NULL); + mpWindowImpl->maWinRegion = Region(true); mpWindowImpl->mbWinRegion = sal_False; mpWindowImpl->mpFrame->ResetClipRegion(); } @@ -6031,7 +6065,7 @@ void Window::SetWindowRegionPixel() { if ( mpWindowImpl->mbWinRegion ) { - mpWindowImpl->maWinRegion = Region( REGION_NULL ); + mpWindowImpl->maWinRegion = Region(true); mpWindowImpl->mbWinRegion = sal_False; ImplSetClipFlag(); @@ -6060,30 +6094,46 @@ void Window::SetWindowRegionPixel( const Region& rRegion ) mpWindowImpl->mpBorderWindow->SetWindowRegionPixel( rRegion ); else if( mpWindowImpl->mbFrame ) { - if( rRegion.GetType() != REGION_NULL ) + if( !rRegion.IsNull() ) { mpWindowImpl->maWinRegion = rRegion; mpWindowImpl->mbWinRegion = ! rRegion.IsEmpty(); + if( mpWindowImpl->mbWinRegion ) { // ClipRegion setzen/updaten - long nX; - long nY; - long nWidth; - long nHeight; - sal_uLong nRectCount; - ImplRegionInfo aInfo; - sal_Bool bRegionRect; - - nRectCount = mpWindowImpl->maWinRegion.GetRectCount(); - mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount ); - bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); - while ( bRegionRect ) + RectangleVector aRectangles; + mpWindowImpl->maWinRegion.GetRegionRectangles(aRectangles); + mpWindowImpl->mpFrame->BeginSetClipRegion(aRectangles.size()); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight ); - bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + mpWindowImpl->mpFrame->UnionClipRegion( + aRectIter->Left(), + aRectIter->Top(), + aRectIter->GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does + aRectIter->GetHeight()); // same for height } + mpWindowImpl->mpFrame->EndSetClipRegion(); + + //long nX; + //long nY; + //long nWidth; + //long nHeight; + //sal_uLong nRectCount; + //ImplRegionInfo aInfo; + //sal_Bool bRegionRect; + // + //nRectCount = mpWindowImpl->maWinRegion.GetRectCount(); + //mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount ); + //bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); + //while ( bRegionRect ) + //{ + // mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight ); + // bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + //} + //mpWindowImpl->mpFrame->EndSetClipRegion(); } else SetWindowRegionPixel(); @@ -6095,11 +6145,11 @@ void Window::SetWindowRegionPixel( const Region& rRegion ) { sal_Bool bInvalidate = sal_False; - if ( rRegion.GetType() == REGION_NULL ) + if ( rRegion.IsNull() ) { if ( mpWindowImpl->mbWinRegion ) { - mpWindowImpl->maWinRegion = Region( REGION_NULL ); + mpWindowImpl->maWinRegion = Region(true); mpWindowImpl->mbWinRegion = sal_False; ImplSetClipFlag(); bInvalidate = sal_True; @@ -6202,7 +6252,7 @@ Region Window::GetPaintRegion() const } else { - Region aPaintRegion( REGION_NULL ); + Region aPaintRegion(true); return aPaintRegion; } } @@ -6452,7 +6502,7 @@ void Window::Show( sal_Bool bVisible, sal_uInt16 nFlags ) if ( mpWindowImpl->mbReallyVisible ) { - Region aInvRegion( REGION_EMPTY ); + Region aInvRegion; sal_Bool bSaveBack = sal_False; if ( ImplIsOverlapWindow() && !mpWindowImpl->mbFrame ) diff --git a/vcl/unx/generic/gdi/pspgraphics.cxx b/vcl/unx/generic/gdi/pspgraphics.cxx index 188cff6be9dd..f0a010d815c5 100644 --- a/vcl/unx/generic/gdi/pspgraphics.cxx +++ b/vcl/unx/generic/gdi/pspgraphics.cxx @@ -46,7 +46,6 @@ #include "outfont.hxx" #include "fontsubset.hxx" #include "salprn.hxx" -#include "region.h" #ifdef ENABLE_GRAPHITE #include <graphite_layout.hxx> @@ -295,20 +294,45 @@ void PspGraphics::ResetClipRegion() bool PspGraphics::setClipRegion( const Region& i_rClip ) { // TODO: support polygonal clipregions here - m_pPrinterGfx->BeginSetClipRegion( i_rClip.GetRectCount() ); + RectangleVector aRectangles; + i_rClip.GetRegionRectangles(aRectangles); + m_pPrinterGfx->BeginSetClipRegion(aRectangles.size()); - ImplRegionInfo aInfo; - long nX, nY, nW, nH; - bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); - while( bRegionRect ) + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - if ( nW && nH ) + const long nW(aRectIter->GetWidth()); + + if(nW) { - m_pPrinterGfx->UnionClipRegion( nX, nY, nW, nH ); + const long nH(aRectIter->GetHeight()); + + if(nH) + { + m_pPrinterGfx->UnionClipRegion( + aRectIter->Left(), + aRectIter->Top(), + nW, + nH); + } } - bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); } + m_pPrinterGfx->EndSetClipRegion(); + + //m_pPrinterGfx->BeginSetClipRegion( i_rClip.GetRectCount() ); + // + //ImplRegionInfo aInfo; + //long nX, nY, nW, nH; + //bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); + //while( bRegionRect ) + //{ + // if ( nW && nH ) + // { + // m_pPrinterGfx->UnionClipRegion( nX, nY, nW, nH ); + // } + // bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); + //} + //m_pPrinterGfx->EndSetClipRegion(); return true; } diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx index d7a3eccb0d09..cda1c27fc98a 100644 --- a/vcl/unx/generic/gdi/salgdi.cxx +++ b/vcl/unx/generic/gdi/salgdi.cxx @@ -49,7 +49,6 @@ #include "printergfx.hxx" #include "xrender_peer.hxx" -#include "region.h" #include <vector> #include <queue> @@ -591,24 +590,48 @@ bool X11SalGraphics::setClipRegion( const Region& i_rClip ) XDestroyRegion( mpClipRegion ); mpClipRegion = XCreateRegion(); - ImplRegionInfo aInfo; - long nX, nY, nW, nH; - bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); - while( bRegionRect ) + RectangleVector aRectangles; + i_rClip.GetRegionRectangles(aRectangles); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - if ( nW && nH ) + const long nW(aRectIter->GetWidth()); + + if(nW) { - XRectangle aRect; - aRect.x = (short)nX; - aRect.y = (short)nY; - aRect.width = (unsigned short)nW; - aRect.height = (unsigned short)nH; + const long nH(aRectIter->GetHeight()); + + if(nH) + { + XRectangle aRect; - XUnionRectWithRegion( &aRect, mpClipRegion, mpClipRegion ); + aRect.x = (short)aRectIter->Left(); + aRect.y = (short)aRectIter->Top(); + aRect.width = (unsigned short)nW; + aRect.height = (unsigned short)nH; + XUnionRectWithRegion(&aRect, mpClipRegion, mpClipRegion); + } } - bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); } + //ImplRegionInfo aInfo; + //long nX, nY, nW, nH; + //bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); + //while( bRegionRect ) + //{ + // if ( nW && nH ) + // { + // XRectangle aRect; + // aRect.x = (short)nX; + // aRect.y = (short)nY; + // aRect.width = (unsigned short)nW; + // aRect.height = (unsigned short)nH; + // + // XUnionRectWithRegion( &aRect, mpClipRegion, mpClipRegion ); + // } + // bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); + //} + // done, invalidate GCs bPenGC_ = sal_False; bFontGC_ = sal_False; diff --git a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx index 41c1a95feac3..eac3312a3a7f 100644 --- a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx +++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx @@ -760,16 +760,29 @@ sal_Bool GtkSalGraphics::drawNativeControl( ControlType nType, } else { - RegionHandle aHdl = aClipRegion.BeginEnumRects(); - Rectangle aPaintRect; - while( aClipRegion.GetNextEnumRect( aHdl, aPaintRect ) ) + RectangleVector aRectangles; + aClipRegion.GetRegionRectangles(aRectangles); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - aPaintRect = aCtrlRect.GetIntersection( aPaintRect ); - if( aPaintRect.IsEmpty() ) + if(aRectIter->IsEmpty()) + { continue; - aClip.push_back( aPaintRect ); + } + + aClip.push_back(*aRectIter); } - aClipRegion.EndEnumRects( aHdl ); + + //RegionHandle aHdl = aClipRegion.BeginEnumRects(); + //Rectangle aPaintRect; + //while( aClipRegion.GetEnumRects( aHdl, aPaintRect ) ) + //{ + // aPaintRect = aCtrlRect.GetIntersection( aPaintRect ); + // if( aPaintRect.IsEmpty() ) + // continue; + // aClip.push_back( aPaintRect ); + //} + //aClipRegion.EndEnumRects( aHdl ); } if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL) ) diff --git a/vcl/unx/headless/svpgdi.cxx b/vcl/unx/headless/svpgdi.cxx index c3f4ce549e1e..5360e71a41ea 100644 --- a/vcl/unx/headless/svpgdi.cxx +++ b/vcl/unx/headless/svpgdi.cxx @@ -42,7 +42,6 @@ #endif #include <svppspgraphics.hxx> -#include <region.h> using namespace basegfx; using namespace basebmp; @@ -152,35 +151,66 @@ void SvpSalGraphics::ResetClipRegion() bool SvpSalGraphics::setClipRegion( const Region& i_rClip ) { if( i_rClip.IsEmpty() ) + { m_aClipMap.reset(); - else if( i_rClip.GetRectCount() == 1 ) + return true; + } + + RectangleVector aRectangles; + i_rClip.GetRegionRectangles(aRectangles); + + if(1 == aRectangles.size()) { m_aClipMap.reset(); - Rectangle aBoundRect( i_rClip.GetBoundRect() ); - m_aDevice = basebmp::subsetBitmapDevice( m_aOrigDevice, - basegfx::B2IRange(aBoundRect.Left(),aBoundRect.Top(),aBoundRect.Right(),aBoundRect.Bottom()) ); + const Rectangle& aBoundRect = aRectangles[0]; + m_aDevice = basebmp::subsetBitmapDevice( + m_aOrigDevice, + basegfx::B2IRange(aBoundRect.Left(),aBoundRect.Top(),aBoundRect.Right(),aBoundRect.Bottom()) ); + return true; } - else + + m_aDevice = m_aOrigDevice; + B2IVector aSize = m_aDevice->getSize(); + m_aClipMap = createBitmapDevice( aSize, false, Format::ONE_BIT_MSB_GREY ); + m_aClipMap->clear( basebmp::Color(0xFFFFFFFF) ); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - m_aDevice = m_aOrigDevice; - B2IVector aSize = m_aDevice->getSize(); - m_aClipMap = createBitmapDevice( aSize, false, Format::ONE_BIT_MSB_GREY ); - m_aClipMap->clear( basebmp::Color(0xFFFFFFFF) ); + const long nW(aRectIter->GetWidth()); - ImplRegionInfo aInfo; - long nX, nY, nW, nH; - bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); - while( bRegionRect ) + if(nW) { - if ( nW && nH ) + const long nH(aRectIter->GetHeight()); + + if(nH) { B2DPolyPolygon aFull; - aFull.append( tools::createPolygonFromRect( B2DRectangle( nX, nY, nX+nW, nY+nH ) ) ); - m_aClipMap->fillPolyPolygon( aFull, basebmp::Color(0), DrawMode_PAINT ); + + aFull.append( + tools::createPolygonFromRect( + B2DRectangle( + aRectIter->Left(), + aRectIter->Top(), + aRectIter->Left() + nW, + aRectIter->Top() + nH))); + m_aClipMap->fillPolyPolygon(aFull, basebmp::Color(0), DrawMode_PAINT); } - bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); } } + + //ImplRegionInfo aInfo; + //long nX, nY, nW, nH; + //bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); + //while( bRegionRect ) + //{ + // if ( nW && nH ) + // { + // B2DPolyPolygon aFull; + // aFull.append( tools::createPolygonFromRect( B2DRectangle( nX, nY, nX+nW, nY+nH ) ) ); + // m_aClipMap->fillPolyPolygon( aFull, basebmp::Color(0), DrawMode_PAINT ); + // } + // bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); + //} return true; } diff --git a/vcl/unx/headless/svppspgraphics.cxx b/vcl/unx/headless/svppspgraphics.cxx index 281f8c57b53a..bcf938909538 100644 --- a/vcl/unx/headless/svppspgraphics.cxx +++ b/vcl/unx/headless/svppspgraphics.cxx @@ -51,7 +51,6 @@ #include "printergfx.hxx" #include "svppspgraphics.hxx" #include "svpbmp.hxx" -#include "region.h" using namespace psp; using namespace rtl; @@ -220,19 +219,41 @@ void PspGraphics::ResetClipRegion() bool PspGraphics::setClipRegion( const Region& i_rClip ) { // TODO: support polygonal clipregions here - m_pPrinterGfx->BeginSetClipRegion( i_rClip.GetRectCount() ); + RectangleVector aRectangles; + i_rClip.GetRegionRectangles(aRectangles); + m_pPrinterGfx->BeginSetClipRegion(aRectangles.size()); - ImplRegionInfo aInfo; - long nX, nY, nW, nH; - bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); - while( bRegionRect ) + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - if ( nW && nH ) + const long nW(aRectIter->GetWidth()); + + if(nW) { - m_pPrinterGfx->UnionClipRegion( nX, nY, nW, nH ); + const long nH(aRectIter->GetHeight()); + + if(nH) + { + m_pPrinterGfx->UnionClipRegion( + aRectIter->Left(), + aRectIter->Top(), + nW, + nH); + } } - bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); } + + //ImplRegionInfo aInfo; + //long nX, nY, nW, nH; + //bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); + //while( bRegionRect ) + //{ + // if ( nW && nH ) + // { + // m_pPrinterGfx->UnionClipRegion( nX, nY, nW, nH ); + // } + // bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); + //} + m_pPrinterGfx->EndSetClipRegion(); return true; } diff --git a/vcl/win/source/gdi/salgdi.cxx b/vcl/win/source/gdi/salgdi.cxx index 2b9d30cd16c8..e25a417a9179 100644 --- a/vcl/win/source/gdi/salgdi.cxx +++ b/vcl/win/source/gdi/salgdi.cxx @@ -41,8 +41,6 @@ #include <win/salgdi.h> #include <win/salframe.h> -#include <region.h> - using namespace rtl; // ======================================================================= @@ -861,10 +859,9 @@ bool WinSalGraphics::setClipRegion( const Region& i_rClip ) mhRegion = 0; } - if( i_rClip.HasPolyPolygon() ) + if( i_rClip.HasPolyPolygonOrB2DPolyPolygon() ) { - // TODO: ConvertToB2DPolyPolygon actually is kind of const, just it does not advertise it in the header - basegfx::B2DPolyPolygon aPolyPolygon( const_cast<Region&>(i_rClip).ConvertToB2DPolyPolygon() ); + const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() ); const sal_uInt32 nCount(aPolyPolygon.count()); if( nCount ) @@ -872,12 +869,15 @@ bool WinSalGraphics::setClipRegion( const Region& i_rClip ) std::vector< POINT > aPolyPoints; aPolyPoints.reserve( 1024 ); std::vector< INT > aPolyCounts( nCount, 0 ); + for(sal_uInt32 a(0); a < nCount; a++) { - basegfx::B2DPolygon aPoly( aPolyPolygon.getB2DPolygon(a) ); + basegfx::B2DPolygon aPoly(aPolyPolygon.getB2DPolygon(a)); + aPoly = basegfx::tools::adaptiveSubdivideByDistance( aPoly, 1 ); const sal_uInt32 nPoints = aPoly.count(); aPolyCounts[a] = nPoints; + for( sal_uInt32 b = 0; b < nPoints; b++ ) { basegfx::B2DPoint aPt( aPoly.getB2DPoint( b ) ); @@ -887,15 +887,18 @@ bool WinSalGraphics::setClipRegion( const Region& i_rClip ) aPolyPoints.push_back( aPOINT ); } } + mhRegion = CreatePolyPolygonRgn( &aPolyPoints[0], &aPolyCounts[0], nCount, ALTERNATE ); } } else { - ULONG nRectCount = i_rClip.GetRectCount(); + RectangleVector aRectangles; + i_rClip.GetRegionRectangles(aRectangles); - ULONG nRectBufSize = sizeof(RECT)*nRectCount; - if ( nRectCount < SAL_CLIPRECT_COUNT ) + //ULONG nRectCount = i_rClip.GetRectCount(); + ULONG nRectBufSize = sizeof(RECT)*aRectangles.size(); + if ( aRectangles.size() < SAL_CLIPRECT_COUNT ) { if ( !mpStdClipRgnData ) mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))]; @@ -905,50 +908,58 @@ bool WinSalGraphics::setClipRegion( const Region& i_rClip ) mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize]; mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER ); mpClipRgnData->rdh.iType = RDH_RECTANGLES; - mpClipRgnData->rdh.nCount = nRectCount; + mpClipRgnData->rdh.nCount = aRectangles.size(); mpClipRgnData->rdh.nRgnSize = nRectBufSize; RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound); SetRectEmpty( pBoundRect ); RECT* pNextClipRect = (RECT*)(&(mpClipRgnData->Buffer)); bool bFirstClipRect = true; - ImplRegionInfo aInfo; - long nX, nY, nW, nH; - bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); - while( bRegionRect ) + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { - if ( nW && nH ) + const long nW(aRectIter->GetWidth()); + const long nH(aRectIter->GetHeight()); + + if(nW && nH) { - long nRight = nX + nW; - long nBottom = nY + nH; + const long nRight(aRectIter->Left() + nW); + const long nBottom(aRectIter->Top() + nH); - if ( bFirstClipRect ) + if(bFirstClipRect) { - pBoundRect->left = nX; - pBoundRect->top = nY; - pBoundRect->right = nRight; - pBoundRect->bottom = nBottom; + pBoundRect->left = aRectIter->Left(); + pBoundRect->top = aRectIter->Top(); + pBoundRect->right = nRight; + pBoundRect->bottom = nBottom; bFirstClipRect = false; } else { - if ( nX < pBoundRect->left ) - pBoundRect->left = (int)nX; + if(aRectIter->Left() < pBoundRect->left) + { + pBoundRect->left = (int)aRectIter->Left(); + } - if ( nY < pBoundRect->top ) - pBoundRect->top = (int)nY; + if(aRectIter->Top() < pBoundRect->top) + { + pBoundRect->top = (int)aRectIter->Top(); + } - if ( nRight > pBoundRect->right ) + if(nRight > pBoundRect->right) + { pBoundRect->right = (int)nRight; + } - if ( nBottom > pBoundRect->bottom ) + if(nBottom > pBoundRect->bottom) + { pBoundRect->bottom = (int)nBottom; + } } - pNextClipRect->left = (int)nX; - pNextClipRect->top = (int)nY; - pNextClipRect->right = (int)nRight; - pNextClipRect->bottom = (int)nBottom; + pNextClipRect->left = (int)aRectIter->Left(); + pNextClipRect->top = (int)aRectIter->Top(); + pNextClipRect->right = (int)nRight; + pNextClipRect->bottom = (int)nBottom; pNextClipRect++; } else @@ -956,8 +967,55 @@ bool WinSalGraphics::setClipRegion( const Region& i_rClip ) mpClipRgnData->rdh.nCount--; mpClipRgnData->rdh.nRgnSize -= sizeof( RECT ); } - bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); } + + //ImplRegionInfo aInfo; + //long nX, nY, nW, nH; + //bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); + //while( bRegionRect ) + //{ + // if ( nW && nH ) + // { + // long nRight = nX + nW; + // long nBottom = nY + nH; + // + // if ( bFirstClipRect ) + // { + // pBoundRect->left = nX; + // pBoundRect->top = nY; + // pBoundRect->right = nRight; + // pBoundRect->bottom = nBottom; + // bFirstClipRect = false; + // } + // else + // { + // if ( nX < pBoundRect->left ) + // pBoundRect->left = (int)nX; + // + // if ( nY < pBoundRect->top ) + // pBoundRect->top = (int)nY; + // + // if ( nRight > pBoundRect->right ) + // pBoundRect->right = (int)nRight; + // + // if ( nBottom > pBoundRect->bottom ) + // pBoundRect->bottom = (int)nBottom; + // } + // + // pNextClipRect->left = (int)nX; + // pNextClipRect->top = (int)nY; + // pNextClipRect->right = (int)nRight; + // pNextClipRect->bottom = (int)nBottom; + // pNextClipRect++; + // } + // else + // { + // mpClipRgnData->rdh.nCount--; + // mpClipRgnData->rdh.nRgnSize -= sizeof( RECT ); + // } + // bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); + //} + // create clip region from ClipRgnData if ( mpClipRgnData->rdh.nCount == 1 ) { |