#i105937# Much improved gradient support for canvas/basegfx/drawinglayer.
See http://blog.thebehrens.net/2009/07/28/hackweek-iv-canvas-convwatch/ for more background information
diff --git a/basegfx/inc/basegfx/matrix/b2dhommatrixtools.hxx b/basegfx/inc/basegfx/matrix/b2dhommatrixtools.hxx
index 0b200b8..54d961d4 100644
--- a/basegfx/inc/basegfx/matrix/b2dhommatrixtools.hxx
+++ b/basegfx/inc/basegfx/matrix/b2dhommatrixtools.hxx
@@ -36,6 +36,8 @@
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/vector/b2dvector.hxx>
namespace rtl { class OUString; }
///////////////////////////////////////////////////////////////////////////////
namespace basegfx
@@ -79,6 +81,10 @@ namespace basegfx
double getRotate() const { const_cast< DecomposedB2DHomMatrixContainer* >(this)->impCheckDecompose(); return mfRotate; }
double getShearX() const { const_cast< DecomposedB2DHomMatrixContainer* >(this)->impCheckDecompose(); return mfShearX; }
};
/// Returns a string with svg's "matrix(m00,m10,m01,m11,m02,m12)" representation
::rtl::OUString exportToSvg( const B2DHomMatrix& rMatrix );
} // end of namespace basegfx
///////////////////////////////////////////////////////////////////////////////
diff --git a/basegfx/inc/basegfx/numeric/ftools.hxx b/basegfx/inc/basegfx/numeric/ftools.hxx
index 5003ede..6cecbec 100644
--- a/basegfx/inc/basegfx/numeric/ftools.hxx
+++ b/basegfx/inc/basegfx/numeric/ftools.hxx
@@ -112,7 +112,7 @@ namespace basegfx
/** clamp given value against given minimum and maximum values
*/
template <class T> const T& clamp(const T& value, const T& minimum, const T& maximum)
template <class T> inline const T& clamp(const T& value, const T& minimum, const T& maximum)
{
if(value < minimum)
{
diff --git a/basegfx/inc/basegfx/tools/gradienttools.hxx b/basegfx/inc/basegfx/tools/gradienttools.hxx
index 0c7f2ab..dbcc5a3 100644
--- a/basegfx/inc/basegfx/tools/gradienttools.hxx
+++ b/basegfx/inc/basegfx/tools/gradienttools.hxx
@@ -37,6 +37,9 @@
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/numeric/ftools.hxx>
#include <vector>
#include <algorithm>
namespace basegfx
{
/** Gradient definition as used in ODF 1.2
@@ -78,6 +81,8 @@ namespace basegfx
{
/** Create matrix for ODF's linear gradient definition
Note that odf linear gradients are varying in y direction.
@param o_rGradientInfo
Receives the calculated texture transformation matrix (for
use with standard [0,1]x[0,1] texture coordinates)
@@ -109,7 +114,7 @@ namespace basegfx
@param rUV
Current uv coordinate. Values outside [0,1] will be
clamped.
clamped. Assumes gradient color varies along the y axis.
@param rGradInfo
Gradient info, for transformation and number of steps
@@ -129,6 +134,14 @@ namespace basegfx
/** Create matrix for ODF's axial gradient definition
Note that odf axial gradients are varying in y
direction. Note further that you can map the axial
gradient to a linear gradient (in case you want or need to
avoid an extra gradient renderer), by using
createLinearODFGradientInfo() instead, shifting the
resulting texture transformation by 0.5 to the top and
appending the same stop colors again, but mirrored.
@param o_rGradientInfo
Receives the calculated texture transformation matrix (for
use with standard [0,1]x[0,1] texture coordinates)
@@ -160,7 +173,7 @@ namespace basegfx
@param rUV
Current uv coordinate. Values outside [0,1] will be
clamped.
clamped. Assumes gradient color varies along the y axis.
@param rGradInfo
Gradient info, for transformation and number of steps
@@ -394,7 +407,6 @@ namespace basegfx
{
return getSquareGradientAlpha(rUV, rGradInfo); // only matrix setup differs
}
}
}
diff --git a/basegfx/inc/basegfx/tools/keystoplerp.hxx b/basegfx/inc/basegfx/tools/keystoplerp.hxx
new file mode 100644
index 0000000..a54b3485
--- /dev/null
+++ b/basegfx/inc/basegfx/tools/keystoplerp.hxx
@@ -0,0 +1,100 @@
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: canvastools.hxx,v $
* $Revision: 1.10 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
#ifndef _BGFX_TOOLS_KEYSTOPLERP_HXX
#define _BGFX_TOOLS_KEYSTOPLERP_HXX
#include <basegfx/numeric/ftools.hxx>
#include <vector>
namespace com{ namespace sun{ namespace star{ namespace uno {
template<typename T> class Sequence;
}}}}
namespace basegfx
{
namespace tools
{
/** Lerp in a vector of key stops
This class holds a key stop vector and provides the
functionality to lerp inside it. Useful e.g. for
multi-stop gradients, or the SMIL key time activity.
For those, given a global [0,1] lerp alpha, one need to
find the suitable bucket index from key stop vector, and
then calculate the relative alpha between the two buckets
found.
*/
class KeyStopLerp
{
public:
typedef std::pair<std::ptrdiff_t,double> ResultType;
/** Create lerper with given vector of stops
@param rKeyStops
Vector of stops, must contain at least two elements
(though preferrably more, otherwise you probably don't
need key stop lerping in the first place). All
elements must be of monotonically increasing value.
*/
explicit KeyStopLerp( const std::vector<double>& rKeyStops );
/** Create lerper with given sequence of stops
@param rKeyStops
Sequence of stops, must contain at least two elements
(though preferrably more, otherwise you probably don't
need key stop lerping in the first place). All
elements must be of monotonically increasing value.
*/
explicit KeyStopLerp( const ::com::sun::star::uno::Sequence<double>& rKeyStops );
/** Find two nearest bucket index & interpolate
@param fAlpha
Find bucket index i, with keyStops[i] < fAlpha <=
keyStops[i+1]. Return new alpha value in [0,1),
proportional to fAlpha's position between keyStops[i]
and keyStops[i+1]
*/
ResultType lerp(double fAlpha) const;
private:
std::vector<double> maKeyStops;
mutable std::ptrdiff_t mnLastIndex;
};
}
}
#endif
diff --git a/basegfx/inc/basegfx/tools/lerp.hxx b/basegfx/inc/basegfx/tools/lerp.hxx
new file mode 100644
index 0000000..590ef34
--- /dev/null
+++ b/basegfx/inc/basegfx/tools/lerp.hxx
@@ -0,0 +1,60 @@
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: lerp.hxx,v $
* $Revision: 1.6 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
#ifndef _BGFX_TOOLS_LERP_HXX
#define _BGFX_TOOLS_LERP_HXX
#include <sal/types.h>
namespace basegfx
{
namespace tools
{
/** Generic linear interpolator
@tpl ValueType
Must have operator+ and operator* defined, and should
have value semantics.
@param t
As usual, t must be in the [0,1] range
*/
template< typename ValueType > ValueType lerp( const ValueType& rFrom,
const ValueType& rTo,
double t )
{
// This is only to suppress a double->int warning. All other
// types should be okay here.
return static_cast<ValueType>( (1.0-t)*rFrom + t*rTo );
}
}
}
#endif /* _BGFX_TOOLS_LERP_HXX */
diff --git a/basegfx/prj/d.lst b/basegfx/prj/d.lst
index a58cd33..1707969 100644
--- a/basegfx/prj/d.lst
+++ b/basegfx/prj/d.lst
@@ -89,6 +89,8 @@ mkdir: %_DEST%\inc%_EXT%\basegfx\tuple
mkdir: %_DEST%\inc%_EXT%\basegfx\tools
..\inc\basegfx\tools\canvastools.hxx %_DEST%\inc%_EXT%\basegfx\tools\canvastools.hxx
..\inc\basegfx\tools\keystoplerp.hxx %_DEST%\inc%_EXT%\basegfx\tools\keystoplerp.hxx
..\inc\basegfx\tools\lerp.hxx %_DEST%\inc%_EXT%\basegfx\tools\lerp.hxx
..\inc\basegfx\tools\unopolypolygon.hxx %_DEST%\inc%_EXT%\basegfx\tools\unopolypolygon.hxx
..\inc\basegfx\tools\rectcliptools.hxx %_DEST%\inc%_EXT%\basegfx\tools\rectcliptools.hxx
..\inc\basegfx\tools\tools.hxx %_DEST%\inc%_EXT%\basegfx\tools\tools.hxx
diff --git a/basegfx/source/matrix/b2dhommatrixtools.cxx b/basegfx/source/matrix/b2dhommatrixtools.cxx
index 59a1ff4..366a08a 100644
--- a/basegfx/source/matrix/b2dhommatrixtools.cxx
+++ b/basegfx/source/matrix/b2dhommatrixtools.cxx
@@ -33,11 +33,39 @@
#include "precompiled_basegfx.hxx"
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <rtl/ustring.hxx>
#include <rtl/ustrbuf.hxx>
///////////////////////////////////////////////////////////////////////////////
namespace basegfx
{
::rtl::OUString exportToSvg( const B2DHomMatrix& rMatrix )
{
rtl::OUStringBuffer aStrBuf;
aStrBuf.appendAscii("matrix(");
aStrBuf.append(rMatrix.get(0,0));
aStrBuf.appendAscii(", ");
aStrBuf.append(rMatrix.get(1,0));
aStrBuf.appendAscii(", ");
aStrBuf.append(rMatrix.get(0,1));
aStrBuf.appendAscii(", ");
aStrBuf.append(rMatrix.get(1,1));
aStrBuf.appendAscii(", ");
aStrBuf.append(rMatrix.get(0,2));
aStrBuf.appendAscii(", ");
aStrBuf.append(rMatrix.get(1,2));
aStrBuf.appendAscii(")");
return aStrBuf.makeStringAndClear();
}
} // end of namespace basegfx
///////////////////////////////////////////////////////////////////////////////
diff --git a/basegfx/source/tools/gradienttools.cxx b/basegfx/source/tools/gradienttools.cxx
index 9e78039..337f9bd 100644
--- a/basegfx/source/tools/gradienttools.cxx
+++ b/basegfx/source/tools/gradienttools.cxx
@@ -52,6 +52,8 @@ namespace basegfx
o_rGradientInfo.maBackTextureTransform.identity();
o_rGradientInfo.mnSteps = nSteps;
fAngle = -fAngle;
double fTargetSizeX(rTargetRange.getWidth());
double fTargetSizeY(rTargetRange.getHeight());
double fTargetOffsetX(rTargetRange.getMinX());
@@ -70,7 +72,23 @@ namespace basegfx
fTargetSizeY = fNewY;
}
// add object scale before rotate
double fSizeWithoutBorder=0;
double fTranslateY=0;
if( bAxial )
{
fSizeWithoutBorder = (1.0 - fBorder) * 0.5;
fTranslateY = 0.5;
}
else
{
fSizeWithoutBorder = 1.0 - fBorder;
fTranslateY = fBorder;
}
if(!fTools::equal(fSizeWithoutBorder, 0.0))
o_rGradientInfo.maTextureTransform.scale(1.0, fSizeWithoutBorder);
o_rGradientInfo.maTextureTransform.translate(0.0, fTranslateY);
o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY);
// add texture rotate after scale to keep perpendicular angles
@@ -90,24 +108,9 @@ namespace basegfx
// prepare aspect for texture
o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0;
// build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform
// build transform from u,v to [0.0 .. 1.0].
o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform;
o_rGradientInfo.maBackTextureTransform.invert();
double fSizeWithoutBorder=0;
if( bAxial )
{
fSizeWithoutBorder = (1.0 - fBorder) * 0.5;
o_rGradientInfo.maBackTextureTransform.translate(0.0, -0.5);
}
else
{
fSizeWithoutBorder = 1.0 - fBorder;
o_rGradientInfo.maBackTextureTransform.translate(0.0, -fBorder);
}
if(!fTools::equal(fSizeWithoutBorder, 0.0))
o_rGradientInfo.maBackTextureTransform.scale(1.0, 1.0 / fSizeWithoutBorder);
}
/** Most of the setup for radial & ellipsoidal gradient is the same,
@@ -125,6 +128,8 @@ namespace basegfx
o_rGradientInfo.maBackTextureTransform.identity();
o_rGradientInfo.mnSteps = nSteps;
fAngle = -fAngle;
double fTargetSizeX(rTargetRange.getWidth());
double fTargetSizeY(rTargetRange.getHeight());
double fTargetOffsetX(rTargetRange.getMinX());
@@ -147,7 +152,11 @@ namespace basegfx
fTargetSizeY = 1.4142 * fTargetSizeY;
}
// add object scale before rotate
const double fHalfBorder((1.0 - fBorder) * 0.5);
if(!fTools::equal(fHalfBorder, 0.0))
o_rGradientInfo.maTextureTransform.scale(fHalfBorder, fHalfBorder);
o_rGradientInfo.maTextureTransform.translate(0.5, 0.5);
o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY);
if( !bCircular )
@@ -155,9 +164,8 @@ namespace basegfx
// add texture rotate after scale to keep perpendicular angles
if(0.0 != fAngle)
{
B2DPoint aCenter(0.5, 0.5);
aCenter *= o_rGradientInfo.maTextureTransform;
const B2DPoint aCenter(0.5*fTargetSizeX,
0.5*fTargetSizeY);
o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY());
o_rGradientInfo.maTextureTransform.rotate(fAngle);
o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY());
@@ -178,17 +186,9 @@ namespace basegfx
// prepare aspect for texture
o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0;
// build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform
// build transform from u,v to [0.0 .. 1.0].
o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform;
o_rGradientInfo.maBackTextureTransform.invert();
o_rGradientInfo.maBackTextureTransform.translate(-0.5, -0.5);
const double fHalfBorder((1.0 - fBorder) * 0.5);
if(!fTools::equal(fHalfBorder, 0.0))
{
const double fFactor(1.0 / fHalfBorder);
o_rGradientInfo.maBackTextureTransform.scale(fFactor, fFactor);
}
}
/** Setup for rect & square gradient is exactly the same. Factored out
@@ -205,6 +205,8 @@ namespace basegfx
o_rGradientInfo.maBackTextureTransform.identity();
o_rGradientInfo.mnSteps = nSteps;
fAngle = -fAngle;
double fTargetSizeX(rTargetRange.getWidth());
double fTargetSizeY(rTargetRange.getHeight());
double fTargetOffsetX(rTargetRange.getMinX());
@@ -223,15 +225,18 @@ namespace basegfx
fTargetSizeY = fNewY;
}
// add object scale before rotate
const double fHalfBorder((1.0 - fBorder) * 0.5);
if(!fTools::equal(fHalfBorder, 0.0))
o_rGradientInfo.maTextureTransform.scale(fHalfBorder, fHalfBorder);
o_rGradientInfo.maTextureTransform.translate(0.5, 0.5);
o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY);
// add texture rotate after scale to keep perpendicular angles
if(0.0 != fAngle)
{
B2DPoint aCenter(0.5, 0.5);
aCenter *= o_rGradientInfo.maTextureTransform;
const B2DPoint aCenter(0.5*fTargetSizeX,
0.5*fTargetSizeY);
o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY());
o_rGradientInfo.maTextureTransform.rotate(fAngle);
o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY());
@@ -254,14 +259,6 @@ namespace basegfx
// build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform
o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform;
o_rGradientInfo.maBackTextureTransform.invert();
o_rGradientInfo.maBackTextureTransform.translate(-0.5, -0.5);
const double fHalfBorder((1.0 - fBorder) * 0.5);
if(!fTools::equal(fHalfBorder, 0.0))
{
const double fFactor(1.0 / fHalfBorder);
o_rGradientInfo.maBackTextureTransform.scale(fFactor, fFactor);
}
}
namespace tools
diff --git a/basegfx/source/tools/keystoplerp.cxx b/basegfx/source/tools/keystoplerp.cxx
new file mode 100644
index 0000000..99c74a3
--- /dev/null
+++ b/basegfx/source/tools/keystoplerp.cxx
@@ -0,0 +1,104 @@
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: canvastools.hxx,v $
* $Revision: 1.10 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
#include "basegfx/tools/keystoplerp.hxx"
#include <com/sun/star/uno/Sequence.hxx>
#include <algorithm>
static void validateInput(const std::vector<double>& rKeyStops)
{
(void)rKeyStops;
#ifdef DBG_UTIL
OSL_ENSURE( rKeyStops.size() > 1,
"KeyStopLerp::KeyStopLerp(): key stop vector must have two entries or more" );
// rKeyStops must be sorted in ascending order
for( ::std::size_t i=1, len=rKeyStops.size(); i<len; ++i )
{
if( rKeyStops[i-1] > rKeyStops[i] )
OSL_ENSURE( false,
"KeyStopLerp::KeyStopLerp(): time vector is not sorted in ascending order!" );
}
#endif
}
namespace basegfx
{
namespace tools
{
KeyStopLerp::KeyStopLerp( const std::vector<double>& rKeyStops ) :
maKeyStops(rKeyStops),
mnLastIndex(0)
{
validateInput(maKeyStops);
}
KeyStopLerp::KeyStopLerp( const ::com::sun::star::uno::Sequence<double>& rKeyStops ) :
maKeyStops(rKeyStops.getLength()),
mnLastIndex(0)
{
std::copy( rKeyStops.getConstArray(),
rKeyStops.getConstArray()+rKeyStops.getLength(),
maKeyStops.begin() );
validateInput(maKeyStops);
}
KeyStopLerp::ResultType KeyStopLerp::lerp(double fAlpha) const
{
// cached value still okay?
if( maKeyStops.at(mnLastIndex) < fAlpha ||
maKeyStops.at(mnLastIndex+1) >= fAlpha )
{
// nope, find new index
mnLastIndex = std::min<std::ptrdiff_t>(
maKeyStops.size()-2,
// range is ensured by max below
std::max<std::ptrdiff_t>(
0,
std::distance( maKeyStops.begin(),
std::lower_bound( maKeyStops.begin(),
maKeyStops.end(),
fAlpha )) - 1 ));
}
// lerp between stop and stop+1
const double fRawLerp=
(fAlpha-maKeyStops.at(mnLastIndex)) /
(maKeyStops.at(mnLastIndex+1) - maKeyStops.at(mnLastIndex));
// clamp to permissible range (input fAlpha might be
// everything)
return ResultType(
mnLastIndex,
clamp(fRawLerp,0.0,1.0));
}
}
}
diff --git a/basegfx/source/tools/makefile.mk b/basegfx/source/tools/makefile.mk
index 1bede8b..d55bbae 100755
--- a/basegfx/source/tools/makefile.mk
+++ b/basegfx/source/tools/makefile.mk
@@ -44,6 +44,7 @@ ENABLE_EXCEPTIONS=TRUE
SLOFILES= $(SLO)$/canvastools.obj \
$(SLO)$/gradienttools.obj \
$(SLO)$/debugplotter.obj \
$(SLO)$/keystoplerp.obj \
$(SLO)$/liangbarsky.obj \
$(SLO)$/tools.obj \
$(SLO)$/unopolypolygon.obj
diff --git a/basegfx/test/basegfxtools.cxx b/basegfx/test/basegfxtools.cxx
new file mode 100644
index 0000000..6ace65c
--- /dev/null
+++ b/basegfx/test/basegfxtools.cxx
@@ -0,0 +1,119 @@
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: basegfx2d.cxx,v $
* $Revision: 1.14 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basegfx.hxx"
// autogenerated file with codegen.pl
#include <cppunit/simpleheader.hxx>
#include <basegfx/tools/keystoplerp.hxx>
#include <basegfx/numeric/ftools.hxx>
#include <boost/tuple/tuple.hpp>
using namespace ::basegfx;
using namespace ::boost::tuples;
namespace basegfxtools
{
class KeyStopLerpTest : public CppUnit::TestFixture
{
tools::KeyStopLerp maKeyStops;
static std::vector<double> getTestVector()
{
std::vector<double> aStops(3);
aStops[0] = 0.1;
aStops[1] = 0.5;
aStops[2] = 0.9;
return aStops;
}
public:
KeyStopLerpTest() :
maKeyStops(getTestVector())
{}
void setUp()
{}
void tearDown()
{}
void test()
{
double fAlpha;
std::ptrdiff_t nIndex;
tie(nIndex,fAlpha) = maKeyStops.lerp(-1.0);
CPPUNIT_ASSERT_MESSAGE("-1.0", nIndex==0 && fAlpha==0.0);
tie(nIndex,fAlpha) = maKeyStops.lerp(0.1);
CPPUNIT_ASSERT_MESSAGE("0.1", nIndex==0 && fAlpha==0.0);
tie(nIndex,fAlpha) = maKeyStops.lerp(0.3);
CPPUNIT_ASSERT_MESSAGE("0.3", nIndex==0 && fTools::equal(fAlpha,0.5));
tie(nIndex,fAlpha) = maKeyStops.lerp(0.5);
CPPUNIT_ASSERT_MESSAGE("0.5", nIndex==0 && fTools::equal(fAlpha,1.0));
tie(nIndex,fAlpha) = maKeyStops.lerp(0.51);
CPPUNIT_ASSERT_MESSAGE("0.51", nIndex==1 && fTools::equal(fAlpha,0.025));
tie(nIndex,fAlpha) = maKeyStops.lerp(0.9);
CPPUNIT_ASSERT_MESSAGE("0.51", nIndex==1 && fTools::equal(fAlpha,1.0));
tie(nIndex,fAlpha) = maKeyStops.lerp(1.0);
CPPUNIT_ASSERT_MESSAGE("0.51", nIndex==1 && fAlpha==1.0);
}
// Change the following lines only, if you add, remove or rename
// member functions of the current class,
// because these macros are need by auto register mechanism.
CPPUNIT_TEST_SUITE(KeyStopLerpTest);
CPPUNIT_TEST(test);
CPPUNIT_TEST_SUITE_END();
};
// -----------------------------------------------------------------------------
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(basegfxtools::KeyStopLerpTest, "basegfxtools");
} // namespace basegfxtools
// -----------------------------------------------------------------------------
// this macro creates an empty function, which will called by the RegisterAllFunctions()
// to let the user the possibility to also register some functions by hand.
// NOADDITIONAL;
diff --git a/basegfx/test/makefile.mk b/basegfx/test/makefile.mk
index 1bd4d59..bc44daf 100644
--- a/basegfx/test/makefile.mk
+++ b/basegfx/test/makefile.mk
@@ -46,6 +46,7 @@ SHL1OBJS= \
$(SLO)$/basegfx1d.obj \
$(SLO)$/basegfx2d.obj \
$(SLO)$/basegfx3d.obj \
$(SLO)$/basegfxtools.obj \
$(SLO)$/testtools.obj
# linking statically against basegfx parts
diff --git a/canvas/inc/canvas/base/graphicdevicebase.hxx b/canvas/inc/canvas/base/graphicdevicebase.hxx
index d0cd621..1105fea 100644
--- a/canvas/inc/canvas/base/graphicdevicebase.hxx
+++ b/canvas/inc/canvas/base/graphicdevicebase.hxx
@@ -33,11 +33,11 @@
#include <rtl/ref.hxx>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/util/XUpdatable.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XColorSpace.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <canvas/parametricpolypolygon.hxx>
#include <canvas/propertysethelper.hxx>
@@ -50,8 +50,7 @@ namespace canvas
/** Helper template base class for XGraphicDevice implementations.
This base class provides partial implementations of the
XGraphicDevice-related interface, such as
XParametricPolyPolygon2DFactory and XColorSpace.
XGraphicDevice-related interface, such as XColorSpace.
This template basically interposes itself between the full
interface you implement (i.e. not restricted to XGraphicDevice
@@ -249,7 +248,7 @@ namespace canvas
return maDeviceHelper.createVolatileAlphaBitmap( this, size );
}
virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2DFactory > SAL_CALL getParametricPolyPolygonFactory( ) throw (::com::sun::star::uno::RuntimeException)
virtual ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > SAL_CALL getParametricPolyPolygonFactory( ) throw (::com::sun::star::uno::RuntimeException)
{
return this;
}
@@ -268,79 +267,26 @@ namespace canvas
return maDeviceHelper.enterFullScreenMode( bEnter );
}
// XParametricPolyPolygon2DFactory
virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D > SAL_CALL createLinearHorizontalGradient( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors, const ::com::sun::star::uno::Sequence< double >& stops ) throw (::com::sun::star::lang::IllegalArgumentException,
::com::sun::star::uno::RuntimeException)
// XMultiServiceFactory
virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstance( const ::rtl::OUString& aServiceSpecifier ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
return ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D >(
ParametricPolyPolygon::createLinearHorizontalGradient( this,
colors,
stops ) );
ParametricPolyPolygon::create(this,
aServiceSpecifier,
::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >()));
}
virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D > SAL_CALL createAxialHorizontalGradient( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors, const ::com::sun::star::uno::Sequence< double >& stops ) throw (::com::sun::star::lang::IllegalArgumentException,
::com::sun::star::uno::RuntimeException)
virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstanceWithArguments( const ::rtl::OUString& aServiceSpecifier, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Arguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
return ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D >(
ParametricPolyPolygon::createAxialHorizontalGradient( this,
colors,
stops ) );
ParametricPolyPolygon::create(this,
aServiceSpecifier,
Arguments));
}
virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D > SAL_CALL createEllipticalGradient( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors, const ::com::sun::star::uno::Sequence< double >& stops, const ::com::sun::star::geometry::RealRectangle2D& boundRect ) throw (::com::sun::star::lang::IllegalArgumentException,
::com::sun::star::uno::RuntimeException)
virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getAvailableServiceNames( ) throw (::com::sun::star::uno::RuntimeException)
{
return ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D >(
ParametricPolyPolygon::createEllipticalGradient( this,
colors,
stops,
boundRect ) );
}
virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D > SAL_CALL createRectangularGradient( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors, const ::com::sun::star::uno::Sequence< double >& stops, const ::com::sun::star::geometry::RealRectangle2D& boundRect ) throw (::com::sun::star::lang::IllegalArgumentException,
::com::sun::star::uno::RuntimeException)
{
return ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D >(
ParametricPolyPolygon::createRectangularGradient( this,
colors,
stops,
boundRect ) );
}
virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D > SAL_CALL createVerticalLinesHatch( const ::com::sun::star::uno::Sequence< double >& /*leftColor*/,
const ::com::sun::star::uno::Sequence< double >& /*rightColor*/ ) throw (::com::sun::star::lang::IllegalArgumentException,
::com::sun::star::uno::RuntimeException)
{
// TODO(F1): hatch factory NYI
return ::com::sun::star::uno::Reference<
::com::sun::star::rendering::XParametricPolyPolygon2D >();
}
virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D > SAL_CALL createOrthogonalLinesHatch( const ::com::sun::star::uno::Sequence< double >& /*leftTopColor*/,
const ::com::sun::star::uno::Sequence< double >& /*rightBottomColor*/ ) throw (::com::sun::star::lang::IllegalArgumentException,
::com::sun::star::uno::RuntimeException)
{
// TODO(F1): hatch factory NYI
return ::com::sun::star::uno::Reference<
::com::sun::star::rendering::XParametricPolyPolygon2D >();
}
virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D > SAL_CALL createThreeCrossingLinesHatch( const ::com::sun::star::uno::Sequence< double >& /*startColor*/,
const ::com::sun::star::uno::Sequence< double >& /*endColor*/ ) throw (::com::sun::star::lang::IllegalArgumentException,
::com::sun::star::uno::RuntimeException)
{
// TODO(F1): hatch factory NYI
return ::com::sun::star::uno::Reference<
::com::sun::star::rendering::XParametricPolyPolygon2D >();
}
virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D > SAL_CALL createFourCrossingLinesHatch( const ::com::sun::star::uno::Sequence< double >& /*startColor*/,
const ::com::sun::star::uno::Sequence< double >& /*endColor*/ ) throw (::com::sun::star::lang::IllegalArgumentException,
::com::sun::star::uno::RuntimeException)
{
// TODO(F1): hatch factory NYI
return ::com::sun::star::uno::Reference<
::com::sun::star::rendering::XParametricPolyPolygon2D >();
return ParametricPolyPolygon::getAvailableServiceNames();
}
diff --git a/canvas/inc/canvas/canvastools.hxx b/canvas/inc/canvas/canvastools.hxx
index 3942ab2..345bcd9 100644
--- a/canvas/inc/canvas/canvastools.hxx
+++ b/canvas/inc/canvas/canvastools.hxx
@@ -417,28 +417,6 @@ namespace canvas
*/
::basegfx::B2IRange spritePixelAreaFromB2DRange( const ::basegfx::B2DRange& rRange );
/** This method clamps the given value to the specified range
@param val
The value to clamp
@param minVal
The minimal value val is allowed to attain
@param maxVal
The maximal value val is allowed to attain
@return the clamped value
*/
template< typename T > T clamp( T val,
T minVal,
T maxVal )
{
return ::std::max( minVal,
::std::min( maxVal,
val ) );
}
/** Retrieve various internal properties of the actual canvas implementation.
This method retrieves a bunch of internal, implementation-
diff --git a/canvas/inc/canvas/parametricpolypolygon.hxx b/canvas/inc/canvas/parametricpolypolygon.hxx
index 9d08831..b93f1c2 100644
--- a/canvas/inc/canvas/parametricpolypolygon.hxx
+++ b/canvas/inc/canvas/parametricpolypolygon.hxx
@@ -33,7 +33,7 @@
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2D.hpp>
#include <cppuhelper/compbase2.hxx>
#include <comphelper/broadcasthelper.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
@@ -62,7 +62,6 @@ namespace canvas
enum GradientType
{
GRADIENT_LINEAR,
GRADIENT_AXIAL,
GRADIENT_ELLIPTICAL,
GRADIENT_RECTANGULAR
};
@@ -103,24 +102,11 @@ namespace canvas
const GradientType meType;
};
static ParametricPolyPolygon* createLinearHorizontalGradient( const ::com::sun::star::uno::Reference<
::com::sun::star::rendering::XGraphicDevice >& rDevice,
const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors,
const ::com::sun::star::uno::Sequence< double >& stops );
static ParametricPolyPolygon* createAxialHorizontalGradient( const ::com::sun::star::uno::Reference<
::com::sun::star::rendering::XGraphicDevice >& rDevice,
const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors,
const ::com::sun::star::uno::Sequence< double >& stops );
static ParametricPolyPolygon* createEllipticalGradient( const ::com::sun::star::uno::Reference<
::com::sun::star::rendering::XGraphicDevice >& rDevice,
const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors,
const ::com::sun::star::uno::Sequence< double >& stops,
const ::com::sun::star::geometry::RealRectangle2D& boundRect );
static ParametricPolyPolygon* createRectangularGradient( const ::com::sun::star::uno::Reference<
::com::sun::star::rendering::XGraphicDevice >& rDevice,
const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors,
const ::com::sun::star::uno::Sequence< double >& stops,
const ::com::sun::star::geometry::RealRectangle2D& boundRect );
static ::com::sun::star::uno::Sequence< ::rtl::OUString > getAvailableServiceNames();
static ParametricPolyPolygon* create(
const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice,
const ::rtl::OUString& rServiceName,
const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& rArgs );
/// Dispose all internal references
virtual void SAL_CALL disposing();
@@ -143,6 +129,20 @@ namespace canvas
~ParametricPolyPolygon(); // we're a ref-counted UNO class. _We_ destroy ourselves.
private:
static ParametricPolyPolygon* createLinearHorizontalGradient( const ::com::sun::star::uno::Reference<
::com::sun::star::rendering::XGraphicDevice >& rDevice,
const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors,
const ::com::sun::star::uno::Sequence< double >& stops );
static ParametricPolyPolygon* createEllipticalGradient( const ::com::sun::star::uno::Reference<
::com::sun::star::rendering::XGraphicDevice >& rDevice,
const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors,
const ::com::sun::star::uno::Sequence< double >& stops,
double fAspect );
static ParametricPolyPolygon* createRectangularGradient( const ::com::sun::star::uno::Reference<
::com::sun::star::rendering::XGraphicDevice >& rDevice,
const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors,
const ::com::sun::star::uno::Sequence< double >& stops,
double fAspect );
/// Private, because objects can only be created from the static factories
ParametricPolyPolygon( const ::com::sun::star::uno::Reference<
diff --git a/canvas/source/cairo/cairo_canvas.hxx b/canvas/source/cairo/cairo_canvas.hxx
index de2b9f8..8fa56b5 100644
--- a/canvas/source/cairo/cairo_canvas.hxx
+++ b/canvas/source/cairo/cairo_canvas.hxx
@@ -44,7 +44,6 @@
#include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XBufferController.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <cppuhelper/compbase7.hxx>
#include <comphelper/uno3.hxx>
@@ -68,7 +67,7 @@ namespace cairocanvas
typedef ::cppu::WeakComponentImplHelper7< ::com::sun::star::rendering::XBitmapCanvas,
::com::sun::star::rendering::XIntegerBitmap,
::com::sun::star::rendering::XGraphicDevice,
::com::sun::star::rendering::XParametricPolyPolygon2DFactory,
::com::sun::star::lang::XMultiServiceFactory,
::com::sun::star::util::XUpdatable,
::com::sun::star::beans::XPropertySet,
::com::sun::star::lang::XServiceName > GraphicDeviceBase_Base;
diff --git a/canvas/source/cairo/cairo_canvashelper.cxx b/canvas/source/cairo/cairo_canvashelper.cxx
index 9cf2dd97..942e5ed 100644
--- a/canvas/source/cairo/cairo_canvashelper.cxx
+++ b/canvas/source/cairo/cairo_canvashelper.cxx
@@ -56,6 +56,8 @@
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/tools/canvastools.hxx>
#include <basegfx/tools/keystoplerp.hxx>
#include <basegfx/tools/lerp.hxx>
#include <comphelper/sequence.hxx>
#include <cppuhelper/compbase1.hxx>
@@ -73,6 +75,7 @@
#include "cairo_canvashelper.hxx"
#include "cairo_canvasbitmap.hxx"
#include <boost/tuple/tuple.hpp>
#include <algorithm>
using namespace ::cairo;
@@ -122,9 +125,29 @@ namespace cairocanvas
mpCairo = pSurface->getCairo();
}
static void setColor( Cairo* pCairo,
const uno::Sequence<double>& rColor )
{
if( rColor.getLength() > 3 )
{
const double alpha = rColor[3];
cairo_set_source_rgba( pCairo,
alpha*rColor[0],
alpha*rColor[1],
alpha*rColor[2],
alpha );
}
else if( rColor.getLength() == 3 )
cairo_set_source_rgb( pCairo,
rColor[0],
rColor[1],
rColor[2] );
}
void CanvasHelper::useStates( const rendering::ViewState& viewState,
const rendering::RenderState& renderState,
bool setColor )
bool bSetColor )
{
Matrix aViewMatrix;
Matrix aRenderMatrix;
@@ -158,19 +181,8 @@ namespace cairocanvas
OSL_TRACE ("render clip END");
}
if( setColor ) {
if( renderState.DeviceColor.getLength() > 3 )
cairo_set_source_rgba( mpCairo.get(),
renderState.DeviceColor [0],
renderState.DeviceColor [1],
renderState.DeviceColor [2],
renderState.DeviceColor [3] );
else if (renderState.DeviceColor.getLength() == 3)
cairo_set_source_rgb( mpCairo.get(),
renderState.DeviceColor [0],
renderState.DeviceColor [1],
renderState.DeviceColor [2] );
}
if( bSetColor )
setColor(mpCairo.get(),renderState.DeviceColor);
cairo_operator_t compositingMode( CAIRO_OPERATOR_OVER );
switch( renderState.CompositeOperation )
@@ -665,11 +677,33 @@ namespace cairocanvas
double alpha = rColor[3];
// cairo expects premultiplied alpha
cairo_pattern_add_color_stop_rgba( pPattern, stop, rColor[0]*alpha, rColor[1]*alpha, rColor[2]*alpha, alpha );
//cairo_pattern_add_color_stop_rgba( pPattern, stop, rColor[0], rColor[1], rColor[2], alpha );
}
}
}
static uno::Sequence<double> lerp(const uno::Sequence<double>& rLeft, const uno::Sequence<double>& rRight, double fAlpha)
{
if( rLeft.getLength() == 3 )
{
uno::Sequence<double> aRes(3);
aRes[0] = basegfx::tools::lerp(rLeft[0],rRight[0],fAlpha);
aRes[1] = basegfx::tools::lerp(rLeft[1],rRight[1],fAlpha);
aRes[2] = basegfx::tools::lerp(rLeft[2],rRight[2],fAlpha);
return aRes;
}
else if( rLeft.getLength() == 4 )
{
uno::Sequence<double> aRes(4);
aRes[0] = basegfx::tools::lerp(rLeft[0],rRight[0],fAlpha);
aRes[1] = basegfx::tools::lerp(rLeft[1],rRight[1],fAlpha);
aRes[2] = basegfx::tools::lerp(rLeft[2],rRight[2],fAlpha);
aRes[3] = basegfx::tools::lerp(rLeft[3],rRight[3],fAlpha);
return aRes;
}
return uno::Sequence<double>();
}
static Pattern* patternFromParametricPolyPolygon( ::canvas::ParametricPolyPolygon& rPolygon )
{
Pattern* pPattern = NULL;
@@ -678,7 +712,6 @@ namespace cairocanvas
// undef macros from vclenum.hxx which conflicts with GradientType enum values
#undef GRADIENT_LINEAR
#undef GRADIENT_AXIAL
#undef GRADIENT_ELLIPTICAL
switch( aValues.meType ) {
@@ -691,26 +724,17 @@ namespace cairocanvas
addColorStops( pPattern, aValues.maColors, aValues.maStops );
break;
// FIXME: NYI
case ::canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR:
case ::canvas::ParametricPolyPolygon::GRADIENT_AXIAL:
x0 = 0;
y0 = 0;
x1 = 1;
y1 = 0;
pPattern = cairo_pattern_create_linear( x0, y0, x1, y1 );
addColorStops( pPattern, aValues.maColors, aValues.maStops );
break;
case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL:
cx = 0.5;
cy = 0.5;
cx = 0;
cy = 0;
r0 = 0;
r1 = 0.5;
r1 = 1;
pPattern = cairo_pattern_create_radial( cx, cy, r0, cx, cy, r1 );
pPattern = cairo_pattern_create_radial( cx, cy, r0, cy, cy, r1 );
addColorStops( pPattern, aValues.maColors, aValues.maStops, true );
break;
default:
break;
}
return pPattern;
@@ -719,7 +743,8 @@ namespace cairocanvas
static void doOperation( Operation aOperation,
Cairo* pCairo,
const uno::Sequence< rendering::Texture >* pTextures,
const SurfaceProviderRef& pDevice )
const SurfaceProviderRef& pDevice,
const basegfx::B2DRange& rBounds )
{
switch( aOperation ) {
case Fill:
@@ -790,19 +815,70 @@ namespace cairocanvas
cairo_matrix_init( &aTextureMatrix,
aTransform.m00, aTransform.m10, aTransform.m01,
aTransform.m11, aTransform.m02, aTransform.m12);
Pattern* pPattern = patternFromParametricPolyPolygon( *pPolyImpl );
if( pPattern ) {
OSL_TRACE( "filling with pattern" );
if( pPolyImpl->getValues().meType == canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR )
{
// no general path gradient yet in cairo; emulate then
cairo_save( pCairo );
cairo_clip( pCairo );
cairo_transform( pCairo, &aTextureMatrix );
cairo_set_source( pCairo, pPattern );
cairo_fill( pCairo );
// fill bound rect with start color
cairo_rectangle( pCairo, rBounds.getMinX(), rBounds.getMinY(),
rBounds.getWidth(), rBounds.getHeight() );
setColor(pCairo,pPolyImpl->getValues().maColors[0]);
cairo_fill(pCairo);
cairo_transform( pCairo, &aTextureMatrix );
// longest line in gradient bound rect
const unsigned int nGradientSize(
static_cast<unsigned int>(
::basegfx::B2DVector(rBounds.getMinimum() - rBounds.getMaximum()).getLength() + 1.0 ) );
// typical number for pixel of the same color (strip size)
const unsigned int nStripSize( nGradientSize < 50 ? 2 : 4 );
// use at least three steps, and at utmost the number of color
// steps
const unsigned int nStepCount(
::std::max(
3U,
::std::min(
nGradientSize / nStripSize,
128U )) + 1 );
const uno::Sequence<double>* pColors=&pPolyImpl->getValues().maColors[0];
basegfx::tools::KeyStopLerp aLerper(pPolyImpl->getValues().maStops);
for( unsigned int i=1; i<nStepCount; ++i )
{
const double fT( i/double(nStepCount) );
std::ptrdiff_t nIndex;
double fAlpha;
boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT);
setColor(pCairo, lerp(pColors[nIndex], pColors[nIndex+1], fAlpha));
cairo_rectangle( pCairo, -1+fT, -1+fT, 2-2*fT, 2-2*fT );
cairo_fill(pCairo);
}
cairo_restore( pCairo );
}
else
{
Pattern* pPattern = patternFromParametricPolyPolygon( *pPolyImpl );
cairo_pattern_destroy( pPattern );
if( pPattern ) {
OSL_TRACE( "filling with pattern" );
cairo_save( pCairo );
cairo_transform( pCairo, &aTextureMatrix );
cairo_set_source( pCairo, pPattern );
cairo_fill( pCairo );
cairo_restore( pCairo );
cairo_pattern_destroy( pPattern );
}
}
}
}
@@ -935,7 +1011,7 @@ namespace cairocanvas
if( aOperation == Fill && pTextures ) {
cairo_set_matrix( pCairo, &aOrigMatrix );
doOperation( aOperation, pCairo, pTextures, pDevice );
doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() );
cairo_set_matrix( pCairo, &aIdentityMatrix );
}
} else {
@@ -948,7 +1024,7 @@ namespace cairocanvas
}
}
if( bOpToDo && ( aOperation != Fill || !pTextures ) )
doOperation( aOperation, pCairo, pTextures, pDevice );
doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() );
cairo_set_matrix( pCairo, &aOrigMatrix );
@@ -1171,12 +1247,12 @@ namespace cairocanvas
const rendering::ViewState& viewState,
const rendering::RenderState& renderState,
const geometry::IntegerSize2D& rSize,
bool /*bModulateColors*/,
bool bModulateColors,
bool bHasAlpha )
{
SurfaceSharedPtr pSurface=pInputSurface;
uno::Reference< rendering::XCachedPrimitive > rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
geometry::IntegerSize2D aBitmapSize = rSize;
geometry::IntegerSize2D aBitmapSize = rSize;
if( mpCairo ) {
cairo_save( mpCairo.get() );
@@ -1198,38 +1274,38 @@ namespace cairocanvas
::rtl::math::approxEqual( aMatrix.y0, 0 ) &&
basegfx::fround( rSize.Width * aMatrix.xx ) > 8 &&
basegfx::fround( rSize.Height* aMatrix.yy ) > 8 )
{
double dWidth, dHeight;
{
double dWidth, dHeight;
dWidth = basegfx::fround( rSize.Width * aMatrix.xx );
dHeight = basegfx::fround( rSize.Height* aMatrix.yy );
aBitmapSize.Width = static_cast<sal_Int32>( dWidth );
aBitmapSize.Height = static_cast<sal_Int32>( dHeight );
dWidth = basegfx::fround( rSize.Width * aMatrix.xx );
dHeight = basegfx::fround( rSize.Height* aMatrix.yy );
aBitmapSize.Width = static_cast<sal_Int32>( dWidth );
aBitmapSize.Height = static_cast<sal_Int32>( dHeight );
SurfaceSharedPtr pScaledSurface = mpSurfaceProvider->createSurface(
::basegfx::B2ISize( aBitmapSize.Width, aBitmapSize.Height ),
bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
CairoSharedPtr pCairo = pScaledSurface->getCairo();
SurfaceSharedPtr pScaledSurface = mpSurfaceProvider->createSurface(
::basegfx::B2ISize( aBitmapSize.Width, aBitmapSize.Height ),
bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
CairoSharedPtr pCairo = pScaledSurface->getCairo();
cairo_set_operator( pCairo.get(), CAIRO_OPERATOR_SOURCE );
// add 0.5px to size to avoid rounding errors in cairo, leading sometimes to random data on the image right/bottom borders
cairo_scale( pCairo.get(), (dWidth+0.5)/rSize.Width, (dHeight+0.5)/rSize.Height );
cairo_set_source_surface( pCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
cairo_paint( pCairo.get() );
cairo_set_operator( pCairo.get(), CAIRO_OPERATOR_SOURCE );
// add 0.5px to size to avoid rounding errors in cairo, leading sometimes to random data on the image right/bottom borders
cairo_scale( pCairo.get(), (dWidth+0.5)/rSize.Width, (dHeight+0.5)/rSize.Height );
cairo_set_source_surface( pCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
cairo_paint( pCairo.get() );
pSurface = pScaledSurface;
pSurface = pScaledSurface;
aMatrix.xx = aMatrix.yy = 1;
cairo_set_matrix( mpCairo.get(), &aMatrix );
aMatrix.xx = aMatrix.yy = 1;
cairo_set_matrix( mpCairo.get(), &aMatrix );
rv = uno::Reference< rendering::XCachedPrimitive >(
new CachedBitmap( pSurface, viewState, renderState,
// cast away const, need to
// change refcount (as this is
// ~invisible to client code,
// still logically const)
const_cast< rendering::XCanvas* >(pCanvas)) );
}
rv = uno::Reference< rendering::XCachedPrimitive >(
new CachedBitmap( pSurface, viewState, renderState,
// cast away const, need to
// change refcount (as this is
// ~invisible to client code,
// still logically const)
const_cast< rendering::XCanvas* >(pCanvas)) );
}
if( !bHasAlpha && mbHaveAlpha )
{
@@ -1270,7 +1346,11 @@ namespace cairocanvas
cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
cairo_rectangle( mpCairo.get(), 0, 0, aBitmapSize.Width, aBitmapSize.Height );
cairo_clip( mpCairo.get() );
cairo_paint( mpCairo.get() );
if( bModulateColors )
cairo_paint_with_alpha( mpCairo.get(), renderState.DeviceColor[3] );
else
cairo_paint( mpCairo.get() );
cairo_restore( mpCairo.get() );
} else
OSL_TRACE ("CanvasHelper called after it was disposed");
@@ -1309,15 +1389,35 @@ namespace cairocanvas
return rv;
}
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* ,
const uno::Reference< rendering::XBitmap >& /*xBitmap*/,
const rendering::ViewState& /*viewState*/,
const rendering::RenderState& /*renderState*/ )
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas,
const uno::Reference< rendering::XBitmap >& xBitmap,
const rendering::ViewState& viewState,
const rendering::RenderState& renderState )
{
// TODO(F3): Implement modulated bitmap!
#ifdef CAIRO_CANVAS_PERF_TRACE
struct timespec aTimer;
mxDevice->startPerfTrace( &aTimer );
#endif
// TODO(P1): Provide caching here.
return uno::Reference< rendering::XCachedPrimitive >(NULL);
uno::Reference< rendering::XCachedPrimitive > rv;
unsigned char* data = NULL;
bool bHasAlpha = false;
SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap, mpSurfaceProvider, data, bHasAlpha );
geometry::IntegerSize2D aSize = xBitmap->getSize();
if( pSurface ) {
rv = implDrawBitmapSurface( pCanvas, pSurface, viewState, renderState, aSize, true, bHasAlpha );
if( data )
free( data );
} else
rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
#ifdef CAIRO_CANVAS_PERF_TRACE
mxDevice->stopPerfTrace( &aTimer, "drawBitmap" );
#endif
return rv;
}
uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice()
diff --git a/canvas/source/cairo/cairo_spritecanvas.hxx b/canvas/source/cairo/cairo_spritecanvas.hxx
index bdbb42c..2109085 100644
--- a/canvas/source/cairo/cairo_spritecanvas.hxx
+++ b/canvas/source/cairo/cairo_spritecanvas.hxx
@@ -42,7 +42,6 @@
#include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XBufferController.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <cppuhelper/compbase9.hxx>
#include <comphelper/uno3.hxx>
@@ -66,7 +65,7 @@ namespace cairocanvas
typedef ::cppu::WeakComponentImplHelper9< ::com::sun::star::rendering::XSpriteCanvas,
::com::sun::star::rendering::XIntegerBitmap,
::com::sun::star::rendering::XGraphicDevice,
::com::sun::star::rendering::XParametricPolyPolygon2DFactory,
::com::sun::star::lang::XMultiServiceFactory,
::com::sun::star::rendering::XBufferController,
::com::sun::star::awt::XWindowListener,
::com::sun::star::util::XUpdatable,
diff --git a/canvas/source/null/null_spritecanvas.hxx b/canvas/source/null/null_spritecanvas.hxx
index 341f2a5..278bcd9 100644
--- a/canvas/source/null/null_spritecanvas.hxx
+++ b/canvas/source/null/null_spritecanvas.hxx
@@ -41,7 +41,7 @@
#include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XBufferController.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <cppuhelper/compbase8.hxx>
#include <comphelper/uno3.hxx>
@@ -60,7 +60,7 @@ namespace nullcanvas
typedef ::cppu::WeakComponentImplHelper8< ::com::sun::star::rendering::XSpriteCanvas,
::com::sun::star::rendering::XIntegerBitmap,
::com::sun::star::rendering::XGraphicDevice,
::com::sun::star::rendering::XParametricPolyPolygon2DFactory,
::com::sun::star::lang::XMultiServiceFactory,
::com::sun::star::rendering::XBufferController,
::com::sun::star::awt::XWindowListener,
::com::sun::star::beans::XPropertySet,
diff --git a/canvas/source/tools/parametricpolypolygon.cxx b/canvas/source/tools/parametricpolypolygon.cxx
index bfce116..222b668 100644
--- a/canvas/source/tools/parametricpolypolygon.cxx
+++ b/canvas/source/tools/parametricpolypolygon.cxx
@@ -53,6 +53,87 @@ using namespace ::com::sun::star;
namespace canvas
{
uno::Sequence<rtl::OUString> ParametricPolyPolygon::getAvailableServiceNames()
{
uno::Sequence<rtl::OUString> aRet(3);
aRet[0] = rtl::OUString::createFromAscii("LinearGradient");
aRet[1] = rtl::OUString::createFromAscii("EllipticalGradient");
aRet[2] = rtl::OUString::createFromAscii("RectangularGradient");
return aRet;
}
ParametricPolyPolygon* ParametricPolyPolygon::create(
const uno::Reference< rendering::XGraphicDevice >& rDevice,
const ::rtl::OUString& rServiceName,
const uno::Sequence< uno::Any >& rArgs )
{
uno::Sequence< uno::Sequence< double > > colorSequence(2);
uno::Sequence< double > colorStops(2);
double fAspectRatio=1.0;
// defaults
uno::Sequence< rendering::RGBColor > rgbColors(1);
rgbColors[0] = rendering::RGBColor(0,0,0);
colorSequence[0] = rDevice->getDeviceColorSpace()->convertFromRGB(rgbColors);
rgbColors[0] = rendering::RGBColor(1,1,1);
colorSequence[1] = rDevice->getDeviceColorSpace()->convertFromRGB(rgbColors);
colorStops[0] = 0;
colorStops[1] = 1;
// extract args
for( sal_Int32 i=0; i<rArgs.getLength(); ++i )
{
beans::PropertyValue aProp;
if( (rArgs[i] >>= aProp) )
{
if( aProp.Name.equalsAscii("Colors") )
{
aProp.Value >>= colorSequence;
}
else if( aProp.Name.equalsAscii("Stops") )
{
aProp.Value >>= colorStops;
}
else if( aProp.Name.equalsAscii("AspectRatio") )
{
aProp.Value >>= fAspectRatio;
}
}
}
if( rServiceName.equalsAscii("LinearGradient") )
{
return createLinearHorizontalGradient(rDevice, colorSequence, colorStops);
}
else if( rServiceName.equalsAscii("EllipticalGradient") )
{
return createEllipticalGradient(rDevice, colorSequence, colorStops, fAspectRatio);
}
else if( rServiceName.equalsAscii("RectangularGradient") )
{
return createRectangularGradient(rDevice, colorSequence, colorStops, fAspectRatio);
}
else if( rServiceName.equalsAscii("VerticalLineHatch") )
{
// TODO: NYI
}
else if( rServiceName.equalsAscii("OrthogonalLinesHatch") )
{
// TODO: NYI
}
else if( rServiceName.equalsAscii("ThreeCrossingLinesHatch") )
{
// TODO: NYI
}
else if( rServiceName.equalsAscii("FourCrossingLinesHatch") )
{
// TODO: NYI
}
return NULL;
}
ParametricPolyPolygon* ParametricPolyPolygon::createLinearHorizontalGradient(
const uno::Reference< rendering::XGraphicDevice >& rDevice,
const uno::Sequence< uno::Sequence< double > >& colors,
@@ -63,58 +144,35 @@ namespace canvas
return new ParametricPolyPolygon( rDevice, GRADIENT_LINEAR, colors, stops );
}
ParametricPolyPolygon* ParametricPolyPolygon::createAxialHorizontalGradient(
const uno::Reference< rendering::XGraphicDevice >& rDevice,
const uno::Sequence< uno::Sequence< double > >& colors,
const uno::Sequence< double >& stops )
{
// TODO(P2): hold gradient brush statically, and only setup
// the colors
return new ParametricPolyPolygon( rDevice, GRADIENT_AXIAL, colors, stops );
}
namespace
{
double calcAspectRatio( const geometry::RealRectangle2D& rBoundRect )
{
const double nWidth( rBoundRect.X2 - rBoundRect.X1 );
const double nHeight( rBoundRect.Y2 - rBoundRect.Y1 );
return ::basegfx::fTools::equalZero( nHeight ) ? 1.0 : fabs( nWidth / nHeight );
}
}
ParametricPolyPolygon* ParametricPolyPolygon::createEllipticalGradient(
const uno::Reference< rendering::XGraphicDevice >& rDevice,
const uno::Sequence< uno::Sequence< double > >& colors,
const uno::Sequence< double >& stops,
const geometry::RealRectangle2D& boundRect )
double fAspectRatio )
{
// TODO(P2): hold gradient polygon statically, and only setup
// the colors
return new ParametricPolyPolygon(
rDevice,
::basegfx::tools::createPolygonFromCircle(
::basegfx::B2DPoint( 0.5, 0.5), 0.5 ),
::basegfx::B2DPoint(0,0), 1 ),
GRADIENT_ELLIPTICAL,
colors, stops,
calcAspectRatio( boundRect ) );
colors, stops, fAspectRatio );
}
ParametricPolyPolygon* ParametricPolyPolygon::createRectangularGradient( const uno::Reference< rendering::XGraphicDevice >& rDevice,
const uno::Sequence< uno::Sequence< double > >& colors,
const uno::Sequence< double >& stops,
const geometry::RealRectangle2D& boundRect )
double fAspectRatio )
{
// TODO(P2): hold gradient polygon statically, and only setup
// the colors
return new ParametricPolyPolygon(
rDevice,
::basegfx::tools::createPolygonFromRect(
::basegfx::B2DRectangle( 0.0, 0.0, 1.0, 1.0 ) ),
::basegfx::B2DRectangle( -1, -1, 1, 1 ) ),
GRADIENT_RECTANGULAR,
colors, stops,
calcAspectRatio( boundRect ) );
colors, stops, fAspectRatio );
}
void SAL_CALL ParametricPolyPolygon::disposing()
diff --git a/canvas/source/vcl/canvas.hxx b/canvas/source/vcl/canvas.hxx
index 2279f81..c4e1a28 100644
--- a/canvas/source/vcl/canvas.hxx
+++ b/canvas/source/vcl/canvas.hxx
@@ -41,7 +41,6 @@
#include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XBufferController.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <cppuhelper/compbase7.hxx>
#include <comphelper/uno3.hxx>
@@ -63,7 +62,7 @@ namespace vclcanvas
typedef ::cppu::WeakComponentImplHelper7< ::com::sun::star::rendering::XBitmapCanvas,
::com::sun::star::rendering::XIntegerBitmap,
::com::sun::star::rendering::XGraphicDevice,
::com::sun::star::rendering::XParametricPolyPolygon2DFactory,
::com::sun::star::lang::XMultiServiceFactory,
::com::sun::star::util::XUpdatable,
::com::sun::star::beans::XPropertySet,
::com::sun::star::lang::XServiceName > GraphicDeviceBase_Base;
diff --git a/canvas/source/vcl/canvashelper_texturefill.cxx b/canvas/source/vcl/canvashelper_texturefill.cxx
index 571a8c4..5219c63 100644
--- a/canvas/source/vcl/canvashelper_texturefill.cxx
+++ b/canvas/source/vcl/canvashelper_texturefill.cxx
@@ -57,6 +57,8 @@
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dlinegeometry.hxx>
#include <basegfx/tools/tools.hxx>
#include <basegfx/tools/lerp.hxx>
#include <basegfx/tools/keystoplerp.hxx>
#include <basegfx/tools/canvastools.hxx>
#include <basegfx/numeric/ftools.hxx>
@@ -65,6 +67,9 @@
#include <canvas/canvastools.hxx>
#include <canvas/parametricpolypolygon.hxx>
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>
#include "spritecanvas.hxx"
#include "canvashelper.hxx"
#include "impltools.hxx"
@@ -118,17 +123,13 @@ namespace vclcanvas
Since most of the code for linear and axial gradients are
the same, we've a unified method here
*/
void fillGeneralLinearGradient( OutputDevice& rOutDev,
const ::basegfx::B2DHomMatrix& rTextureTransform,
const ::Rectangle& rBounds,
int nStepCount,
const ::Color& rColor1,
const ::Color& rColor2,
bool bFillNonOverlapping,
bool bAxialGradient )
void fillLinearGradient( OutputDevice& rOutDev,
const ::basegfx::B2DHomMatrix& rTextureTransform,
const ::Rectangle& rBounds,
unsigned int nStepCount,
const ::canvas::ParametricPolyPolygon::Values& rValues,
const std::vector< ::Color >& rColors )
{
(void)bFillNonOverlapping;
// determine general position of gradient in relation to
// the bound rect
// =====================================================
@@ -207,36 +208,26 @@ namespace vclcanvas
// iteratively render all other strips
// -----------------------------------
// ensure that nStepCount is odd, to have a well-defined
// middle index for axial gradients.
if( bAxialGradient && !(nStepCount % 2) )
// ensure that nStepCount matches color stop parity, to
// have a well-defined middle color e.g. for axial
// gradients.
if( (rColors.size() % 2) != (nStepCount % 2) )
++nStepCount;
const int nStepCountHalved( nStepCount / 2 );
basegfx::tools::KeyStopLerp aLerper(rValues.maStops);
// only iterate nStepCount-1 steps, as the last strip is
// explicitely painted below
for( int i=0; i<nStepCount-1; ++i )
for( unsigned int i=0; i<nStepCount-1; ++i )
{
// lerp color
if( bAxialGradient )
{
// axial gradient has a triangle-like interpolation function
const int iPrime( i<=nStepCountHalved ? i : nStepCount-i-1);
std::ptrdiff_t nIndex;
double fAlpha;
boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(double(i)/nStepCount);
rOutDev.SetFillColor(
Color( (UINT8)(((nStepCountHalved - iPrime)*rColor1.GetRed() + iPrime*rColor2.GetRed())/nStepCountHalved),
(UINT8)(((nStepCountHalved - iPrime)*rColor1.GetGreen() + iPrime*rColor2.GetGreen())/nStepCountHalved),
(UINT8)(((nStepCountHalved - iPrime)*rColor1.GetBlue() + iPrime*rColor2.GetBlue())/nStepCountHalved) ) );
}
else
{
// linear gradient has a plain lerp between start and end color
rOutDev.SetFillColor(
Color( (UINT8)(((nStepCount - i)*rColor1.GetRed() + i*rColor2.GetRed())/nStepCount),
(UINT8)(((nStepCount - i)*rColor1.GetGreen() + i*rColor2.GetGreen())/nStepCount),
(UINT8)(((nStepCount - i)*rColor1.GetBlue() + i*rColor2.GetBlue())/nStepCount) ) );
}
rOutDev.SetFillColor(
Color( (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetRed(),rColors[nIndex+1].GetRed(),fAlpha)),
(UINT8)(basegfx::tools::lerp(rColors[nIndex].GetGreen(),rColors[nIndex+1].GetGreen(),fAlpha)),
(UINT8)(basegfx::tools::lerp(rColors[nIndex].GetBlue(),rColors[nIndex+1].GetBlue(),fAlpha)) ));
// copy right egde of polygon to left edge (and also
// copy the closing point)
@@ -283,59 +274,18 @@ namespace vclcanvas
aTempPoly[3] = ::Point( ::basegfx::fround( rPoint4.getX() ),
::basegfx::fround( rPoint4.getY() ) );
if( bAxialGradient )
rOutDev.SetFillColor( rColor1 );
else
rOutDev.SetFillColor( rColor2 );
rOutDev.SetFillColor( rColors.back() );
rOutDev.DrawPolygon( aTempPoly );
}
inline void fillLinearGradient( OutputDevice& rOutDev,
const ::Color& rColor1,
const ::Color& rColor2,
const ::basegfx::B2DHomMatrix& rTextureTransform,
const ::Rectangle& rBounds,
int nStepCount,
bool bFillNonOverlapping )
{
fillGeneralLinearGradient( rOutDev,
rTextureTransform,
rBounds,
nStepCount,
rColor1,
rColor2,
bFillNonOverlapping,
false );
}
inline void fillAxialGradient( OutputDevice& rOutDev,
const ::Color& rColor1,
const ::Color& rColor2,
const ::basegfx::B2DHomMatrix& rTextureTransform,
const ::Rectangle& rBounds,
int nStepCount,
bool bFillNonOverlapping )
{
fillGeneralLinearGradient( rOutDev,
rTextureTransform,
rBounds,
nStepCount,
rColor1,
rColor2,
bFillNonOverlapping,
true );
}
void fillPolygonalGradient( OutputDevice& rOutDev,
const ::canvas::ParametricPolyPolygon::Values& rValues,
const ::Color& rColor1,
const ::Color& rColor2,
const ::basegfx::B2DHomMatrix& rTextureTransform,
const ::Rectangle& rBounds,
int nStepCount,
bool bFillNonOverlapping )
unsigned int nStepCount,
bool bFillNonOverlapping,
const ::canvas::ParametricPolyPolygon::Values& rValues,
const std::vector< ::Color >& rColors )
{
const ::basegfx::B2DPolygon& rGradientPoly( rValues.maGradientPoly );
@@ -369,9 +319,6 @@ namespace vclcanvas
// apply scaling (possibly anisotrophic) to inner polygon
// ------------------------------------------------------
// move center of scaling to origin
aInnerPolygonTransformMatrix.translate( -0.5, -0.5 );
// scale inner polygon according to aspect ratio: for
// wider-than-tall bounds (nAspectRatio > 1.0), the inner
// polygon, representing the gradient focus, must have
@@ -396,9 +343,6 @@ namespace vclcanvas
aInnerPolygonTransformMatrix.scale( 0.0, 0.0 );
}
// move origin back to former center of polygon
aInnerPolygonTransformMatrix.translate( 0.5, 0.5 );
// and finally, add texture transform to it.
aInnerPolygonTransformMatrix *= rTextureTransform;
@@ -406,8 +350,8 @@ namespace vclcanvas
aInnerPoly.transform( aInnerPolygonTransformMatrix );
const sal_Int32 nNumPoints( aOuterPoly.count() );
::Polygon aTempPoly( static_cast<USHORT>(nNumPoints+1) );
const sal_uInt32 nNumPoints( aOuterPoly.count() );
::Polygon aTempPoly( static_cast<USHORT>(nNumPoints+1) );
// increase number of steps by one: polygonal gradients have
// the outermost polygon rendered in rColor2, and the
@@ -425,37 +369,42 @@ namespace vclcanvas
// color).
++nStepCount;
basegfx::tools::KeyStopLerp aLerper(rValues.maStops);
if( !bFillNonOverlapping )
{
// fill background
rOutDev.SetFillColor( rColor1 );
rOutDev.SetFillColor( rColors.front() );
rOutDev.DrawRect( rBounds );
// render polygon
// ==============
for( int i=1,p; i<nStepCount; ++i )
for( unsigned int i=1,p; i<nStepCount; ++i )
{
const double fT( i/double(nStepCount) );
std::ptrdiff_t nIndex;
double fAlpha;
boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT);
// lerp color
rOutDev.SetFillColor(
Color( (UINT8)(((nStepCount - i)*rColor1.GetRed() + i*rColor2.GetRed())/nStepCount),
(UINT8)(((nStepCount - i)*rColor1.GetGreen() + i*rColor2.GetGreen())/nStepCount),
(UINT8)(((nStepCount - i)*rColor1.GetBlue() + i*rColor2.GetBlue())/nStepCount) ) );
Color( (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetRed(),rColors[nIndex+1].GetRed(),fAlpha)),
(UINT8)(basegfx::tools::lerp(rColors[nIndex].GetGreen(),rColors[nIndex+1].GetGreen(),fAlpha)),
(UINT8)(basegfx::tools::lerp(rColors[nIndex].GetBlue(),rColors[nIndex+1].GetBlue(),fAlpha)) ));
// scale and render polygon, by interpolating between
// outer and inner polygon.
// calc interpolation parameter in [0,1] range
const double nT( (nStepCount-i)/double(nStepCount) );
for( p=0; p<nNumPoints; ++p )
{
const ::basegfx::B2DPoint& rOuterPoint( aOuterPoly.getB2DPoint(p) );
const ::basegfx::B2DPoint& rInnerPoint( aInnerPoly.getB2DPoint(p) );
aTempPoly[(USHORT)p] = ::Point(
basegfx::fround( (1.0-nT)*rInnerPoint.getX() + nT*rOuterPoint.getX() ),
basegfx::fround( (1.0-nT)*rInnerPoint.getY() + nT*rOuterPoint.getY() ) );
basegfx::fround( fT*rInnerPoint.getX() + (1-fT)*rOuterPoint.getX() ),
basegfx::fround( fT*rInnerPoint.getY() + (1-fT)*rOuterPoint.getY() ) );
}
// close polygon explicitely
@@ -489,13 +438,19 @@ namespace vclcanvas
aTempPolyPoly.Insert( aTempPoly );
aTempPolyPoly.Insert( aTempPoly2 );
for( int i=0,p; i<nStepCount; ++i )
for( unsigned int i=0,p; i<nStepCount; ++i )
{
const double fT( (i+1)/double(nStepCount) );
std::ptrdiff_t nIndex;
double fAlpha;
boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT);
// lerp color
rOutDev.SetFillColor(
Color( (UINT8)(((nStepCount - i)*rColor1.GetRed() + i*rColor2.GetRed())/nStepCount),
(UINT8)(((nStepCount - i)*rColor1.GetGreen() + i*rColor2.GetGreen())/nStepCount),
(UINT8)(((nStepCount - i)*rColor1.GetBlue() + i*rColor2.GetBlue())/nStepCount) ) );
Color( (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetRed(),rColors[nIndex+1].GetRed(),fAlpha)),
(UINT8)(basegfx::tools::lerp(rColors[nIndex].GetGreen(),rColors[nIndex+1].GetGreen(),fAlpha)),
(UINT8)(basegfx::tools::lerp(rColors[nIndex].GetBlue(),rColors[nIndex+1].GetBlue(),fAlpha)) ));
#if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0
if( i && !(i % 10) )
@@ -506,17 +461,14 @@ namespace vclcanvas
// calculate the inner polygon, which is actually the
// start of the _next_ color strip. Thus, i+1
// calc interpolation parameter in [0,1] range
const double nT( (nStepCount-i-1)/double(nStepCount) );
for( p=0; p<nNumPoints; ++p )
{
const ::basegfx::B2DPoint& rOuterPoint( aOuterPoly.getB2DPoint(p) );
const ::basegfx::B2DPoint& rInnerPoint( aInnerPoly.getB2DPoint(p) );
aTempPoly[(USHORT)p] = ::Point(
basegfx::fround( (1.0-nT)*rInnerPoint.getX() + nT*rOuterPoint.getX() ),
basegfx::fround( (1.0-nT)*rInnerPoint.getY() + nT*rOuterPoint.getY() ) );
basegfx::fround( fT*rInnerPoint.getX() + (1-fT)*rOuterPoint.getX() ),
basegfx::fround( fT*rInnerPoint.getY() + (1-fT)*rOuterPoint.getY() ) );
}
// close polygon explicitely
@@ -549,46 +501,33 @@ namespace vclcanvas
void doGradientFill( OutputDevice& rOutDev,
const ::canvas::ParametricPolyPolygon::Values& rValues,
const ::Color& rColor1,
const ::Color& rColor2,
const std::vector< ::Color >& rColors,
const ::basegfx::B2DHomMatrix& rTextureTransform,
const ::Rectangle& rBounds,
int nStepCount,
unsigned int nStepCount,
bool bFillNonOverlapping )
{
switch( rValues.meType )
{
case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR:
fillLinearGradient( rOutDev,
rColor1,
rColor2,
rTextureTransform,
rBounds,
nStepCount,
bFillNonOverlapping );
break;
case ::canvas::ParametricPolyPolygon::GRADIENT_AXIAL:
fillAxialGradient( rOutDev,
rColor1,
rColor2,
rTextureTransform,
rBounds,
nStepCount,
bFillNonOverlapping );
rValues,
rColors );
break;
case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL:
// FALLTHROUGH intended
case ::canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR:
fillPolygonalGradient( rOutDev,
rValues,
rColor1,
rColor2,
rTextureTransform,
rBounds,
nStepCount,
bFillNonOverlapping );
bFillNonOverlapping,
rValues,
rColors );
break;
default:
@@ -597,11 +536,19 @@ namespace vclcanvas
}
}
int numColorSteps( const ::Color& rColor1, const ::Color& rColor2 )
{
return ::std::max(
labs( rColor1.GetRed() - rColor2.GetRed() ),
::std::max(
labs( rColor1.GetGreen() - rColor2.GetGreen() ),
labs( rColor1.GetBlue() - rColor2.GetBlue() ) ) );
}
bool gradientFill( OutputDevice& rOutDev,
OutputDevice* p2ndOutDev,
const ::canvas::ParametricPolyPolygon::Values& rValues,
const ::Color& rColor1,
const ::Color& rColor2,
const std::vector< ::Color >& rColors,
const PolyPolygon& rPoly,
const rendering::ViewState& viewState,
const rendering::RenderState& renderState,
@@ -646,12 +593,9 @@ namespace vclcanvas
// calc step size
// --------------
const int nColorSteps(
::std::max(
labs( rColor1.GetRed() - rColor2.GetRed() ),
::std::max(
labs( rColor1.GetGreen() - rColor2.GetGreen() ),
labs( rColor1.GetBlue() - rColor2.GetBlue() ) ) ) );
int nColorSteps = 0;
for( size_t i=0; i<rColors.size()-1; ++i )
nColorSteps += numColorSteps(rColors[i],rColors[i+1]);
// longest line in gradient bound rect
const int nGradientSize(
@@ -690,8 +634,7 @@ namespace vclcanvas
rOutDev.IntersectClipRegion( aPolygonDeviceRectOrig );
doGradientFill( rOutDev,
rValues,
rColor1,
rColor2,
rColors,
aTextureTransform,
aPolygonDeviceRectOrig,
nStepCount,
@@ -704,8 +647,7 @@ namespace vclcanvas
p2ndOutDev->IntersectClipRegion( aPolygonDeviceRectOrig );
doGradientFill( *p2ndOutDev,
rValues,
rColor1,
rColor2,
rColors,
aTextureTransform,
aPolygonDeviceRectOrig,
nStepCount,
@@ -723,8 +665,7 @@ namespace vclcanvas
doGradientFill( rOutDev,
rValues,
rColor1,
rColor2,
rColors,
aTextureTransform,
aPolygonDeviceRectOrig,
nStepCount,
@@ -737,8 +678,7 @@ namespace vclcanvas
p2ndOutDev->SetClipRegion( aPolyClipRegion );
doGradientFill( *p2ndOutDev,
rValues,
rColor1,
rColor2,
rColors,
aTextureTransform,
aPolygonDeviceRectOrig,
nStepCount,
@@ -753,8 +693,7 @@ namespace vclcanvas
rOutDev.SetRasterOp( ROP_XOR );
doGradientFill( rOutDev,
rValues,
rColor1,
rColor2,
rColors,
aTextureTransform,
aPolygonDeviceRectOrig,
nStepCount,
@@ -765,8 +704,7 @@ namespace vclcanvas
rOutDev.SetRasterOp( ROP_XOR );
doGradientFill( rOutDev,
rValues,
rColor1,
rColor2,
rColors,
aTextureTransform,
aPolygonDeviceRectOrig,
nStepCount,
@@ -779,8 +717,7 @@ namespace vclcanvas
p2ndOutDev->SetRasterOp( ROP_XOR );
doGradientFill( *p2ndOutDev,
rValues,
rColor1,
rColor2,
rColors,
aTextureTransform,
aPolygonDeviceRectOrig,
nStepCount,
@@ -791,8 +728,7 @@ namespace vclcanvas
p2ndOutDev->SetRasterOp( ROP_XOR );
doGradientFill( *p2ndOutDev,
rValues,
rColor1,
rColor2,
rColors,
aTextureTransform,
aPolygonDeviceRectOrig,
nStepCount,
@@ -855,33 +791,41 @@ namespace vclcanvas
::canvas::ParametricPolyPolygon* pGradient =
dynamic_cast< ::canvas::ParametricPolyPolygon* >( textures[0].Gradient.get() );
if( pGradient )
if( pGradient && pGradient->getValues().maColors.getLength() )
{
// copy state from Gradient polypoly locally
// (given object might change!)
const ::canvas::ParametricPolyPolygon::Values& rValues(
pGradient->getValues() );
// TODO: use all the colors and place them on given positions/stops
const ::Color aColor1(
::vcl::unotools::stdColorSpaceSequenceToColor(
rValues.maColors [0] ) );
const ::Color aColor2(
::vcl::unotools::stdColorSpaceSequenceToColor(
rValues.maColors [rValues.maColors.getLength () - 1] ) );
if( rValues.maColors.getLength() < 2 )
{
rendering::RenderState aTempState=renderState;
aTempState.DeviceColor = rValues.maColors[0];
fillPolyPolygon(pCanvas, xPolyPolygon, viewState, aTempState);
}
else
{
std::vector< ::Color > aColors(rValues.maColors.getLength());
std::transform(&rValues.maColors[0],
&rValues.maColors[0]+rValues.maColors.getLength(),
aColors.begin(),
boost::bind(
&vcl::unotools::stdColorSpaceSequenceToColor,
_1));
// TODO(E1): Return value
// TODO(F1): FillRule
gradientFill( mpOutDev->getOutDev(),
mp2ndOutDev.get() ? &mp2ndOutDev->getOutDev() : (OutputDevice*)NULL,
rValues,
aColor1,
aColor2,
aPolyPoly,
viewState,
renderState,
textures[0],
nTransparency );
// TODO(E1): Return value
// TODO(F1): FillRule
gradientFill( mpOutDev->getOutDev(),
mp2ndOutDev.get() ? &mp2ndOutDev->getOutDev() : (OutputDevice*)NULL,
rValues,
aColors,
aPolyPoly,
viewState,
renderState,
textures[0],
nTransparency );
}
}
else
{
diff --git a/canvas/source/vcl/spritecanvas.hxx b/canvas/source/vcl/spritecanvas.hxx
index 545eeee..66762bc 100644
--- a/canvas/source/vcl/spritecanvas.hxx
+++ b/canvas/source/vcl/spritecanvas.hxx
@@ -42,7 +42,6 @@
#include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XBufferController.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <cppuhelper/compbase9.hxx>
#include <comphelper/uno3.hxx>
@@ -65,7 +64,7 @@ namespace vclcanvas
typedef ::cppu::WeakComponentImplHelper9< ::com::sun::star::rendering::XSpriteCanvas,
::com::sun::star::rendering::XIntegerBitmap,
::com::sun::star::rendering::XGraphicDevice,
::com::sun::star::rendering::XParametricPolyPolygon2DFactory,
::com::sun::star::lang::XMultiServiceFactory,
::com::sun::star::rendering::XBufferController,
::com::sun::star::awt::XWindowListener,
::com::sun::star::util::XUpdatable,
diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx
index c6f9a29..daef89b 100644
--- a/cppcanvas/source/mtfrenderer/implrenderer.cxx
+++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx
@@ -49,7 +49,6 @@
#include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/TexturingMode.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/geometry/RealPoint2D.hpp>
#include <com/sun/star/rendering/ViewState.hpp>
@@ -61,6 +60,7 @@
#include <com/sun/star/rendering/PathJoinType.hpp>
#include <basegfx/tools/canvastools.hxx>
#include <basegfx/tools/gradienttools.hxx>
#include <basegfx/numeric/ftools.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
@@ -590,13 +590,12 @@ namespace cppcanvas
// discernible difference should be visible.
nSteps > 64 )
{
uno::Reference< rendering::XParametricPolyPolygon2DFactory > xFactory(
uno::Reference< lang::XMultiServiceFactory> xFactory(
rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
if( xFactory.is() )
{
::basegfx::B2DHomMatrix aTextureTransformation;
rendering::Texture aTexture;
rendering::Texture aTexture;
aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
@@ -631,242 +630,118 @@ namespace cppcanvas
uno::Sequence< uno::Sequence < double > > aColors(2);
uno::Sequence< double > aStops(2);
aStops[0] = 0.0;
aStops[1] = 1.0;
if( rGradient.GetStyle() == GRADIENT_AXIAL )
{
aStops.realloc(3);
aColors.realloc(3);
aColors[0] = aStartColor;
aColors[1] = aEndColor;
aStops[0] = 0.0;
aStops[1] = 0.5;
aStops[2] = 1.0;
aColors[0] = aEndColor;
aColors[1] = aStartColor;
aColors[2] = aEndColor;
}
else
{
aStops[0] = 0.0;
aStops[1] = 1.0;
// Setup texture transformation
// ----------------------------
aColors[0] = aStartColor;
aColors[1] = aEndColor;
}
const ::basegfx::B2DRectangle aBounds(
::basegfx::tools::getRange(aDevicePoly) );
const ::basegfx::B2DVector aOffset(
rGradient.GetOfsX() / 100.0,
rGradient.GetOfsY() / 100.0);
double fRotation( rGradient.GetAngle() * M_PI / 1800.0 );
const double fBorder( rGradient.GetBorder() / 100.0 );
// setup rotation angle. VCL rotates
// counter-clockwise, while canvas transformation
// rotates clockwise
double nRotation( -rGradient.GetAngle() * M_PI / 1800.0 );
basegfx::B2DHomMatrix aRot90;
aRot90.rotate(M_PI_2);
basegfx::ODFGradientInfo aGradInfo;
rtl::OUString aGradientService;
switch( rGradient.GetStyle() )
{
case GRADIENT_LINEAR:
// FALLTHROUGH intended
basegfx::tools::createLinearODFGradientInfo(aGradInfo,
aBounds,
nSteps,
fBorder,
fRotation);
// map odf to svg gradient orientation - x
// instead of y direction
aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aRot90;
aGradientService = rtl::OUString::createFromAscii("LinearGradient");
break;
case GRADIENT_AXIAL:
{
// standard orientation for VCL linear
// gradient is vertical, thus, rotate 90
// degrees
nRotation += M_PI/2.0;
basegfx::tools::createLinearODFGradientInfo(aGradInfo,
aBounds,
nSteps,
fBorder,
fRotation);
// map odf to svg gradient orientation - x
// instead of y direction
aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aRot90;
const double nBorder(
::basegfx::pruneScaleValue(
(1.0 - rGradient.GetBorder() / 100.0) ) );
// map odf axial gradient to 3-stop linear
// gradient - shift left by 0.5
basegfx::B2DHomMatrix aShift;
aShift.translate(-0.5,0);
aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aShift;
// shrink texture, to account for border
// (only in x direction, linear gradient
// is constant in y direction, anyway)
aTextureTransformation.scale( nBorder,
1.0 );
// linear gradients don't respect offsets
// (they are implicitely assumed to be
// 50%). linear gradients don't have
// border on both sides, only on the
// startColor side, axial gradients have
// border on both sides. As both gradients
// are invariant in y direction: leave y
// offset alone.
double nOffsetX( rGradient.GetBorder() / 200.0 );
// determine type of gradient (and necessary
// transformation matrix, should it be emulated by a
// generic gradient)
switch( rGradient.GetStyle() )
{
case GRADIENT_LINEAR:
nOffsetX = rGradient.GetBorder() / 100.0;
aTexture.Gradient = xFactory->createLinearHorizontalGradient( aColors,
aStops );
break;
case GRADIENT_AXIAL:
// vcl considers center color as start color
::std::swap(aColors[0],aColors[1]);
aTexture.Gradient = xFactory->createAxialHorizontalGradient( aColors,
aStops );
break;
default: // other cases can't happen
break;
}
// apply border offset values
aTextureTransformation.translate( nOffsetX,
0.0 );
// rotate texture according to gradient rotation
aTextureTransformation.translate( -0.5, -0.5 );
aTextureTransformation.rotate( nRotation );
// to let the first strip of a rotated
// gradient start at the _edge_ of the
// bound rect (and not, due to rotation,
// slightly inside), slightly enlarge the
// gradient:
//
// y/2 sin(alpha) + x/2 cos(alpha)
//
// (values to change are not actual
// gradient scales, but original bound
// rect dimensions. Since we still want
// the border setting to apply after that,
// we multiply with that as above for
// nScaleX)
const double nScale(
::basegfx::pruneScaleValue(
fabs( aBounds.getHeight()*sin(nRotation) ) +
fabs( aBounds.getWidth()*cos(nRotation) )));
aTextureTransformation.scale( nScale, nScale );
// translate back origin to center of
// primitive
aTextureTransformation.translate( 0.5*aBounds.getWidth(),
0.5*aBounds.getHeight() );
aGradientService = rtl::OUString::createFromAscii("LinearGradient");
break;
}
break;
case GRADIENT_RADIAL:
// FALLTHROUGH intended
basegfx::tools::createRadialODFGradientInfo(aGradInfo,
aBounds,
aOffset,
nSteps,
fBorder);
aGradientService = rtl::OUString::createFromAscii("EllipticalGradient");
break;
case GRADIENT_ELLIPTICAL:
// FALLTHROUGH intended
basegfx::tools::createEllipticalODFGradientInfo(aGradInfo,
aBounds,
aOffset,
nSteps,
fBorder,
fRotation);
aGradientService = rtl::OUString::createFromAscii("EllipticalGradient");
break;
case GRADIENT_SQUARE:
// FALLTHROUGH intended
basegfx::tools::createSquareODFGradientInfo(aGradInfo,
aBounds,
aOffset,
nSteps,
fBorder,
fRotation);
aGradientService = rtl::OUString::createFromAscii("RectangularGradient");
break;
case GRADIENT_RECT:
{
// determine scale factors for the gradient (must
// be scaled up from [0,1]x[0,1] rect to object
// bounds). Will potentially changed in switch
// statement below.
// Respect border value, while doing so, the VCL
// gradient's border will effectively shrink the
// resulting gradient.
double nScaleX( aBounds.getWidth() * (1.0 - rGradient.GetBorder() / 100.0) );
double nScaleY( aBounds.getHeight()* (1.0 - rGradient.GetBorder() / 100.0) );
// determine offset values. Since the border is
// divided half-by-half to both sides of the
// gradient, divide translation offset by an
// additional 2. Also respect offset here, but
// since VCL gradients have their center at [0,0]
// for zero offset, but canvas gradients have
// their top, left edge aligned with the
// primitive, and offset of 50% effectively must
// yield zero shift. Both values will potentially
// be adapted in switch statement below.
double nOffsetX( aBounds.getWidth() *
(2.0 * rGradient.GetOfsX() - 100.0 + rGradient.GetBorder()) / 200.0 );
double nOffsetY( aBounds.getHeight() *
(2.0 * rGradient.GetOfsY() - 100.0 + rGradient.GetBorder()) / 200.0 );
// determine type of gradient (and necessary
// transformation matrix, should it be emulated by a
// generic gradient)
switch( rGradient.GetStyle() )
{
case GRADIENT_RADIAL:
{
// create isotrophic scaling
if( nScaleX > nScaleY )
{
nOffsetY -= (nScaleX - nScaleY) * 0.5;
nScaleY = nScaleX;
}
else
{
nOffsetX -= (nScaleY - nScaleX) * 0.5;
nScaleX = nScaleY;
}
// enlarge gradient to match bound rect diagonal
aTextureTransformation.translate( -0.5, -0.5 );
const double nScale( hypot(aBounds.getWidth(), aBounds.getHeight()) / nScaleX );
aTextureTransformation.scale( nScale, nScale );
aTextureTransformation.translate( 0.5, 0.5 );
aTexture.Gradient = xFactory->createEllipticalGradient( aColors,
aStops,
geometry::RealRectangle2D(0.0,0.0,
1.0,1.0) );
}
break;
case GRADIENT_ELLIPTICAL:
{
// enlarge gradient slightly
aTextureTransformation.translate( -0.5, -0.5 );
const double nSqrt2( sqrt(2.0) );
aTextureTransformation.scale( nSqrt2,nSqrt2 );
aTextureTransformation.translate( 0.5, 0.5 );
aTexture.Gradient = xFactory->createEllipticalGradient(
aColors,
aStops,
::basegfx::unotools::rectangle2DFromB2DRectangle(
aBounds ));
}
break;
case GRADIENT_SQUARE:
// create isotrophic scaling
if( nScaleX > nScaleY )
{
nOffsetY -= (nScaleX - nScaleY) * 0.5;
nScaleY = nScaleX;
}
else
{
nOffsetX -= (nScaleY - nScaleX) * 0.5;
nScaleX = nScaleY;
}
aTexture.Gradient = xFactory->createRectangularGradient( aColors,
aStops,
geometry::RealRectangle2D(0.0,0.0,
1.0,1.0) );
break;
case GRADIENT_RECT:
aTexture.Gradient = xFactory->createRectangularGradient(
aColors,
aStops,
::basegfx::unotools::rectangle2DFromB2DRectangle(
aBounds ) );
break;
default: // other cases can't happen
break;
}
nScaleX = ::basegfx::pruneScaleValue( nScaleX );
nScaleY = ::basegfx::pruneScaleValue( nScaleY );
aTextureTransformation.scale( nScaleX, nScaleY );
// rotate texture according to gradient rotation
aTextureTransformation.translate( -0.5*nScaleX, -0.5*nScaleY );
aTextureTransformation.rotate( nRotation );
aTextureTransformation.translate( 0.5*nScaleX, 0.5*nScaleY );
aTextureTransformation.translate( nOffsetX, nOffsetY );
}
break;
basegfx::tools::createRectangularODFGradientInfo(aGradInfo,
aBounds,
aOffset,
nSteps,
fBorder,
fRotation);
aGradientService = rtl::OUString::createFromAscii("RectangularGradient");
break;
default:
ENSURE_OR_THROW( false,
"ImplRenderer::createGradientAction(): Unexpected gradient type" );
"ImplRenderer::createGradientAction(): Unexpected gradient type" );
break;
}
@@ -877,31 +752,49 @@ namespace cppcanvas
// gradient will always display at the origin, and
// not within the polygon bound (which might be
// miles away from the origin).
aTextureTransformation.translate( aBounds.getMinX(),
aBounds.getMinY() );
aGradInfo.maTextureTransform.translate( aBounds.getMinX(),
aBounds.getMinY() );
::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
aTextureTransformation );
aGradInfo.maTextureTransform );
ActionSharedPtr pPolyAction(
internal::PolyPolyActionFactory::createPolyPolyAction(
aDevicePoly,
rParms.mrCanvas,
getState( rParms.mrStates ),
aTexture ) );
uno::Sequence<uno::Any> args(3);
beans::PropertyValue aProp;
aProp.Name = rtl::OUString::createFromAscii("Colors");
aProp.Value <<= aColors;
args[0] <<= aProp;
aProp.Name = rtl::OUString::createFromAscii("Stops");
aProp.Value <<= aStops;
args[1] <<= aProp;
aProp.Name = rtl::OUString::createFromAscii("AspectRatio");
aProp.Value <<= aGradInfo.mfAspectRatio;
args[2] <<= aProp;
if( pPolyAction )
aTexture.Gradient.set(
xFactory->createInstanceWithArguments(aGradientService,
args),
uno::UNO_QUERY);
if( aTexture.Gradient.is() )
{
maActions.push_back(
MtfAction(
pPolyAction,
rParms.mrCurrActionIndex ) );
ActionSharedPtr pPolyAction(
internal::PolyPolyActionFactory::createPolyPolyAction(
aDevicePoly,
rParms.mrCanvas,
getState( rParms.mrStates ),
aTexture ) );
rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
if( pPolyAction )
{
maActions.push_back(
MtfAction(
pPolyAction,
rParms.mrCurrActionIndex ) );
rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
}
// done, using native gradients
return;
}
// done, using native gradients
return;
}
}