diff options
author | Chris Sherlock <chris.sherlock79@gmail.com> | 2014-04-06 20:57:49 +1000 |
---|---|---|
committer | Chris Sherlock <chris.sherlock79@gmail.com> | 2014-04-06 22:08:41 -0500 |
commit | 8659d189ec04aca78c8ffff97fcca507ca0a9ec3 (patch) | |
tree | f96203da4e501024f1f851c683065f61e6f28afe | |
parent | 3b6dba357f94b581cfeee844f9203a84aa1b5823 (diff) |
fdo#74702 Refactor gradient clipping functions
There are two gradient clipping functions: one uses a normal intersection
to get the symmetric difference to clip the gradient - this is used by
OS X and when printing. The other uses XOR clipping, which is an elegant
trick to implement complex clipping on graphics systems that have minimal
capabilities.
cf. http://www.openoffice.org/marketing/ooocon2008/programme/wednesday_1401.pdf
Change-Id: Iab16258c8e758c41a29337525927ba780329e887
Reviewed-on: https://gerrit.libreoffice.org/8873
Tested-by: LibreOffice gerrit bot <gerrit@libreoffice.org>
Reviewed-by: Chris Sherlock <chris.sherlock79@gmail.com>
Tested-by: Chris Sherlock <chris.sherlock79@gmail.com>
-rw-r--r-- | include/vcl/outdev.hxx | 6 | ||||
-rw-r--r-- | include/vcl/print.hxx | 3 | ||||
-rw-r--r-- | vcl/source/gdi/outdev4.cxx | 251 | ||||
-rw-r--r-- | vcl/source/gdi/print.cxx | 15 |
4 files changed, 152 insertions, 123 deletions
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index 016fc168513c..119573613a2e 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -844,6 +844,12 @@ protected: virtual void EmulateDrawTransparent( const PolyPolygon& rPolyPoly, sal_uInt16 nTransparencePercent ); void DrawInvisiblePolygon( const PolyPolygon& rPolyPoly ); + virtual void ClipGradientToBounds( Gradient &rGradient, const PolyPolygon &rPolyPoly ); + void ClipGradient( Gradient &rGradient, const PolyPolygon &rPolyPoly, const Rectangle &rBoundRect ); + void XORClipGradient( Gradient &rGradient, const PolyPolygon &rPolyPoly, const Rectangle &rBoundRect ); + + virtual void ClipGradientMetafile ( const Gradient &rGradient, const PolyPolygon &rPolyPoly, const Rectangle &rBoundRect ); + private: typedef void ( OutputDevice::* FontUpdateHandler_t )( bool ); diff --git a/include/vcl/print.hxx b/include/vcl/print.hxx index d70e7c025c01..f9179bd814d3 100644 --- a/include/vcl/print.hxx +++ b/include/vcl/print.hxx @@ -274,7 +274,10 @@ public: protected: long ImplGetGradientStepCount( long nMinRect ) SAL_OVERRIDE; + virtual void ClipGradientToBounds( Gradient &rGradient, const PolyPolygon &rPolyPoly ) SAL_OVERRIDE; + virtual void ClipGradientMetafile ( const Gradient &rGradient, const PolyPolygon &rPolyPoly, const Rectangle &rBoundRect ) SAL_OVERRIDE; virtual bool UsePolyPolygonForComplexGradient() SAL_OVERRIDE; + void ScaleBitmap ( Bitmap&, SalTwoRect& ) SAL_OVERRIDE { }; public: diff --git a/vcl/source/gdi/outdev4.cxx b/vcl/source/gdi/outdev4.cxx index 4b825f44dbfd..51033a5f27e5 100644 --- a/vcl/source/gdi/outdev4.cxx +++ b/vcl/source/gdi/outdev4.cxx @@ -660,9 +660,9 @@ void OutputDevice::DrawGradient( const Rectangle& rRect, aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT ); if( aGradient.GetStyle() == GradientStyle_LINEAR || aGradient.GetStyle() == GradientStyle_AXIAL ) - ImplDrawLinearGradient( aRect, aGradient, false, NULL ); + ImplDrawLinearGradient( aRect, rGradient, false, NULL ); else - ImplDrawComplexGradient( aRect, aGradient, false, NULL ); + ImplDrawComplexGradient( aRect, rGradient, false, NULL ); } Pop(); @@ -675,6 +675,129 @@ void OutputDevice::DrawGradient( const Rectangle& rRect, } } +void OutputDevice::ClipGradientMetafile ( const Gradient &rGradient, const PolyPolygon &rPolyPoly, const Rectangle &rBoundRect ) +{ + const bool bOldOutput = IsOutputEnabled(); + + EnableOutput( false ); + Push( PUSH_RASTEROP ); + SetRasterOp( ROP_XOR ); + DrawGradient( rBoundRect, rGradient ); + SetFillColor( COL_BLACK ); + SetRasterOp( ROP_0 ); + DrawPolyPolygon( rPolyPoly ); + SetRasterOp( ROP_XOR ); + DrawGradient( rBoundRect, rGradient ); + Pop(); + EnableOutput( bOldOutput ); +} + +void OutputDevice::ClipGradientToBounds ( Gradient &rGradient, const PolyPolygon &rPolyPoly ) +{ + const Rectangle aBoundRect( rPolyPoly.GetBoundRect() ); + + if( ImplGetSVData()->maGDIData.mbNoXORClipping ) + ClipGradient ( rGradient, rPolyPoly, aBoundRect ); + else + XORClipGradient ( rGradient, rPolyPoly, aBoundRect ); +} + +void OutputDevice::ClipGradient ( Gradient &rGradient, const PolyPolygon &rPolyPoly, const Rectangle &rBoundRect ) +{ + if( !Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() ) + { + // convert rectangle to pixels + Rectangle aRect( ImplLogicToDevicePixel( rBoundRect ) ); + aRect.Justify(); + + // do nothing if the rectangle is empty + if ( !aRect.IsEmpty() ) + { + if( !mpGraphics && !ImplGetGraphics() ) + return; + + if( mbInitClipRegion ) + ImplInitClipRegion(); + + if( !mbOutputClipped ) + { + PolyPolygon aClipPolyPoly( ImplLogicToDevicePixel( rPolyPoly ) ); + + // draw gradients without border + if( mbLineColor || mbInitLineColor ) + { + mpGraphics->SetLineColor(); + mbInitLineColor = true; + } + + mbInitFillColor = true; + + // calculate step count if necessary + if ( !rGradient.GetSteps() ) + rGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT ); + + if( rGradient.GetStyle() == GradientStyle_LINEAR || rGradient.GetStyle() == GradientStyle_AXIAL ) + ImplDrawLinearGradient( aRect, rGradient, false, &aClipPolyPoly ); + else + ImplDrawComplexGradient( aRect, rGradient, false, &aClipPolyPoly ); + } + } + } +} + +void OutputDevice::XORClipGradient ( Gradient &rGradient, const PolyPolygon &rPolyPoly, const Rectangle &rBoundRect ) +{ + const PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) ); + Point aPoint; + Rectangle aDstRect( aPoint, GetOutputSizePixel() ); + + aDstRect.Intersection( rBoundRect ); + + ClipToPaintRegion( aDstRect ); + + if( !aDstRect.IsEmpty() ) + { + boost::scoped_ptr<VirtualDevice> pVDev; + const Size aDstSize( aDstRect.GetSize() ); + + if( HasAlpha() ) + { + // #110958# Pay attention to alpha VDevs here, otherwise, + // background will be wrong: Temp VDev has to have alpha, too. + pVDev.reset(new VirtualDevice( *this, 0, GetAlphaBitCount() > 1 ? 0 : 1 )); + } + else + { + // nothing special here. Plain VDev + pVDev.reset(new VirtualDevice()); + } + + if( pVDev->SetOutputSizePixel( aDstSize) ) + { + MapMode aVDevMap; + const bool bOldMap = mbMap; + + EnableMapMode( false ); + + pVDev->DrawOutDev( Point(), aDstSize, aDstRect.TopLeft(), aDstSize, *this ); + pVDev->SetRasterOp( ROP_XOR ); + aVDevMap.SetOrigin( Point( -aDstRect.Left(), -aDstRect.Top() ) ); + pVDev->SetMapMode( aVDevMap ); + pVDev->DrawGradient( rBoundRect, rGradient ); + pVDev->SetFillColor( COL_BLACK ); + pVDev->SetRasterOp( ROP_0 ); + pVDev->DrawPolyPolygon( aPolyPoly ); + pVDev->SetRasterOp( ROP_XOR ); + pVDev->DrawGradient( rBoundRect, rGradient ); + aVDevMap.SetOrigin( Point() ); + pVDev->SetMapMode( aVDevMap ); + DrawOutDev( aDstRect.TopLeft(), aDstSize, Point(), aDstSize, *pVDev ); + + EnableMapMode( bOldMap ); + } + } +} + void OutputDevice::DrawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient ) { @@ -719,34 +842,12 @@ void OutputDevice::DrawGradient( const PolyPolygon& rPolyPoly, if( mpMetaFile ) { - const Rectangle aRect( rPolyPoly.GetBoundRect() ); + const Rectangle aBoundRect( rPolyPoly.GetBoundRect() ); mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) ); mpMetaFile->AddAction( new MetaGradientExAction( rPolyPoly, rGradient ) ); - if( OUTDEV_PRINTER == meOutDevType ) - { - Push( PUSH_CLIPREGION ); - IntersectClipRegion(Region(rPolyPoly)); - DrawGradient( aRect, rGradient ); - Pop(); - } - else - { - const bool bOldOutput = IsOutputEnabled(); - - EnableOutput( false ); - Push( PUSH_RASTEROP ); - SetRasterOp( ROP_XOR ); - DrawGradient( aRect, rGradient ); - SetFillColor( COL_BLACK ); - SetRasterOp( ROP_0 ); - DrawPolyPolygon( rPolyPoly ); - SetRasterOp( ROP_XOR ); - DrawGradient( aRect, rGradient ); - Pop(); - EnableOutput( bOldOutput ); - } + ClipGradientMetafile ( rGradient, rPolyPoly, aBoundRect ); mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) ); } @@ -783,103 +884,7 @@ void OutputDevice::DrawGradient( const PolyPolygon& rPolyPoly, aGradient.SetEndColor( aEndCol ); } - if( OUTDEV_PRINTER == meOutDevType || ImplGetSVData()->maGDIData.mbNoXORClipping ) - { - const Rectangle aBoundRect( rPolyPoly.GetBoundRect() ); - - if( !Rectangle( PixelToLogic( Point() ), GetOutputSize() ).IsEmpty() ) - { - // convert rectangle to pixels - Rectangle aRect( ImplLogicToDevicePixel( aBoundRect ) ); - aRect.Justify(); - - // do nothing if the rectangle is empty - if ( !aRect.IsEmpty() ) - { - if( !mpGraphics && !ImplGetGraphics() ) - return; - - if( mbInitClipRegion ) - ImplInitClipRegion(); - - if( !mbOutputClipped ) - { - PolyPolygon aClipPolyPoly( ImplLogicToDevicePixel( rPolyPoly ) ); - - // draw gradients without border - if( mbLineColor || mbInitLineColor ) - { - mpGraphics->SetLineColor(); - mbInitLineColor = true; - } - - mbInitFillColor = true; - - // calculate step count if necessary - if ( !aGradient.GetSteps() ) - aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT ); - - if( aGradient.GetStyle() == GradientStyle_LINEAR || aGradient.GetStyle() == GradientStyle_AXIAL ) - ImplDrawLinearGradient( aRect, aGradient, false, &aClipPolyPoly ); - else - ImplDrawComplexGradient( aRect, aGradient, false, &aClipPolyPoly ); - } - } - } - } - else - { - const PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) ); - const Rectangle aBoundRect( aPolyPoly.GetBoundRect() ); - Point aPoint; - Rectangle aDstRect( aPoint, GetOutputSizePixel() ); - - aDstRect.Intersection( aBoundRect ); - - ClipToPaintRegion( aDstRect ); - - if( !aDstRect.IsEmpty() ) - { - boost::scoped_ptr<VirtualDevice> pVDev; - const Size aDstSize( aDstRect.GetSize() ); - - if( HasAlpha() ) - { - // #110958# Pay attention to alpha VDevs here, otherwise, - // background will be wrong: Temp VDev has to have alpha, too. - pVDev.reset(new VirtualDevice( *this, 0, GetAlphaBitCount() > 1 ? 0 : 1 )); - } - else - { - // nothing special here. Plain VDev - pVDev.reset(new VirtualDevice()); - } - - if( pVDev->SetOutputSizePixel( aDstSize) ) - { - MapMode aVDevMap; - const bool bOldMap = mbMap; - - EnableMapMode( false ); - - pVDev->DrawOutDev( Point(), aDstSize, aDstRect.TopLeft(), aDstSize, *this ); - pVDev->SetRasterOp( ROP_XOR ); - aVDevMap.SetOrigin( Point( -aDstRect.Left(), -aDstRect.Top() ) ); - pVDev->SetMapMode( aVDevMap ); - pVDev->DrawGradient( aBoundRect, aGradient ); - pVDev->SetFillColor( COL_BLACK ); - pVDev->SetRasterOp( ROP_0 ); - pVDev->DrawPolyPolygon( aPolyPoly ); - pVDev->SetRasterOp( ROP_XOR ); - pVDev->DrawGradient( aBoundRect, aGradient ); - aVDevMap.SetOrigin( Point() ); - pVDev->SetMapMode( aVDevMap ); - DrawOutDev( aDstRect.TopLeft(), aDstSize, Point(), aDstSize, *pVDev ); - - EnableMapMode( bOldMap ); - } - } - } + ClipGradientToBounds ( aGradient, rPolyPoly ); } if( mpAlphaVDev ) diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx index 7adfcdef8bce..c66f1219a66d 100644 --- a/vcl/source/gdi/print.cxx +++ b/vcl/source/gdi/print.cxx @@ -1812,4 +1812,19 @@ bool Printer::UsePolyPolygonForComplexGradient() return true; } +void Printer::ClipGradientToBounds ( Gradient &rGradient, const PolyPolygon &rPolyPoly ) +{ + const Rectangle aBoundRect( rPolyPoly.GetBoundRect() ); + + ClipGradient ( rGradient, rPolyPoly, aBoundRect ); +} + +void Printer::ClipGradientMetafile ( const Gradient &rGradient, const PolyPolygon &rPolyPoly, const Rectangle &rBoundRect ) +{ + Push( PUSH_CLIPREGION ); + IntersectClipRegion(Region(rPolyPoly)); + DrawGradient( rBoundRect, rGradient ); + Pop(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |