summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--basegfx/inc/basegfx/matrix/b2dhommatrixtools.hxx6
-rw-r--r--basegfx/inc/basegfx/numeric/ftools.hxx2
-rw-r--r--basegfx/inc/basegfx/tools/gradienttools.hxx18
-rw-r--r--basegfx/inc/basegfx/tools/keystoplerp.hxx100
-rw-r--r--basegfx/inc/basegfx/tools/lerp.hxx60
-rw-r--r--basegfx/prj/d.lst2
-rw-r--r--basegfx/source/matrix/b2dhommatrixtools.cxx28
-rw-r--r--basegfx/source/tools/gradienttools.cxx81
-rw-r--r--basegfx/source/tools/keystoplerp.cxx104
-rwxr-xr-xbasegfx/source/tools/makefile.mk1
-rw-r--r--basegfx/test/basegfxtools.cxx119
-rw-r--r--basegfx/test/makefile.mk1
-rw-r--r--canvas/inc/canvas/base/graphicdevicebase.hxx82
-rw-r--r--canvas/inc/canvas/canvastools.hxx22
-rw-r--r--canvas/inc/canvas/parametricpolypolygon.hxx40
-rw-r--r--canvas/source/cairo/cairo_canvas.hxx3
-rw-r--r--canvas/source/cairo/cairo_canvashelper.cxx268
-rw-r--r--canvas/source/cairo/cairo_spritecanvas.hxx3
-rw-r--r--canvas/source/null/null_spritecanvas.hxx4
-rw-r--r--canvas/source/tools/parametricpolypolygon.cxx114
-rw-r--r--canvas/source/vcl/canvas.hxx3
-rw-r--r--canvas/source/vcl/canvashelper_texturefill.cxx286
-rw-r--r--canvas/source/vcl/spritecanvas.hxx3
-rw-r--r--cppcanvas/source/mtfrenderer/implrenderer.cxx369
24 files changed, 1032 insertions, 687 deletions
diff --git a/basegfx/inc/basegfx/matrix/b2dhommatrixtools.hxx b/basegfx/inc/basegfx/matrix/b2dhommatrixtools.hxx
index 0b200b812bed..54d961d40ac2 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 5003ede0c4cf..6cecbecc1f9f 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 0c7f2ab2c060..dbcc5a3221f0 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 000000000000..a54b3485b1a1
--- /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 000000000000..590ef34c2009
--- /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 a58cd33e4f9c..170796920945 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 59a1ff432fc7..366a08a1d202 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 9e78039cd590..337f9bd8e52b 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 000000000000..99c74a350a69
--- /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 1bede8b22d88..d55bbae12f8f 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 000000000000..6ace65c5894d
--- /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 1bd4d59b98d5..bc44daffd27c 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 d0cd621f65a2..1105fea55eab 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 3942ab2726ef..345bcd9187ae 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 9d0883192094..b93f1c27a682 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 de2b9f8693a1..8fa56b5f4187 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 9cf2dd978759..942e5edb06a6 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( pPolyImpl->getValues().meType == canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR )
+ {
+ // no general path gradient yet in cairo; emulate then
+ cairo_save( pCairo );
+ cairo_clip( 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) );
- if( pPattern ) {
- OSL_TRACE( "filling with pattern" );
+ std::ptrdiff_t nIndex;
+ double fAlpha;
+ boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT);
- cairo_save( pCairo );
+ 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_transform( pCairo, &aTextureMatrix );
- cairo_set_source( pCairo, pPattern );
- cairo_fill( pCairo );
cairo_restore( pCairo );
+ }
+ else
+ {
+ Pattern* pPattern = patternFromParametricPolyPolygon( *pPolyImpl );
+
+ 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 );
+ 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;
-
- 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();
-
- 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;
-
- 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)) );
- }
+ {
+ 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 );
+
+ 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() );
+
+ pSurface = pScaledSurface;
+
+ 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)) );
+ }
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 bdbb42c6da12..210908552d73 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 341f2a5a95a6..278bcd9a8e7c 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 bfce116393d0..222b668a5fb0 100644
--- a/canvas/source/tools/parametricpolypolygon.cxx
+++ b/canvas/source/tools/parametricpolypolygon.cxx
@@ -53,68 +53,126 @@ using namespace ::com::sun::star;
namespace canvas
{
- ParametricPolyPolygon* ParametricPolyPolygon::createLinearHorizontalGradient(
- const uno::Reference< rendering::XGraphicDevice >& rDevice,
- const uno::Sequence< uno::Sequence< double > >& colors,
- const uno::Sequence< double >& stops )
+ uno::Sequence<rtl::OUString> ParametricPolyPolygon::getAvailableServiceNames()
{
- // TODO(P2): hold gradient brush statically, and only setup
- // the colors
- return new ParametricPolyPolygon( rDevice, GRADIENT_LINEAR, colors, stops );
+ 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::createAxialHorizontalGradient(
+ ParametricPolyPolygon* ParametricPolyPolygon::createLinearHorizontalGradient(
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 );
- }
+ return new ParametricPolyPolygon( rDevice, GRADIENT_LINEAR, colors, stops );
}
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 2279f817a406..c4e1a2853532 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 571a8c4fc5a3..5219c6349186 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] ) );
-
- // 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 );
+ 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,
+ aColors,
+ aPolyPoly,
+ viewState,
+ renderState,
+ textures[0],
+ nTransparency );
+ }
}
else
{
diff --git a/canvas/source/vcl/spritecanvas.hxx b/canvas/source/vcl/spritecanvas.hxx
index 545eeeed4577..66762bcb65b7 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 c6f9a295b332..daef89bf2905 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;
-
- const double nBorder(
- ::basegfx::pruneScaleValue(
- (1.0 - rGradient.GetBorder() / 100.0) ) );
-
- // 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() );
+ basegfx::tools::createLinearODFGradientInfo(aGradInfo,
+ aBounds,
+ nSteps,
+ fBorder,
+ fRotation);
+ // map odf to svg gradient orientation - x
+ // instead of y direction
+ aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aRot90;
+
+ // 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;
+
+ aGradientService = rtl::OUString::createFromAscii("LinearGradient");
+ break;
}
- break;
case GRADIENT_RADIAL:
- // FALLTHROUGH intended
- case GRADIENT_ELLIPTICAL:
- // FALLTHROUGH intended
- case GRADIENT_SQUARE:
- // FALLTHROUGH intended
- 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 );
+ basegfx::tools::createRadialODFGradientInfo(aGradInfo,
+ aBounds,
+ aOffset,
+ nSteps,
+ fBorder);
+ aGradientService = rtl::OUString::createFromAscii("EllipticalGradient");
+ break;
- aTextureTransformation.scale( nScaleX, nScaleY );
+ case GRADIENT_ELLIPTICAL:
+ basegfx::tools::createEllipticalODFGradientInfo(aGradInfo,
+ aBounds,
+ aOffset,
+ nSteps,
+ fBorder,
+ fRotation);
+ aGradientService = rtl::OUString::createFromAscii("EllipticalGradient");
+ break;
- // 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 );
+ case GRADIENT_SQUARE:
+ basegfx::tools::createSquareODFGradientInfo(aGradInfo,
+ aBounds,
+ aOffset,
+ nSteps,
+ fBorder,
+ fRotation);
+ aGradientService = rtl::OUString::createFromAscii("RectangularGradient");
+ break;
- aTextureTransformation.translate( nOffsetX, nOffsetY );
- }
- break;
+ case GRADIENT_RECT:
+ 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 );
+
+ 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;
+
+ aTexture.Gradient.set(
+ xFactory->createInstanceWithArguments(aGradientService,
+ args),
+ uno::UNO_QUERY);
+ if( aTexture.Gradient.is() )
+ {
+ ActionSharedPtr pPolyAction(
+ internal::PolyPolyActionFactory::createPolyPolyAction(
+ aDevicePoly,
+ rParms.mrCanvas,
+ getState( rParms.mrStates ),
+ aTexture ) );
- ActionSharedPtr pPolyAction(
- internal::PolyPolyActionFactory::createPolyPolyAction(
- aDevicePoly,
- rParms.mrCanvas,
- getState( rParms.mrStates ),
- aTexture ) );
+ if( pPolyAction )
+ {
+ maActions.push_back(
+ MtfAction(
+ pPolyAction,
+ rParms.mrCurrActionIndex ) );
- if( pPolyAction )
- {
- maActions.push_back(
- MtfAction(
- pPolyAction,
- rParms.mrCurrActionIndex ) );
+ rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
+ }
- rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
+ // done, using native gradients
+ return;
}
-
- // done, using native gradients
- return;
}
}