[Libreoffice-commits] core.git: include/vcl vcl/inc vcl/source
Chris Sherlock
chris.sherlock79 at gmail.com
Mon Nov 3 14:54:42 PST 2014
include/vcl/outdev.hxx | 8
vcl/inc/generic/genpspgraphics.h | 2
vcl/inc/headless/svpgdi.hxx | 1
vcl/inc/quartz/salgdi.h | 1
vcl/inc/salgdi.hxx | 11
vcl/inc/unx/salgdi.h | 2
vcl/inc/win/salgdi.h | 1
vcl/source/gdi/salgdilayout.cxx | 5
vcl/source/outdev/gradient.cxx | 521 ++++++++++++++++++++++++++++++++-------
9 files changed, 461 insertions(+), 91 deletions(-)
New commits:
commit ad6d94009cf8ea526eb70bf1a07e5c6a21320f83
Author: Chris Sherlock <chris.sherlock79 at gmail.com>
Date: Sat Oct 25 18:51:51 2014 +1100
vcl: Allow SalGraphics to draw gradients natively
The aim of this patch is to allow for native gradient rendering in
SalGraphics (i.e. let OpenGL do this natively). It is a two step
process:
1. I need to allow gradient draw into SalGraphics, however the current
completely intertwined with the metafile code in OutputDevice. I am
seperating the gradient metafile code from the gradient drawing code.
2. After splitting the metafile stuff from the actual gradient drawing,
I am now able to call on SalGraphics::DrawGradient(). This just
calls on SalGraphics::drawGradient() which returns false if there is
no way of drawing native gradients, and true if there is. If false,
then we use OutputDevice's DrawGradient() functionality.
Change-Id: Ibaaabe13b76a8e7a037d9f751b5f662653a50566
Reviewed-on: https://gerrit.libreoffice.org/12119
Reviewed-by: Chris Sherlock <chris.sherlock79 at gmail.com>
Tested-by: Chris Sherlock <chris.sherlock79 at gmail.com>
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 30da2ea..7603351 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -833,8 +833,12 @@ protected:
private:
- SAL_DLLPRIVATE void DrawLinearGradient( const Rectangle& rRect, const Gradient& rGradient, bool bMtf, const tools::PolyPolygon* pClipPolyPoly );
- SAL_DLLPRIVATE void DrawComplexGradient( const Rectangle& rRect, const Gradient& rGradient, bool bMtf, const tools::PolyPolygon* pClipPolyPoly );
+ SAL_DLLPRIVATE void DrawLinearGradient( const Rectangle& rRect, const Gradient& rGradient, const tools::PolyPolygon* pClipPolyPoly );
+ SAL_DLLPRIVATE void DrawComplexGradient( const Rectangle& rRect, const Gradient& rGradient, const tools::PolyPolygon* pClipPolyPoly );
+
+ SAL_DLLPRIVATE void DrawGradientToMetafile( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient );
+ SAL_DLLPRIVATE void DrawLinearGradientToMetafile( const Rectangle& rRect, const Gradient& rGradient );
+ SAL_DLLPRIVATE void DrawComplexGradientToMetafile( const Rectangle& rRect, const Gradient& rGradient );
SAL_DLLPRIVATE long GetGradientSteps( const Gradient& rGradient, const Rectangle& rRect, bool bMtf, bool bComplex=false );
diff --git a/vcl/inc/generic/genpspgraphics.h b/vcl/inc/generic/genpspgraphics.h
index 2a562c3..30c8fec 100644
--- a/vcl/inc/generic/genpspgraphics.h
+++ b/vcl/inc/generic/genpspgraphics.h
@@ -148,6 +148,8 @@ public:
const sal_uInt32* pPoints,
const SalPoint* const* pPtAry,
const sal_uInt8* const* pFlgAry ) SAL_OVERRIDE;
+ virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) SAL_OVERRIDE { return false; };
+
virtual void copyArea( long nDestX,
long nDestY,
long nSrcX,
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index a872d4a..cbbac7a 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -211,6 +211,7 @@ public:
const sal_uInt32* pPoints,
const SalPoint* const* pPtAry,
const sal_uInt8* const* pFlgAry ) SAL_OVERRIDE;
+ virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) SAL_OVERRIDE { return false; };
virtual void copyArea( long nDestX,
long nDestY,
diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index 23d3bb3..eb21e09 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -237,6 +237,7 @@ public:
const ::basegfx::B2DVector& rLineWidths,
basegfx::B2DLineJoin,
com::sun::star::drawing::LineCap eLineCap) SAL_OVERRIDE;
+ virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) SAL_OVERRIDE { return false; };
// CopyArea --> No RasterOp, but ClipRegion
virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth,
diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx
index 7e06ee6..2266d87 100644
--- a/vcl/inc/salgdi.hxx
+++ b/vcl/inc/salgdi.hxx
@@ -288,6 +288,12 @@ public:
const sal_uInt8* const* pFlgAry,
const OutputDevice *pOutDev );
+ bool DrawGradient(
+ const tools::PolyPolygon& rPolyPoly,
+ const Gradient& rGradient,
+ OutputDevice* );
+
+
// CopyArea --> No RasterOp, but ClipRegion
void CopyArea(
long nDestX, long nDestY,
@@ -451,6 +457,11 @@ protected:
const SalPoint* const* pPtAry,
const sal_uInt8* const* pFlgAry ) = 0;
+
+ virtual bool drawGradient(
+ const tools::PolyPolygon& rPolyPoly,
+ const Gradient& rGradient ) = 0;
+
// CopyArea --> No RasterOp, but ClipRegion
virtual void copyArea(
long nDestX, long nDestY,
diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h
index c4eea0f..f564112 100644
--- a/vcl/inc/unx/salgdi.h
+++ b/vcl/inc/unx/salgdi.h
@@ -277,6 +277,8 @@ public:
basegfx::B2DLineJoin,
com::sun::star::drawing::LineCap) SAL_OVERRIDE;
virtual bool drawFilledTrapezoids( const ::basegfx::B2DTrapezoid*, int nTrapCount, double fTransparency );
+ virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) SAL_OVERRIDE { return false; };
+
#if 1 // TODO: remove these obselete methods
virtual bool drawPolyLineBezier( sal_uInt32 nPoints,
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index 66c5618..ca423fb 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -219,6 +219,7 @@ protected:
virtual bool drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry );
virtual bool drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry );
virtual bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry );
+ virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) SAL_OVERRIDE { return false; };
// CopyArea --> No RasterOp, but ClipRegion
virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth,
diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx
index a331f0b..599500b 100644
--- a/vcl/source/gdi/salgdilayout.cxx
+++ b/vcl/source/gdi/salgdilayout.cxx
@@ -544,6 +544,11 @@ bool SalGraphics::DrawPolyLine( const basegfx::B2DPolygon& i_rPolygon,
return bRet;
}
+bool SalGraphics::DrawGradient( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient, OutputDevice* )
+{
+ return drawGradient( rPolyPoly, rGradient );
+}
+
void SalGraphics::CopyArea( long nDestX, long nDestY,
long nSrcX, long nSrcY,
long nSrcWidth, long nSrcHeight,
diff --git a/vcl/source/outdev/gradient.cxx b/vcl/source/outdev/gradient.cxx
index f8b0b21..c018fea 100644
--- a/vcl/source/outdev/gradient.cxx
+++ b/vcl/source/outdev/gradient.cxx
@@ -50,6 +50,12 @@ void OutputDevice::DrawGradient( const tools::PolyPolygon& rPolyPoly,
if ( mbOutputClipped )
return;
+ if ( mpGraphics || AcquireGraphics() )
+ {
+ if ( mpGraphics->DrawGradient( rPolyPoly, rGradient, this ) )
+ return;
+ }
+
if ( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() )
{
if ( mnDrawMode & ( DRAWMODE_BLACKGRADIENT | DRAWMODE_WHITEGRADIENT | DRAWMODE_SETTINGSGRADIENT) )
@@ -71,27 +77,7 @@ void OutputDevice::DrawGradient( const tools::PolyPolygon& rPolyPoly,
SetGrayscaleColors( aGradient );
}
- if( mpMetaFile )
- {
- const Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
-
- if ( rPolyPoly.IsRect() )
- {
- mpMetaFile->AddAction( new MetaGradientAction( aBoundRect, aGradient ) );
- }
- else
- {
- mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) );
- mpMetaFile->AddAction( new MetaGradientExAction( rPolyPoly, rGradient ) );
-
- Push( PushFlags::CLIPREGION );
- IntersectClipRegion(vcl::Region(rPolyPoly));
- DrawGradient( aBoundRect, rGradient );
- Pop();
-
- mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) );
- }
- }
+ DrawGradientToMetafile( rPolyPoly, rGradient );
if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
return;
@@ -148,9 +134,9 @@ void OutputDevice::DrawGradient( const tools::PolyPolygon& rPolyPoly,
// if the clipping polypolygon is a rectangle, then it's the same size as the bounding of the
// polypolygon, so pass in a NULL for the clipping parameter
if( aGradient.GetStyle() == GradientStyle_LINEAR || rGradient.GetStyle() == GradientStyle_AXIAL )
- DrawLinearGradient( aRect, aGradient, false, aClipPolyPoly.IsRect() ? NULL : &aClipPolyPoly );
+ DrawLinearGradient( aRect, aGradient, aClipPolyPoly.IsRect() ? NULL : &aClipPolyPoly );
else
- DrawComplexGradient( aRect, aGradient, false, aClipPolyPoly.IsRect() ? NULL : &aClipPolyPoly );
+ DrawComplexGradient( aRect, aGradient, aClipPolyPoly.IsRect() ? NULL : &aClipPolyPoly );
}
Pop();
@@ -162,6 +148,83 @@ void OutputDevice::DrawGradient( const tools::PolyPolygon& rPolyPoly,
mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
}
+void OutputDevice::DrawGradientToMetafile ( const tools::PolyPolygon& rPolyPoly,
+ const Gradient& rGradient )
+{
+ if ( !mpMetaFile )
+ return;
+
+ if ( rPolyPoly.Count() && rPolyPoly[ 0 ].GetSize() )
+ {
+ Gradient aGradient( rGradient );
+
+ if ( mnDrawMode & ( DRAWMODE_GRAYGRADIENT | DRAWMODE_GHOSTEDGRADIENT ) )
+ {
+ SetGrayscaleColors( aGradient );
+ }
+
+ const Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
+
+ if ( rPolyPoly.IsRect() )
+ {
+ mpMetaFile->AddAction( new MetaGradientAction( aBoundRect, aGradient ) );
+ }
+ else
+ {
+ mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_BEGIN" ) );
+ mpMetaFile->AddAction( new MetaGradientExAction( rPolyPoly, rGradient ) );
+
+ Push( PushFlags::CLIPREGION );
+ IntersectClipRegion(vcl::Region(rPolyPoly));
+ DrawGradient( aBoundRect, rGradient );
+ Pop();
+
+ mpMetaFile->AddAction( new MetaCommentAction( "XGRAD_SEQ_END" ) );
+ }
+
+ if( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
+ return;
+
+ // Clip and then draw the gradient
+ 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( !mbOutputClipped )
+ {
+ tools::PolyPolygon aClipPolyPoly( ImplLogicToDevicePixel( rPolyPoly ) );
+
+ // calculate step count if necessary
+ if ( !aGradient.GetSteps() )
+ aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
+
+ if ( rPolyPoly.IsRect() )
+ {
+ // because we draw with no border line, we have to expand gradient
+ // rect to avoid missing lines on the right and bottom edge
+ aRect.Left()--;
+ aRect.Top()--;
+ aRect.Right()++;
+ aRect.Bottom()++;
+ }
+
+ // if the clipping polypolygon is a rectangle, then it's the same size as the bounding of the
+ // polypolygon, so pass in a NULL for the clipping parameter
+ if( aGradient.GetStyle() == GradientStyle_LINEAR || rGradient.GetStyle() == GradientStyle_AXIAL )
+ DrawLinearGradientToMetafile( aRect, aGradient );
+ else
+ DrawComplexGradientToMetafile( aRect, aGradient );
+ }
+ }
+ }
+ }
+}
+
namespace
{
inline sal_uInt8 GetGradientColorValue( long nValue )
@@ -177,7 +240,7 @@ namespace
void OutputDevice::DrawLinearGradient( const Rectangle& rRect,
const Gradient& rGradient,
- bool bMtf, const tools::PolyPolygon* pClipPolyPoly )
+ const tools::PolyPolygon* pClipPolyPoly )
{
// get BoundRect of rotated rectangle
Rectangle aRect;
@@ -244,10 +307,8 @@ void OutputDevice::DrawLinearGradient( const Rectangle& rRect,
nRed = (sal_uInt8)nStartRed;
nGreen = (sal_uInt8)nStartGreen;
nBlue = (sal_uInt8)nStartBlue;
- if ( bMtf )
- mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
- else
- mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
aBorderRect.Bottom() = (long)( aBorderRect.Top() + fBorder );
aRect.Top() = aBorderRect.Bottom();
@@ -256,10 +317,9 @@ void OutputDevice::DrawLinearGradient( const Rectangle& rRect,
aPoly[2] = aBorderRect.BottomRight();
aPoly[3] = aBorderRect.BottomLeft();
aPoly.Rotate( aCenter, nAngle );
- if ( bMtf )
- mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
- else
- ImplDrawPolygon( aPoly, pClipPolyPoly );
+
+ ImplDrawPolygon( aPoly, pClipPolyPoly );
+
if ( !bLinear)
{
aBorderRect = aMirrorRect;
@@ -270,14 +330,13 @@ void OutputDevice::DrawLinearGradient( const Rectangle& rRect,
aPoly[2] = aBorderRect.BottomRight();
aPoly[3] = aBorderRect.BottomLeft();
aPoly.Rotate( aCenter, nAngle );
- if ( bMtf )
- mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
- else
- ImplDrawPolygon( aPoly, pClipPolyPoly );
+
+ ImplDrawPolygon( aPoly, pClipPolyPoly );
}
}
// calculate step count
+ bool bMtf = false;
long nStepCount = GetGradientSteps( rGradient, aRect, bMtf );
// minimal three steps and maximal as max color steps
@@ -313,10 +372,8 @@ void OutputDevice::DrawLinearGradient( const Rectangle& rRect,
nGreen = GetGradientColorValue((long)fTempColor);
fTempColor = ((double)nStartBlue) * (1.0-fAlpha) + ((double)nEndBlue) * fAlpha;
nBlue = GetGradientColorValue((long)fTempColor);
- if ( bMtf )
- mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
- else
- mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
// Polygon for this color step
aRect.Top() = (long)( fGradientLine + ((double) i) * fScanInc );
@@ -326,10 +383,9 @@ void OutputDevice::DrawLinearGradient( const Rectangle& rRect,
aPoly[2] = aRect.BottomRight();
aPoly[3] = aRect.BottomLeft();
aPoly.Rotate( aCenter, nAngle );
- if ( bMtf )
- mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
- else
- ImplDrawPolygon( aPoly, pClipPolyPoly );
+
+ ImplDrawPolygon( aPoly, pClipPolyPoly );
+
if ( !bLinear )
{
aMirrorRect.Bottom() = (long)( fMirrorGradientLine - ((double) i) * fScanInc );
@@ -339,10 +395,8 @@ void OutputDevice::DrawLinearGradient( const Rectangle& rRect,
aPoly[2] = aMirrorRect.BottomRight();
aPoly[3] = aMirrorRect.BottomLeft();
aPoly.Rotate( aCenter, nAngle );
- if ( bMtf )
- mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
- else
- ImplDrawPolygon( aPoly, pClipPolyPoly );
+
+ ImplDrawPolygon( aPoly, pClipPolyPoly );
}
}
if ( !bLinear)
@@ -351,10 +405,8 @@ void OutputDevice::DrawLinearGradient( const Rectangle& rRect,
nRed = GetGradientColorValue(nEndRed);
nGreen = GetGradientColorValue(nEndGreen);
nBlue = GetGradientColorValue(nEndBlue);
- if ( bMtf )
- mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
- else
- mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
aRect.Top() = (long)( fGradientLine + ((double)nSteps) * fScanInc );
aRect.Bottom() = (long)( fMirrorGradientLine - ((double) nSteps) * fScanInc );
@@ -363,16 +415,14 @@ void OutputDevice::DrawLinearGradient( const Rectangle& rRect,
aPoly[2] = aRect.BottomRight();
aPoly[3] = aRect.BottomLeft();
aPoly.Rotate( aCenter, nAngle );
- if ( bMtf )
- mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
- else
- ImplDrawPolygon( aPoly, pClipPolyPoly );
+
+ ImplDrawPolygon( aPoly, pClipPolyPoly );
}
}
void OutputDevice::DrawComplexGradient( const Rectangle& rRect,
- const Gradient& rGradient,
- bool bMtf, const tools::PolyPolygon* pClipPolyPoly )
+ const Gradient& rGradient,
+ const tools::PolyPolygon* pClipPolyPoly )
{
// Determine if we output via Polygon or PolyPolygon
// For all rasteroperations other then Overpaint always use PolyPolygon,
@@ -398,11 +448,12 @@ void OutputDevice::DrawComplexGradient( const Rectangle& rRect,
rGradient.GetBoundRect( rRect, aRect, aCenter );
- if ( UsePolyPolygonForComplexGradient() || bMtf )
+ if ( UsePolyPolygonForComplexGradient() )
pPolyPoly.reset(new tools::PolyPolygon( 2 ));
- // last parameter - true if complex gradient, false if linear
- long nStepCount = GetGradientSteps( rGradient, rRect, bMtf, true );
+ bool bMtf = false;
+ bool bComplex = true;
+ long nStepCount = GetGradientSteps( rGradient, rRect, bMtf, bComplex );
// at least three steps and at most the number of colour differences
long nSteps = std::max( nStepCount, 2L );
@@ -438,10 +489,7 @@ void OutputDevice::DrawComplexGradient( const Rectangle& rRect,
sal_uInt8 nRed = (sal_uInt8) nStartRed, nGreen = (sal_uInt8) nStartGreen, nBlue = (sal_uInt8) nStartBlue;
bool bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
- if( bMtf )
- mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
- else
- mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
if( pPolyPoly )
{
@@ -494,10 +542,7 @@ void OutputDevice::DrawComplexGradient( const Rectangle& rRect,
pPolyPoly->Replace( pPolyPoly->GetObject( 1 ), 0 );
pPolyPoly->Replace( aPoly, 1 );
- if( bMtf )
- mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) );
- else
- ImplDrawPolyPolygon( *pPolyPoly, pClipPolyPoly );
+ ImplDrawPolyPolygon( *pPolyPoly, pClipPolyPoly );
// #107349# Set fill color _after_ geometry painting:
// pPolyPoly's geometry is the band from last iteration's
@@ -506,18 +551,12 @@ void OutputDevice::DrawComplexGradient( const Rectangle& rRect,
// full aPoly. Thus, here, we're painting the band before
// the one painted in the window outdev path below. To get
// matching colors, have to delay color setting here.
- if( bMtf )
- mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
- else
- mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
}
else
{
// #107349# Set fill color _before_ geometry painting
- if( bMtf )
- mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
- else
- mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
ImplDrawPolygon( aPoly, pClipPolyPoly );
}
@@ -540,18 +579,322 @@ void OutputDevice::DrawComplexGradient( const Rectangle& rRect,
nBlue = GetGradientColorValue( nEndBlue );
}
- if( bMtf )
- {
- mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
- mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
- }
- else
- {
- mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
- ImplDrawPolygon( rPoly, pClipPolyPoly );
- }
+ mpGraphics->SetFillColor( MAKE_SALCOLOR( nRed, nGreen, nBlue ) );
+ ImplDrawPolygon( rPoly, pClipPolyPoly );
+ }
+ }
+}
+
+void OutputDevice::DrawLinearGradientToMetafile( const Rectangle& rRect,
+ const Gradient& rGradient )
+{
+ // get BoundRect of rotated rectangle
+ Rectangle aRect;
+ Point aCenter;
+ sal_uInt16 nAngle = rGradient.GetAngle() % 3600;
+
+ rGradient.GetBoundRect( rRect, aRect, aCenter );
+
+ bool bLinear = (rGradient.GetStyle() == GradientStyle_LINEAR);
+ double fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0;
+ if ( !bLinear )
+ {
+ fBorder /= 2.0;
+ }
+ Rectangle aMirrorRect = aRect; // used in style axial
+ aMirrorRect.Top() = ( aRect.Top() + aRect.Bottom() ) / 2;
+ if ( !bLinear )
+ {
+ aRect.Bottom() = aMirrorRect.Top();
+ }
+
+ // colour-intensities of start- and finish; change if needed
+ long nFactor;
+ Color aStartCol = rGradient.GetStartColor();
+ Color aEndCol = rGradient.GetEndColor();
+ long nStartRed = aStartCol.GetRed();
+ long nStartGreen = aStartCol.GetGreen();
+ long nStartBlue = aStartCol.GetBlue();
+ long nEndRed = aEndCol.GetRed();
+ long nEndGreen = aEndCol.GetGreen();
+ long nEndBlue = aEndCol.GetBlue();
+ nFactor = rGradient.GetStartIntensity();
+ nStartRed = (nStartRed * nFactor) / 100;
+ nStartGreen = (nStartGreen * nFactor) / 100;
+ nStartBlue = (nStartBlue * nFactor) / 100;
+ nFactor = rGradient.GetEndIntensity();
+ nEndRed = (nEndRed * nFactor) / 100;
+ nEndGreen = (nEndGreen * nFactor) / 100;
+ nEndBlue = (nEndBlue * nFactor) / 100;
+
+ // gradient style axial has exchanged start and end colors
+ if ( !bLinear)
+ {
+ long nTempColor = nStartRed;
+ nStartRed = nEndRed;
+ nEndRed = nTempColor;
+ nTempColor = nStartGreen;
+ nStartGreen = nEndGreen;
+ nEndGreen = nTempColor;
+ nTempColor = nStartBlue;
+ nStartBlue = nEndBlue;
+ nEndBlue = nTempColor;
+ }
+
+ sal_uInt8 nRed;
+ sal_uInt8 nGreen;
+ sal_uInt8 nBlue;
+
+ // Create border
+ Rectangle aBorderRect = aRect;
+ Polygon aPoly( 4 );
+ if (fBorder > 0.0)
+ {
+ nRed = (sal_uInt8)nStartRed;
+ nGreen = (sal_uInt8)nStartGreen;
+ nBlue = (sal_uInt8)nStartBlue;
+
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
+
+ aBorderRect.Bottom() = (long)( aBorderRect.Top() + fBorder );
+ aRect.Top() = aBorderRect.Bottom();
+ aPoly[0] = aBorderRect.TopLeft();
+ aPoly[1] = aBorderRect.TopRight();
+ aPoly[2] = aBorderRect.BottomRight();
+ aPoly[3] = aBorderRect.BottomLeft();
+ aPoly.Rotate( aCenter, nAngle );
+
+ mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
+
+ if ( !bLinear)
+ {
+ aBorderRect = aMirrorRect;
+ aBorderRect.Top() = (long) ( aBorderRect.Bottom() - fBorder );
+ aMirrorRect.Bottom() = aBorderRect.Top();
+ aPoly[0] = aBorderRect.TopLeft();
+ aPoly[1] = aBorderRect.TopRight();
+ aPoly[2] = aBorderRect.BottomRight();
+ aPoly[3] = aBorderRect.BottomLeft();
+ aPoly.Rotate( aCenter, nAngle );
+
+ mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
+ }
+ }
+
+ bool bMtf = true;
+ long nStepCount = GetGradientSteps( rGradient, aRect, bMtf );
+
+ // minimal three steps and maximal as max color steps
+ long nAbsRedSteps = std::abs( nEndRed - nStartRed );
+ long nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
+ long nAbsBlueSteps = std::abs( nEndBlue - nStartBlue );
+ long nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
+ nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
+ long nSteps = std::min( nStepCount, nMaxColorSteps );
+ if ( nSteps < 3)
+ {
+ nSteps = 3;
+ }
+
+ double fScanInc = ((double)aRect.GetHeight()) / (double) nSteps;
+ double fGradientLine = (double)aRect.Top();
+ double fMirrorGradientLine = (double) aMirrorRect.Bottom();
+
+ double fAlpha = 0.0;
+ const double fStepsMinus1 = ((double)nSteps) - 1.0;
+ double fTempColor;
+ if ( !bLinear)
+ {
+ nSteps -= 1; // draw middle polygons as one polygon after loop to avoid gap
+ }
+ for ( long i = 0; i < nSteps; i++ )
+ {
+ // linear interpolation of color
+ fAlpha = ((double)i) / fStepsMinus1;
+ fTempColor = ((double)nStartRed) * (1.0-fAlpha) + ((double)nEndRed) * fAlpha;
+ nRed = GetGradientColorValue((long)fTempColor);
+ fTempColor = ((double)nStartGreen) * (1.0-fAlpha) + ((double)nEndGreen) * fAlpha;
+ nGreen = GetGradientColorValue((long)fTempColor);
+ fTempColor = ((double)nStartBlue) * (1.0-fAlpha) + ((double)nEndBlue) * fAlpha;
+ nBlue = GetGradientColorValue((long)fTempColor);
+
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
+
+ // Polygon for this color step
+ aRect.Top() = (long)( fGradientLine + ((double) i) * fScanInc );
+ aRect.Bottom() = (long)( fGradientLine + ( ((double) i) + 1.0 ) * fScanInc );
+ aPoly[0] = aRect.TopLeft();
+ aPoly[1] = aRect.TopRight();
+ aPoly[2] = aRect.BottomRight();
+ aPoly[3] = aRect.BottomLeft();
+ aPoly.Rotate( aCenter, nAngle );
+
+ mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
+
+ if ( !bLinear )
+ {
+ aMirrorRect.Bottom() = (long)( fMirrorGradientLine - ((double) i) * fScanInc );
+ aMirrorRect.Top() = (long)( fMirrorGradientLine - (((double) i) + 1.0)* fScanInc );
+ aPoly[0] = aMirrorRect.TopLeft();
+ aPoly[1] = aMirrorRect.TopRight();
+ aPoly[2] = aMirrorRect.BottomRight();
+ aPoly[3] = aMirrorRect.BottomLeft();
+ aPoly.Rotate( aCenter, nAngle );
+
+ mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
}
}
+ if ( !bLinear)
+ {
+ // draw middle polygon with end color
+ nRed = GetGradientColorValue(nEndRed);
+ nGreen = GetGradientColorValue(nEndGreen);
+ nBlue = GetGradientColorValue(nEndBlue);
+
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
+
+ aRect.Top() = (long)( fGradientLine + ((double)nSteps) * fScanInc );
+ aRect.Bottom() = (long)( fMirrorGradientLine - ((double) nSteps) * fScanInc );
+ aPoly[0] = aRect.TopLeft();
+ aPoly[1] = aRect.TopRight();
+ aPoly[2] = aRect.BottomRight();
+ aPoly[3] = aRect.BottomLeft();
+ aPoly.Rotate( aCenter, nAngle );
+
+ mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
+ }
+}
+
+void OutputDevice::DrawComplexGradientToMetafile( const Rectangle& rRect,
+ const Gradient& rGradient )
+{
+ // Determine if we output via Polygon or PolyPolygon
+ // For all rasteroperations other then Overpaint always use PolyPolygon,
+ // as we will get wrong results if we output multiple times on top of each other.
+ // Also for printers always use PolyPolygon, as not all printers
+ // can print polygons on top of each other.
+
+ boost::scoped_ptr<tools::PolyPolygon> pPolyPoly;
+ Rectangle aRect;
+ Point aCenter;
+ Color aStartCol( rGradient.GetStartColor() );
+ Color aEndCol( rGradient.GetEndColor() );
+ long nStartRed = ( (long) aStartCol.GetRed() * rGradient.GetStartIntensity() ) / 100;
+ long nStartGreen = ( (long) aStartCol.GetGreen() * rGradient.GetStartIntensity() ) / 100;
+ long nStartBlue = ( (long) aStartCol.GetBlue() * rGradient.GetStartIntensity() ) / 100;
+ long nEndRed = ( (long) aEndCol.GetRed() * rGradient.GetEndIntensity() ) / 100;
+ long nEndGreen = ( (long) aEndCol.GetGreen() * rGradient.GetEndIntensity() ) / 100;
+ long nEndBlue = ( (long) aEndCol.GetBlue() * rGradient.GetEndIntensity() ) / 100;
+ long nRedSteps = nEndRed - nStartRed;
+ long nGreenSteps = nEndGreen - nStartGreen;
+ long nBlueSteps = nEndBlue - nStartBlue;
+ sal_uInt16 nAngle = rGradient.GetAngle() % 3600;
+
+ rGradient.GetBoundRect( rRect, aRect, aCenter );
+
+ pPolyPoly.reset(new tools::PolyPolygon( 2 ));
+
+ // last parameter - true if complex gradient, false if linear
+ long nStepCount = GetGradientSteps( rGradient, rRect, true, true );
+
+ // at least three steps and at most the number of colour differences
+ long nSteps = std::max( nStepCount, 2L );
+ long nCalcSteps = std::abs( nRedSteps );
+ long nTempSteps = std::abs( nGreenSteps );
+ if ( nTempSteps > nCalcSteps )
+ nCalcSteps = nTempSteps;
+ nTempSteps = std::abs( nBlueSteps );
+ if ( nTempSteps > nCalcSteps )
+ nCalcSteps = nTempSteps;
+ if ( nCalcSteps < nSteps )
+ nSteps = nCalcSteps;
+ if ( !nSteps )
+ nSteps = 1;
+
+ // determine output limits and stepsizes for all directions
+ Polygon aPoly;
+ double fScanLeft = aRect.Left();
+ double fScanTop = aRect.Top();
+ double fScanRight = aRect.Right();
+ double fScanBottom = aRect.Bottom();
+ double fScanIncX = (double) aRect.GetWidth() / (double) nSteps * 0.5;
+ double fScanIncY = (double) aRect.GetHeight() / (double) nSteps * 0.5;
+
+ // all gradients are rendered as nested rectangles which shrink
+ // equally in each dimension - except for 'square' gradients
+ // which shrink to a central vertex but are not per-se square.
+ if( rGradient.GetStyle() != GradientStyle_SQUARE )
+ {
+ fScanIncY = std::min( fScanIncY, fScanIncX );
+ fScanIncX = fScanIncY;
+ }
+ sal_uInt8 nRed = (sal_uInt8) nStartRed, nGreen = (sal_uInt8) nStartGreen, nBlue = (sal_uInt8) nStartBlue;
+ bool bPaintLastPolygon( false ); // #107349# Paint last polygon only if loop has generated any output
+
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
+
+ pPolyPoly->Insert( aPoly = rRect );
+ pPolyPoly->Insert( aPoly );
+
+ // loop to output Polygone/PolyPolygone sequentially
+ for( long i = 1; i < nSteps; i++ )
+ {
+ // calculate new Polygon
+ aRect.Left() = (long)( fScanLeft += fScanIncX );
+ aRect.Top() = (long)( fScanTop += fScanIncY );
+ aRect.Right() = (long)( fScanRight -= fScanIncX );
+ aRect.Bottom() = (long)( fScanBottom -= fScanIncY );
+
+ if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
+ break;
+
+ if( rGradient.GetStyle() == GradientStyle_RADIAL || rGradient.GetStyle() == GradientStyle_ELLIPTICAL )
+ aPoly = Polygon( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
+ else
+ aPoly = Polygon( aRect );
+
+ aPoly.Rotate( aCenter, nAngle );
+
+ // adapt colour accordingly
+ const long nStepIndex = ( ( pPolyPoly ) ? i : ( i + 1 ) );
+ nRed = GetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) / nSteps ) );
+ nGreen = GetGradientColorValue( nStartGreen + ( ( nGreenSteps * nStepIndex ) / nSteps ) );
+ nBlue = GetGradientColorValue( nStartBlue + ( ( nBlueSteps * nStepIndex ) / nSteps ) );
+
+ bPaintLastPolygon = true; // #107349# Paint last polygon only if loop has generated any output
+
+ pPolyPoly->Replace( pPolyPoly->GetObject( 1 ), 0 );
+ pPolyPoly->Replace( aPoly, 1 );
+
+ mpMetaFile->AddAction( new MetaPolyPolygonAction( *pPolyPoly ) );
+
+ // #107349# Set fill color _after_ geometry painting:
+ // pPolyPoly's geometry is the band from last iteration's
+ // aPoly to current iteration's aPoly. The window outdev
+ // path (see else below), on the other hand, paints the
+ // full aPoly. Thus, here, we're painting the band before
+ // the one painted in the window outdev path below. To get
+ // matching colors, have to delay color setting here.
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
+ }
+
+ const Polygon& rPoly = pPolyPoly->GetObject( 1 );
+
+ if( !rPoly.GetBoundRect().IsEmpty() )
+ {
+ // #107349# Paint last polygon with end color only if loop
+ // has generated output. Otherwise, the current
+ // (i.e. start) color is taken, to generate _any_ output.
+ if( bPaintLastPolygon )
+ {
+ nRed = GetGradientColorValue( nEndRed );
+ nGreen = GetGradientColorValue( nEndGreen );
+ nBlue = GetGradientColorValue( nEndBlue );
+ }
+
+ mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue ), true ) );
+ mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
+ }
}
long OutputDevice::GetGradientStepCount( long nMinRect )
@@ -671,9 +1014,9 @@ void OutputDevice::AddGradientActions( const Rectangle& rRect, const Gradient& r
aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
if( aGradient.GetStyle() == GradientStyle_LINEAR || aGradient.GetStyle() == GradientStyle_AXIAL )
- DrawLinearGradient( aRect, aGradient, true, NULL );
+ DrawLinearGradientToMetafile( aRect, aGradient );
else
- DrawComplexGradient( aRect, aGradient, true, NULL );
+ DrawComplexGradientToMetafile( aRect, aGradient );
mpMetaFile->AddAction( new MetaPopAction() );
mpMetaFile = pOldMtf;
More information about the Libreoffice-commits
mailing list