summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Sherlock <chris.sherlock79@gmail.com>2014-04-06 20:57:49 +1000
committerChris Sherlock <chris.sherlock79@gmail.com>2014-04-06 22:08:41 -0500
commit8659d189ec04aca78c8ffff97fcca507ca0a9ec3 (patch)
treef96203da4e501024f1f851c683065f61e6f28afe
parent3b6dba357f94b581cfeee844f9203a84aa1b5823 (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.hxx6
-rw-r--r--include/vcl/print.hxx3
-rw-r--r--vcl/source/gdi/outdev4.cxx251
-rw-r--r--vcl/source/gdi/print.cxx15
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: */