[ooo-build-commit] patches/test
Thorsten Behrens
thorsten at kemper.freedesktop.org
Wed Jul 22 15:05:02 PDT 2009
patches/test/canvas-gradient-fixes.diff | 2769 ++++++++++++++++++++++++++++++++
patches/test/slideshow-primitives.diff | 1774 ++++++++++++++++++++
patches/test/slideshow-unittests.diff | 60
3 files changed, 4603 insertions(+)
New commits:
commit 3e9659020cc253e17cddaad000425e981aa6ff21
Author: Thorsten Behrens <tbehrens at novell.com>
Date: Thu Jul 23 00:02:26 2009 +0200
WIP: slideshow on drawinglayer plus canvas gradients brush-up
* patches/test/canvas-gradient-fixes.diff: larger rewrite of
how XCanvas handles & provides gradients
* patches/test/slideshow-primitives.diff: first steps towards
using drawinglayer primitives also in slideshow
* patches/test/slideshow-unittests.diff: make slideshow unit
tests compile again
diff --git a/patches/test/canvas-gradient-fixes.diff b/patches/test/canvas-gradient-fixes.diff
new file mode 100644
index 0000000..986f38a
--- /dev/null
+++ b/patches/test/canvas-gradient-fixes.diff
@@ -0,0 +1,2769 @@
+canvas gradient fixes
+
+From: Thorsten Behrens <thb at openoffice.org>
+
+
+---
+
+ basegfx/inc/basegfx/numeric/ftools.hxx | 2
+ basegfx/inc/basegfx/tools/gradienttools.hxx | 4
+ basegfx/inc/basegfx/tools/keystoplerp.hxx | 100 +++++
+ basegfx/inc/basegfx/tools/lerp.hxx | 60 +++
+ basegfx/prj/d.lst | 2
+ basegfx/source/tools/keystoplerp.cxx | 104 ++++++
+ basegfx/source/tools/makefile.mk | 1
+ basegfx/test/basegfxtools.cxx | 119 ++++++
+ basegfx/test/makefile.mk | 1
+ canvas/inc/canvas/base/graphicdevicebase.hxx | 86 +----
+ canvas/inc/canvas/canvastools.hxx | 22 -
+ canvas/inc/canvas/parametricpolypolygon.hxx | 40 +-
+ canvas/source/cairo/cairo_canvas.hxx | 3
+ canvas/source/cairo/cairo_canvashelper.cxx | 113 ++++--
+ canvas/source/cairo/cairo_spritecanvas.hxx | 3
+ canvas/source/null/null_spritecanvas.hxx | 4
+ canvas/source/tools/parametricpolypolygon.cxx | 110 +++++-
+ canvas/source/vcl/canvas.hxx | 3
+ canvas/source/vcl/canvashelper_texturefill.cxx | 262 ++++++--------
+ canvas/source/vcl/spritecanvas.hxx | 3
+ cppcanvas/source/mtfrenderer/emfplus.cxx | 74 ++--
+ cppcanvas/source/mtfrenderer/implrenderer.cxx | 368 +++++++-------------
+ offapi/com/sun/star/rendering/XGraphicDevice.idl | 65 +++-
+ offapi/com/sun/star/rendering/makefile.mk | 1
+ .../source/engine/activities/activitybase.cxx | 2
+ .../activities/continuouskeytimeactivitybase.cxx | 69 +---
+ .../activities/continuouskeytimeactivitybase.hxx | 7
+ .../source/engine/activities/interpolation.hxx | 21 +
+ slideshow/source/engine/shapes/viewshape.cxx | 7
+ slideshow/source/engine/tools.cxx | 26 +
+ slideshow/source/inc/lerp.hxx | 62 ---
+ 31 files changed, 958 insertions(+), 786 deletions(-)
+ create mode 100644 basegfx/inc/basegfx/tools/keystoplerp.hxx
+ create mode 100644 basegfx/inc/basegfx/tools/lerp.hxx
+ create mode 100644 basegfx/source/tools/keystoplerp.cxx
+ create mode 100644 basegfx/test/basegfxtools.cxx
+ delete mode 100644 slideshow/source/inc/lerp.hxx
+
+
+diff --git basegfx/inc/basegfx/numeric/ftools.hxx basegfx/inc/basegfx/numeric/ftools.hxx
+index 9321745..080695d 100644
+--- basegfx/inc/basegfx/numeric/ftools.hxx
++++ 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 basegfx/inc/basegfx/tools/gradienttools.hxx basegfx/inc/basegfx/tools/gradienttools.hxx
+index 1b45aa9..59435f8 100644
+--- basegfx/inc/basegfx/tools/gradienttools.hxx
++++ 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
+@@ -394,7 +397,6 @@ namespace basegfx
+ {
+ return getSquareGradientAlpha(rUV, rGradInfo); // only matrix setup differs
+ }
+-
+ }
+ }
+
+diff --git basegfx/inc/basegfx/tools/keystoplerp.hxx basegfx/inc/basegfx/tools/keystoplerp.hxx
+new file mode 100644
+index 0000000..df4d3bb
+--- /dev/null
++++ 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 basegfx/inc/basegfx/tools/lerp.hxx basegfx/inc/basegfx/tools/lerp.hxx
+new file mode 100644
+index 0000000..36835f5
+--- /dev/null
++++ 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 basegfx/prj/d.lst basegfx/prj/d.lst
+index a58cd33..1707969 100644
+--- basegfx/prj/d.lst
++++ 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 basegfx/source/tools/keystoplerp.cxx basegfx/source/tools/keystoplerp.cxx
+new file mode 100644
+index 0000000..c7a58c2
+--- /dev/null
++++ 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 basegfx/source/tools/makefile.mk basegfx/source/tools/makefile.mk
+index df75a82..39e63b3 100755
+--- basegfx/source/tools/makefile.mk
++++ 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 basegfx/test/basegfxtools.cxx basegfx/test/basegfxtools.cxx
+new file mode 100644
+index 0000000..c8e8b88
+--- /dev/null
++++ 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 basegfx/test/makefile.mk basegfx/test/makefile.mk
+index 710d194..252c887 100644
+--- basegfx/test/makefile.mk
++++ 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 canvas/inc/canvas/base/graphicdevicebase.hxx canvas/inc/canvas/base/graphicdevicebase.hxx
+index 52bd86c..2dd2967 100644
+--- canvas/inc/canvas/base/graphicdevicebase.hxx
++++ 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 ) );
++ return ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D >(
++ 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 ) );
++ return ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D >(
++ 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 canvas/inc/canvas/canvastools.hxx canvas/inc/canvas/canvastools.hxx
+index 3b1e827..0a1275c 100644
+--- canvas/inc/canvas/canvastools.hxx
++++ 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 canvas/inc/canvas/parametricpolypolygon.hxx canvas/inc/canvas/parametricpolypolygon.hxx
+index e88028b..c9aa9bf 100644
+--- canvas/inc/canvas/parametricpolypolygon.hxx
++++ 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 canvas/source/cairo/cairo_canvas.hxx canvas/source/cairo/cairo_canvas.hxx
+index 62185d4..7528e2f 100644
+--- canvas/source/cairo/cairo_canvas.hxx
++++ 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 canvas/source/cairo/cairo_canvashelper.cxx canvas/source/cairo/cairo_canvashelper.cxx
+index 5ca2a96..e05ba73 100644
+--- canvas/source/cairo/cairo_canvashelper.cxx
++++ canvas/source/cairo/cairo_canvashelper.cxx
+@@ -665,7 +665,6 @@ 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 );
+ }
+ }
+ }
+@@ -691,9 +690,7 @@ 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;
+@@ -708,7 +705,7 @@ namespace cairocanvas
+ r0 = 0;
+ r1 = 0.5;
+
+- 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;
+ }
+@@ -1171,12 +1168,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 +1195,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 +1267,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 +1310,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 canvas/source/cairo/cairo_spritecanvas.hxx canvas/source/cairo/cairo_spritecanvas.hxx
+index 86cbf00..f308277 100644
+--- canvas/source/cairo/cairo_spritecanvas.hxx
++++ 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 canvas/source/null/null_spritecanvas.hxx canvas/source/null/null_spritecanvas.hxx
+index c65add5..f304b6b 100644
+--- canvas/source/null/null_spritecanvas.hxx
++++ 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 canvas/source/tools/parametricpolypolygon.cxx canvas/source/tools/parametricpolypolygon.cxx
+index 134fe2d..97e7d4b 100644
+--- canvas/source/tools/parametricpolypolygon.cxx
++++ canvas/source/tools/parametricpolypolygon.cxx
+@@ -53,42 +53,102 @@ 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
+@@ -97,14 +157,13 @@ namespace canvas
+ ::basegfx::tools::createPolygonFromCircle(
+ ::basegfx::B2DPoint( 0.5, 0.5), 0.5 ),
+ 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
+@@ -113,8 +172,7 @@ namespace canvas
+ ::basegfx::tools::createPolygonFromRect(
+ ::basegfx::B2DRectangle( 0.0, 0.0, 1.0, 1.0 ) ),
+ GRADIENT_RECTANGULAR,
+- colors, stops,
+- calcAspectRatio( boundRect ) );
++ colors, stops, fAspectRatio );
+ }
+
+ void SAL_CALL ParametricPolyPolygon::disposing()
+diff --git canvas/source/vcl/canvas.hxx canvas/source/vcl/canvas.hxx
+index dcee24e..e80d2fb 100644
+--- canvas/source/vcl/canvas.hxx
++++ 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 canvas/source/vcl/canvashelper_texturefill.cxx canvas/source/vcl/canvashelper_texturefill.cxx
+index 7c4ad96..dfbaeb7 100644
+--- canvas/source/vcl/canvashelper_texturefill.cxx
++++ 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 );
+
+@@ -406,8 +356,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,22 +375,28 @@ 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 )
+ {
++ std::ptrdiff_t nIndex;
++ double fAlpha;
++ boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(double(i)/nStepCount);
++
+ // 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.
+@@ -489,13 +445,17 @@ 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 )
+ {
++ std::ptrdiff_t nIndex;
++ double fAlpha;
++ boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(double(i)/nStepCount);
++
+ // 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) )
+@@ -549,46 +509,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 );
++ rValues,
++ rColors );
+ break;
+
+- case ::canvas::ParametricPolyPolygon::GRADIENT_AXIAL:
+- fillAxialGradient( rOutDev,
+- rColor1,
+- rColor2,
+- rTextureTransform,
+- rBounds,
+- nStepCount,
+- bFillNonOverlapping );
+- 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 +544,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 +601,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 +642,7 @@ namespace vclcanvas
+ rOutDev.IntersectClipRegion( aPolygonDeviceRectOrig );
+ doGradientFill( rOutDev,
+ rValues,
+- rColor1,
+- rColor2,
++ rColors,
+ aTextureTransform,
+ aPolygonDeviceRectOrig,
+ nStepCount,
+@@ -704,8 +655,7 @@ namespace vclcanvas
+ p2ndOutDev->IntersectClipRegion( aPolygonDeviceRectOrig );
+ doGradientFill( *p2ndOutDev,
+ rValues,
+- rColor1,
+- rColor2,
++ rColors,
+ aTextureTransform,
+ aPolygonDeviceRectOrig,
+ nStepCount,
+@@ -723,8 +673,7 @@ namespace vclcanvas
+
+ doGradientFill( rOutDev,
+ rValues,
+- rColor1,
+- rColor2,
++ rColors,
+ aTextureTransform,
+ aPolygonDeviceRectOrig,
+ nStepCount,
+@@ -737,8 +686,7 @@ namespace vclcanvas
+ p2ndOutDev->SetClipRegion( aPolyClipRegion );
+ doGradientFill( *p2ndOutDev,
+ rValues,
+- rColor1,
+- rColor2,
++ rColors,
+ aTextureTransform,
+ aPolygonDeviceRectOrig,
+ nStepCount,
+@@ -753,8 +701,7 @@ namespace vclcanvas
+ rOutDev.SetRasterOp( ROP_XOR );
+ doGradientFill( rOutDev,
+ rValues,
+- rColor1,
+- rColor2,
++ rColors,
+ aTextureTransform,
+ aPolygonDeviceRectOrig,
+ nStepCount,
+@@ -765,8 +712,7 @@ namespace vclcanvas
+ rOutDev.SetRasterOp( ROP_XOR );
+ doGradientFill( rOutDev,
+ rValues,
+- rColor1,
+- rColor2,
++ rColors,
+ aTextureTransform,
+ aPolygonDeviceRectOrig,
+ nStepCount,
+@@ -779,8 +725,7 @@ namespace vclcanvas
+ p2ndOutDev->SetRasterOp( ROP_XOR );
+ doGradientFill( *p2ndOutDev,
+ rValues,
+- rColor1,
+- rColor2,
++ rColors,
+ aTextureTransform,
+ aPolygonDeviceRectOrig,
+ nStepCount,
+@@ -791,8 +736,7 @@ namespace vclcanvas
+ p2ndOutDev->SetRasterOp( ROP_XOR );
+ doGradientFill( *p2ndOutDev,
+ rValues,
+- rColor1,
+- rColor2,
++ rColors,
+ aTextureTransform,
+ aPolygonDeviceRectOrig,
+ nStepCount,
+@@ -855,33 +799,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 canvas/source/vcl/spritecanvas.hxx canvas/source/vcl/spritecanvas.hxx
+index 0c56d16..e9e9c8f 100644
+--- canvas/source/vcl/spritecanvas.hxx
++++ 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 cppcanvas/source/mtfrenderer/emfplus.cxx cppcanvas/source/mtfrenderer/emfplus.cxx
+index a35dbef..6260df1 100644
+--- cppcanvas/source/mtfrenderer/emfplus.cxx
++++ cppcanvas/source/mtfrenderer/emfplus.cxx
+@@ -15,7 +15,6 @@
+
+ #include <com/sun/star/rendering/XCanvas.hpp>
+ #include <com/sun/star/rendering/TexturingMode.hpp>
+-#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
+
+ #include <bitmapaction.hxx>
+ #include <implrenderer.hxx>
+@@ -96,7 +95,7 @@ namespace cppcanvas
+ public:
+ EMFPPath (sal_Int32 _nPoints, bool bLines = false)
+ {
+- if( _nPoints<0 || _nPoints>SAL_MAX_INT32/(2*sizeof(float)) )
++ if( _nPoints<0L || _nPoints>SAL_MAX_INT32/(2*sal_Int32(sizeof(float))) )
+ _nPoints = SAL_MAX_INT32/(2*sizeof(float));
+ nPoints = _nPoints;
+ pPoints = new float [nPoints*2];
+@@ -133,8 +132,6 @@ namespace cppcanvas
+
+ if (pPointTypes)
+ for (int i = 0; i < nPoints; i ++) {
+- UINT8 pathType;
+-
+ s >> pPointTypes [i];
+ EMFP_DEBUG (printf ("EMF+\tpoint type: %x\n", pPointTypes [i]));
+ }
+@@ -149,8 +146,6 @@ namespace cppcanvas
+ ::basegfx::B2DPolyPolygon& GetPolygon (ImplRenderer& rR, bool bMapIt = true)
+ {
+ ::basegfx::B2DPolygon polygon;
+- sal_Int32 points = nPoints;
+-
+ aPolygon.clear ();
+
+ int last_normal = 0, p = 0;
+@@ -240,7 +235,7 @@ namespace cppcanvas
+ EMFP_DEBUG (printf ("EMF+\theader: 0x%08x parts: %d\n", header, parts));
+
+ if (parts) {
+- if( parts<0 || parts>SAL_MAX_INT32/sizeof(sal_Int32) )
++ if( parts<0 || parts>SAL_MAX_INT32/sal_Int32(sizeof(sal_Int32)) )
+ parts = SAL_MAX_INT32/sizeof(sal_Int32);
+
+ combineMode = new sal_Int32 [parts];
+@@ -354,7 +349,7 @@ namespace cppcanvas
+ s >> surroundColorsNumber;
+ EMFP_DEBUG (printf ("EMF+\tsurround colors: %d\n", surroundColorsNumber));
+
+- if( surroundColorsNumber<0 || surroundColorsNumber>SAL_MAX_INT32/sizeof(::Color) )
++ if( surroundColorsNumber<0 || surroundColorsNumber>SAL_MAX_INT32/sal_Int32(sizeof(::Color)) )
+ surroundColorsNumber = SAL_MAX_INT32/sizeof(::Color);
+
+ surroundColors = new ::Color [surroundColorsNumber];
+@@ -406,7 +401,7 @@ namespace cppcanvas
+ if (additionalFlags & 0x08) {
+ s >> blendPoints;
+ EMFP_DEBUG (printf ("EMF+\tuse blend, points: %d\n", blendPoints));
+- if( blendPoints<0 || blendPoints>SAL_MAX_INT32/(2*sizeof(float)) )
++ if( blendPoints<0 || blendPoints>SAL_MAX_INT32/sal_Int32(2*sizeof(float)) )
+ blendPoints = SAL_MAX_INT32/(2*sizeof(float));
+ blendPositions = new float [2*blendPoints];
+ blendFactors = blendPositions + blendPoints;
+@@ -423,9 +418,9 @@ namespace cppcanvas
+ if (additionalFlags & 0x04) {
+ s >> colorblendPoints;
+ EMFP_DEBUG (printf ("EMF+\tuse color blend, points: %d\n", colorblendPoints));
+- if( colorblendPoints<0 || colorblendPoints>SAL_MAX_INT32/sizeof(float) )
++ if( colorblendPoints<0 || colorblendPoints>SAL_MAX_INT32/sal_Int32(sizeof(float)) )
+ colorblendPoints = SAL_MAX_INT32/sizeof(float);
+- if( colorblendPoints>SAL_MAX_INT32/sizeof(::Color) )
++ if( colorblendPoints>SAL_MAX_INT32/sal_Int32(sizeof(::Color)) )
+ colorblendPoints = SAL_MAX_INT32/sizeof(::Color);
+ colorblendPositions = new float [colorblendPoints];
+ colorblendColors = new ::Color [colorblendPoints];
+@@ -439,9 +434,9 @@ namespace cppcanvas
+ EMFP_DEBUG (printf ("EMF+\tcolor[%d]: 0x%08x\n", i, color));
+ }
+ }
+- } else
++ } else {
+ EMFP_DEBUG (dumpWords (s, 1024));
+-
++ }
+ break;
+ }
+ // linear gradient
+@@ -481,7 +476,7 @@ namespace cppcanvas
+ if (additionalFlags & 0x08) {
+ s >> blendPoints;
+ EMFP_DEBUG (printf ("EMF+\tuse blend, points: %d\n", blendPoints));
+- if( blendPoints<0 || blendPoints>SAL_MAX_INT32/(2*sizeof(float)) )
++ if( blendPoints<0 || blendPoints>SAL_MAX_INT32/sal_Int32(2*sizeof(float)) )
+ blendPoints = SAL_MAX_INT32/(2*sizeof(float));
+ blendPositions = new float [2*blendPoints];
+ blendFactors = blendPositions + blendPoints;
+@@ -498,9 +493,9 @@ namespace cppcanvas
+ if (additionalFlags & 0x04) {
+ s >> colorblendPoints;
+ EMFP_DEBUG (printf ("EMF+\tuse color blend, points: %d\n", colorblendPoints));
+- if( colorblendPoints<0 || colorblendPoints>SAL_MAX_INT32/sizeof(float) )
++ if( colorblendPoints<0 || colorblendPoints>SAL_MAX_INT32/sal_Int32(sizeof(float)) )
+ colorblendPoints = SAL_MAX_INT32/sizeof(float);
+- if( colorblendPoints>SAL_MAX_INT32/sizeof(::Color) )
++ if( colorblendPoints>SAL_MAX_INT32/sal_Int32(sizeof(::Color)) )
+ colorblendPoints = SAL_MAX_INT32/sizeof(::Color);
+ colorblendPositions = new float [colorblendPoints];
+ colorblendColors = new ::Color [colorblendPoints];
+@@ -554,7 +549,7 @@ namespace cppcanvas
+ rStrokeAttributes.StrokeWidth = (rState.mapModeTransform * rR.MapSize (width, 0)).getX ();
+ }
+
+- void Read (SvStream& s, ImplRenderer& rR, sal_Int32 nHDPI, sal_Int32 nVDPI)
++ void Read (SvStream& s, ImplRenderer& rR, sal_Int32 /*nHDPI*/, sal_Int32 /*nVDPI*/)
+ {
+ UINT32 header, unknown, penFlags, unknown2;
+ int i;
+@@ -603,7 +598,7 @@ namespace cppcanvas
+
+ if (penFlags & 256) {
+ s >> dashPatternLen;
+- if( dashPatternLen<0 || dashPatternLen>SAL_MAX_INT32/sizeof(float) )
++ if( dashPatternLen<0 || dashPatternLen>SAL_MAX_INT32/sal_Int32(sizeof(float)) )
+ dashPatternLen = SAL_MAX_INT32/sizeof(float);
+ dashPattern = new float [dashPatternLen];
+ for (i = 0; i < dashPatternLen; i++)
+@@ -618,7 +613,7 @@ namespace cppcanvas
+
+ if (penFlags & 1024) {
+ s >> compoundArrayLen;
+- if( compoundArrayLen<0 || compoundArrayLen>SAL_MAX_INT32/sizeof(float) )
++ if( compoundArrayLen<0 || compoundArrayLen>SAL_MAX_INT32/sal_Int32(sizeof(float)) )
+ compoundArrayLen = SAL_MAX_INT32/sizeof(float);
+ compoundArray = new float [compoundArrayLen];
+ for (i = 0; i < compoundArrayLen; i++)
+@@ -845,10 +840,7 @@ namespace cppcanvas
+ ::basegfx::B2DHomMatrix aWorldTransformation;
+ ::basegfx::B2DHomMatrix aBaseTransformation;
+ rendering::Texture aTexture;
+- double nRotation( 0.0 );
+ const ::basegfx::B2DRectangle aBounds( ::basegfx::tools::getRange( localPolygon ) );
+- const double nScale( ::basegfx::pruneScaleValue( fabs( aBounds.getHeight()*sin(nRotation) ) +
+- fabs( aBounds.getWidth()*cos(nRotation) )));
+
+ aWorldTransformation.set (0, 0, aWorldTransform.eM11);
+ aWorldTransformation.set (0, 1, aWorldTransform.eM21);
+@@ -896,7 +888,7 @@ namespace cppcanvas
+ aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
+ aTexture.Alpha = 1.0;
+
+- uno::Reference< rendering::XParametricPolyPolygon2DFactory > xFactory(
++ uno::Reference< lang::XMultiServiceFactory> xFactory(
+ rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
+
+ if( xFactory.is() ) {
+@@ -957,15 +949,26 @@ namespace cppcanvas
+ }
+ }
+
++ uno::Sequence<uno::Any> args(2);
++ 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;
++
+ EMFP_DEBUG (printf ("EMF+\t\tset gradient\n"));
+ if (brush->type == 4)
+- aTexture.Gradient = xFactory->createLinearHorizontalGradient( aColors,
+- aStops );
++ aTexture.Gradient.set(
++ xFactory->createInstanceWithArguments(
++ rtl::OUString::createFromAscii("LinearGradient"), args),
++ uno::UNO_QUERY);
+ else {
+- geometry::RealRectangle2D aBoundsRectangle (0, 0, 1, 1);
+- aTexture.Gradient = xFactory->createEllipticalGradient( aColors,
+- aStops,
+- aBoundsRectangle);
++ aTexture.Gradient.set(
++ xFactory->createInstanceWithArguments(
++ rtl::OUString::createFromAscii("EllipticalGradient"), args),
++ uno::UNO_QUERY);
+ }
+ }
+
+@@ -995,7 +998,6 @@ namespace cppcanvas
+
+ void ImplRenderer::processObjectRecord(SvMemoryStream& rObjectStream, UINT16 flags)
+ {
+- UINT32 objectLen;
+ sal_uInt32 index;
+
+ EMFP_DEBUG (printf ("EMF+ Object slot: %hd flags: %hx\n", flags & 0xff, flags & 0xff00));
+@@ -1078,7 +1080,7 @@ namespace cppcanvas
+
+ EMFP_DEBUG (printf ("EMF+ record size: %d type: %04hx flags: %04hx data size: %d\n", size, type, flags, dataSize));
+
+- if (type == EmfPlusRecordTypeObject && (mbMultipart && flags & 0x7fff == mMFlags & 0x7fff || flags & 0x8000)) {
++ if (type == EmfPlusRecordTypeObject && ((mbMultipart && (flags & 0x7fff) == (mMFlags & 0x7fff)) || flags & 0x8000)) {
+ if (!mbMultipart) {
+ mbMultipart = true;
+ mMFlags = flags;
+@@ -1177,12 +1179,8 @@ namespace cppcanvas
+ }
+ case EmfPlusRecordTypeFillPolygon:
+ {
+- sal_uInt8 index = flags & 0xff;
+ sal_uInt32 brushIndexOrColor;
+- sal_Int32 brushIndex;
+ sal_Int32 points;
+- UINT32 color;
+- USHORT transparency = 0;
+
+ rMF >> brushIndexOrColor;
+ rMF >> points;
+@@ -1326,8 +1324,9 @@ namespace cppcanvas
+
+ rFactoryParms.mrCurrActionIndex += pBmpAction->getActionCount()-1;
+ }
+- } else
++ } else {
+ EMFP_DEBUG (printf ("EMF+ DrawImagePoints TODO (fixme)\n"));
++ }
+ }
+ break;
+ }
+@@ -1407,8 +1406,9 @@ namespace cppcanvas
+ // reset clip
+ if (region.parts == 0 && region.initialState == EmfPlusRegionInitialStateInfinite) {
+ updateClipping (::basegfx::B2DPolyPolygon (), rFactoryParms, false);
+- } else
++ } else {
+ EMFP_DEBUG (printf ("EMF+\tTODO\n"));
++ }
+ break;
+ }
+ case EmfPlusRecordTypeDrawDriverString:
+diff --git cppcanvas/source/mtfrenderer/implrenderer.cxx cppcanvas/source/mtfrenderer/implrenderer.cxx
+index bf8d831..b33a26c 100644
+--- cppcanvas/source/mtfrenderer/implrenderer.cxx
++++ 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>
+@@ -591,13 +591,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;
+@@ -632,245 +631,103 @@ namespace cppcanvas
+ uno::Sequence< uno::Sequence < double > > aColors(2);
+ uno::Sequence< double > aStops(2);
+
+- aStops[0] = 0.0;
+- aStops[1] = 1.0;
+-
+- aColors[0] = aStartColor;
+- aColors[1] = aEndColor;
+-
++ if( rGradient.GetStyle() == GRADIENT_AXIAL )
++ {
++ aStops.realloc(3);
++ aColors.realloc(3);
+
+- // Setup texture transformation
+- // ----------------------------
++ 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;
++
++ aColors[0] = aStartColor;
++ aColors[1] = aEndColor;
++ }
++
+ const ::basegfx::B2DRectangle aBounds(
+ ::basegfx::tools::getRange(aDevicePoly) );
+-
+- // setup rotation angle. VCL rotates
+- // counter-clockwise, while canvas transformation
+- // rotates clockwise
+- double nRotation( -rGradient.GetAngle() * M_PI / 1800.0 );
+-
++ const ::basegfx::B2DVector aOffset(
++ rGradient.GetOfsX() / 100.0,
++ rGradient.GetOfsY() / 100.0);
++ const double fRotation( rGradient.GetAngle() * M_PI / 1800.0 );
++ const double fBorder( rGradient.GetBorder() / 100.0 );
++
++ basegfx::ODFGradientInfo aGradInfo;
++ rtl::OUString aGradientService;
+ switch( rGradient.GetStyle() )
+ {
+ case GRADIENT_LINEAR:
+- // FALLTHROUGH intended
+- 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;
+- }
++ basegfx::tools::createLinearODFGradientInfo(aGradInfo,
++ aBounds,
++ nSteps,
++ fBorder,
++ fRotation);
++ aGradientService = rtl::OUString::createFromAscii("LinearGradient");
++ 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() );
+- }
+- break;
++ case GRADIENT_AXIAL:
++ basegfx::tools::createAxialODFGradientInfo(aGradInfo,
++ aBounds,
++ nSteps,
++ fBorder,
++ fRotation);
++ aGradientService = rtl::OUString::createFromAscii("LinearGradient");
++ 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;
+- }
++ basegfx::tools::createRadialODFGradientInfo(aGradInfo,
++ aBounds,
++ aOffset,
++ nSteps,
++ fBorder);
++ aGradientService = rtl::OUString::createFromAscii("EllipticalGradient");
++ break;
+
+- nScaleX = ::basegfx::pruneScaleValue( nScaleX );
+- nScaleY = ::basegfx::pruneScaleValue( nScaleY );
++ case GRADIENT_ELLIPTICAL:
++ basegfx::tools::createEllipticalODFGradientInfo(aGradInfo,
++ aBounds,
++ aOffset,
++ nSteps,
++ fBorder,
++ fRotation);
++ aGradientService = rtl::OUString::createFromAscii("EllipticalGradient");
++ break;
+
+- aTextureTransformation.scale( nScaleX, nScaleY );
++ case GRADIENT_SQUARE:
++ basegfx::tools::createSquareODFGradientInfo(aGradInfo,
++ aBounds,
++ aOffset,
++ nSteps,
++ fBorder,
++ fRotation);
++ aGradientService = rtl::OUString::createFromAscii("RectangularGradient");
++ 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 );
+-
+- 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;
+ }
+-
++
+ // As the texture coordinate space is relative to
+ // the polygon coordinate space (NOT to the
+ // polygon itself), move gradient to the start of
+@@ -878,31 +735,50 @@ 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 );
+-
+- ActionSharedPtr pPolyAction(
+- internal::PolyPolyActionFactory::createPolyPolyAction(
+- aDevicePoly,
+- rParms.mrCanvas,
+- getState( rParms.mrStates ),
+- aTexture ) );
+-
+- if( pPolyAction )
++ 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() )
+ {
+- maActions.push_back(
+- MtfAction(
+- pPolyAction,
+- rParms.mrCurrActionIndex ) );
++ ActionSharedPtr pPolyAction(
++ internal::PolyPolyActionFactory::createPolyPolyAction(
++ aDevicePoly,
++ rParms.mrCanvas,
++ getState( rParms.mrStates ),
++ aTexture ) );
++
++ 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;
++ }
+ }
+ }
+
+@@ -1910,7 +1786,7 @@ namespace cppcanvas
+ if (count == -1) {
+ count = 0;
+ char *env;
+- if (env = getenv ("EMF_PLUS_LIMIT")) {
++ if( (env=getenv ("EMF_PLUS_LIMIT")) ) {
+ limit = atoi (env);
+ EMFP_DEBUG (printf ("EMF+ records limit: %d\n", limit));
+ }
+diff --git offapi/com/sun/star/rendering/XGraphicDevice.idl offapi/com/sun/star/rendering/XGraphicDevice.idl
+index b94f097..6a46714 100644
+--- offapi/com/sun/star/rendering/XGraphicDevice.idl
++++ offapi/com/sun/star/rendering/XGraphicDevice.idl
+@@ -51,8 +51,8 @@
+ #ifndef __com_sun_star_rendering_XParametricPolyPolygon2DFactory_idl__
+ #include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.idl>
+ #endif
+-#ifndef __com_sun_star_rendering_XColorSpace_idl__
+-#include <com/sun/star/rendering/XColorSpace.idl>
++#ifndef __com_sun_star_lang_XMultiServiceFactory_idl__
++#include <com/sun/star/lang/XMultiServiceFactory.idl>
+ #endif
+
+ module com { module sun { module star { module rendering {
+@@ -220,8 +220,67 @@ interface XGraphicDevice : ::com::sun::star::uno::XInterface
+ this is not advisable: each canvas implementation is free to
+ internally generate optimized parametric polygons, which can
+ be used more directly for e.g. texturing operations.
++
++ <pre>
++ Available services (all canvas implementations should provide
++ this minimal set, though are free to add more; just check the
++ getAvailableServiceNames() on the returned interface):
++
++ - Gradients - all gradients need to support two construction
++ parameters, "Colors" being a <type>sequence<Color></type>
++ and "Stops" being a <type>sequence<double></type>. Both must
++ have the same length, and at least two elements. See
++ http://www.w3.org/TR/SVG11/pservers.html#GradientStops for
++ the semantics of gradient stops and colors.
++ Required gradient services:
++
++ * "LinearGradient" - the gradient varies linearly between
++ the given colors. without coordinate system
++ transformation, the color interpolation happens in
++ increasing x direction, and is constant in y
++ direction. Equivalent to svg linear gradient
++ http://www.w3.org/TR/SVG11/pservers.html#LinearGradients
++
++ * "EllipticalGradient" - this gradient has zeroth color
++ index in the middle, and varies linearly between center
++ and final color. The services takes an additional
++ parameter named "AspectRatio" of <type>double</type>
++ (width divided by height), if this aspect ratio is 1, the
++ gradient is circular. If it's not 1, the gradient is
++ elliptical, with the special twist that the aspect ratio
++ is maintained also for the center color: the gradient will
++ not collapse into a single point, but become a line of
++ center color. If "AspectRatio" is missing, or equal to 1,
++ this gradient yields similar results as the svg radial
++ gradient
++ http://www.w3.org/TR/SVG11/pservers.html#RadialGradients
++
++ * "RectangularGradient" - this gradient has zeroth color
++ index in the middle, and varies linearly between center
++ and final color via rectangular boxes
++ around the center point. The services takes an additional
++ parameter named "AspectRatio" of <type>double</type>
++ (width divided by height), if this aspect ratio is 1, the
++ gradient is quadratic. If it's not 1, the gradient is
++ rectangular, with the special twist that the aspect ratio
++ is maintained also for the center color: the gradient will
++ not collapse into a single point, but become a line of
++ center color.
++
++ - Hatch patterns - Required hatch services:
++
++ * "VerticalLineHatch" - this hatching consists of vertical lines
++ * "OrthogonalLinesHatch" - this hatching consists of
++ crossing vertical and horizontal lines
++ * "ThreeCrossingLinesHatch" - this hatching consists of
++ vertical and horizontal lines plus diagonal lines from
++ left, top to bottom, right.
++ * "FourCrossingLinesHatch" - this hatching consists of
++ vertical and horizontal lines plus diagonal lines in both
++ directions.
++ </pre>
+ */
+- XParametricPolyPolygon2DFactory getParametricPolyPolygonFactory();
++ com::sun::star::lang::XMultiServiceFactory getParametricPolyPolygonFactory();
+
+ //-------------------------------------------------------------------------
+
+diff --git offapi/com/sun/star/rendering/makefile.mk offapi/com/sun/star/rendering/makefile.mk
+index 8466a1e..d4979ed 100644
+--- offapi/com/sun/star/rendering/makefile.mk
++++ offapi/com/sun/star/rendering/makefile.mk
+@@ -109,7 +109,6 @@ IDLFILES=\
+ XIntegerReadOnlyBitmap.idl \
+ XLinePolyPolygon2D.idl \
+ XParametricPolyPolygon2D.idl \
+- XParametricPolyPolygon2DFactory.idl \
+ XPolyPolygon2D.idl \
+ XSimpleCanvas.idl \
+ XSprite.idl \
+diff --git slideshow/source/engine/activities/activitybase.cxx slideshow/source/engine/activities/activitybase.cxx
+index 97eeb6c..b0ca84a 100644
+--- slideshow/source/engine/activities/activitybase.cxx
++++ slideshow/source/engine/activities/activitybase.cxx
+@@ -162,7 +162,7 @@ namespace slideshow
+ // ================================
+
+ // clamp nT to permissible [0,1] range
+- nT = ::canvas::tools::clamp( nT, 0.0, 1.0 );
++ nT = ::basegfx::clamp( nT, 0.0, 1.0 );
+
+ // take acceleration/deceleration into account. if the sum
+ // of mnAccelerationFraction and mnDecelerationFraction
+diff --git slideshow/source/engine/activities/continuouskeytimeactivitybase.cxx slideshow/source/engine/activities/continuouskeytimeactivitybase.cxx
+index 4306967..554f1ce 100644
+--- slideshow/source/engine/activities/continuouskeytimeactivitybase.cxx
++++ slideshow/source/engine/activities/continuouskeytimeactivitybase.cxx
+@@ -38,6 +38,7 @@
+
+ #include <continuouskeytimeactivitybase.hxx>
+
++#include <boost/tuple/tuple.hpp>
+ #include <algorithm>
+ #include <iterator>
+
+@@ -48,34 +49,14 @@ namespace slideshow
+ {
+ ContinuousKeyTimeActivityBase::ContinuousKeyTimeActivityBase( const ActivityParameters& rParms ) :
+ SimpleContinuousActivityBase( rParms ),
+- maKeyTimes( rParms.maDiscreteTimes ),
+- mnLastIndex( 0 )
++ maLerper( rParms.maDiscreteTimes )
+ {
+- ENSURE_OR_THROW( maKeyTimes.size() > 1,
++ ENSURE_OR_THROW( rParms.maDiscreteTimes.size() > 1,
+ "ContinuousKeyTimeActivityBase::ContinuousKeyTimeActivityBase(): key times vector must have two entries or more" );
+-
+-#ifdef DBG_UTIL
+- // check parameters: rKeyTimes must be sorted in
+- // ascending order, and contain values only from the range
+- // [0,1]
+- for( ::std::size_t i=1, len=maKeyTimes.size(); i<len; ++i )
+- {
+- if( maKeyTimes[i] < 0.0 ||
+- maKeyTimes[i] > 1.0 ||
+- maKeyTimes[i-1] < 0.0 ||
+- maKeyTimes[i-1] > 1.0 )
+- {
+- ENSURE_OR_THROW( false, "ContinuousKeyTimeActivityBase::ContinuousKeyTimeActivityBase(): time values not within [0,1] range!" );
+- }
+-
+- if( maKeyTimes[i-1] > maKeyTimes[i] )
+- {
+- ENSURE_OR_THROW( false, "ContinuousKeyTimeActivityBase::ContinuousKeyTimeActivityBase(): time vector is not sorted in ascending order!" );
+- }
+- }
+-
+- // TODO(E2): check this also in production code?
+-#endif
++ ENSURE_OR_THROW( rParms.maDiscreteTimes.front() == 0.0,
++ "ContinuousKeyTimeActivityBase::ContinuousKeyTimeActivityBase(): key times vector first entry must be zero" );
++ ENSURE_OR_THROW( rParms.maDiscreteTimes.back() <= 1.0,
++ "ContinuousKeyTimeActivityBase::ContinuousKeyTimeActivityBase(): key times vector last entry must be less or equal 1" );
+ }
+
+ void ContinuousKeyTimeActivityBase::simplePerform( double nSimpleTime,
+@@ -84,40 +65,14 @@ namespace slideshow
+ // calc simple time from global time - sweep through the
+ // array multiple times for repeated animations (according to
+ // SMIL spec).
+- const double nT( calcAcceleratedTime( nSimpleTime ) );
+-
+- // determine position within key times vector from
+- // current simple time
+-
+- // shortcut: cached value still okay?
+- if( maKeyTimes[ mnLastIndex ] < nT ||
+- maKeyTimes[ mnLastIndex+1 ] >= nT )
+- {
+- // nope, find new index
+- mnLastIndex = ::std::min< ::std::ptrdiff_t >(
+- maKeyTimes.size()-2,
+- // range is ensured by max below
+- ::std::max< ::std::ptrdiff_t >(
+- 0,
+- ::std::distance( maKeyTimes.begin(),
+- ::std::lower_bound( maKeyTimes.begin(),
+- maKeyTimes.end(),
+- nT ) ) - 1 ) );
+- }
+-
+- OSL_ENSURE( mnLastIndex+1 < maKeyTimes.size(),
+- "ContinuousKeyTimeActivityBase::simplePerform(): index out of range" );
+-
+- // mnLastIndex is now valid and up-to-date
++ double fAlpha( calcAcceleratedTime( nSimpleTime ) );
++ std::ptrdiff_t nIndex;
+
+- // calc current simple time, as a fractional value ([0,1] range).
+- // I.e. the relative position between the two index times.
+- const double nCurrFractionalSimplTime( (nT - maKeyTimes[ mnLastIndex ]) /
+- (maKeyTimes[ mnLastIndex+1 ] - maKeyTimes[ mnLastIndex ]) );
++ boost::tuples::tie(nIndex,fAlpha) = maLerper.lerp(fAlpha);
+
+ perform(
+- mnLastIndex,
+- nCurrFractionalSimplTime,
++ nIndex,
++ fAlpha,
+ nRepeatCount );
+ }
+ }
+diff --git slideshow/source/engine/activities/continuouskeytimeactivitybase.hxx slideshow/source/engine/activities/continuouskeytimeactivitybase.hxx
+index 9d767ea..4e06ec1 100644
+--- slideshow/source/engine/activities/continuouskeytimeactivitybase.hxx
++++ slideshow/source/engine/activities/continuouskeytimeactivitybase.hxx
+@@ -32,6 +32,8 @@
+ #define INCLUDED_SLIDESHOW_CONTINUOUSKEYTIMEACTIVITYBASE_HXX
+
+ #include "simplecontinuousactivitybase.hxx"
++
++#include <basegfx/tools/keystoplerp.hxx>
+ #include <vector>
+
+
+@@ -76,10 +78,7 @@ namespace slideshow
+ sal_uInt32 nRepeatCount ) const;
+
+ private:
+- const ::std::vector< double > maKeyTimes;
+-
+- /// last active index in maKeyTimes (to avoid frequent searching)
+- mutable ::std::size_t mnLastIndex;
++ const ::basegfx::tools::KeyStopLerp maLerper;
+ };
+ }
+ }
+diff --git slideshow/source/engine/activities/interpolation.hxx slideshow/source/engine/activities/interpolation.hxx
+index 5327c4a..5c4289b 100644
+--- slideshow/source/engine/activities/interpolation.hxx
++++ slideshow/source/engine/activities/interpolation.hxx
+@@ -31,11 +31,11 @@
+ #ifndef INCLUDED_SLIDESHOW_INTERPOLATION_HXX
+ #define INCLUDED_SLIDESHOW_INTERPOLATION_HXX
+
+-#include "lerp.hxx"
++#include <basegfx/tools/lerp.hxx>
+
+-namespace slideshow
++namespace basegfx
+ {
+- namespace internal
++ namespace tools
+ {
+ // Interpolator specializations
+ // ============================
+@@ -45,9 +45,10 @@ namespace slideshow
+ // not-straight-forward-interpolatable types
+
+ /// Specialization for RGBColor, to employ color-specific interpolator
+- template<> RGBColor lerp< RGBColor >( const RGBColor& rFrom,
+- const RGBColor& rTo,
+- double t )
++ template<> ::slideshow::internal::RGBColor lerp< ::slideshow::internal::RGBColor >(
++ const ::slideshow::internal::RGBColor& rFrom,
++ const ::slideshow::internal::RGBColor& rTo,
++ double t )
+ {
+ return interpolate( rFrom, rTo, t );
+ }
+@@ -81,14 +82,20 @@ namespace slideshow
+ "lerp<bool> called" );
+ return rTo;
+ }
++ }
++}
+
++namespace slideshow
++{
++ namespace internal
++ {
+ template< typename ValueType > struct Interpolator
+ {
+ ValueType operator()( const ValueType& rFrom,
+ const ValueType& rTo,
+ double t ) const
+ {
+- return lerp( rFrom, rTo, t );
++ return basegfx::tools::lerp( rFrom, rTo, t );
+ }
+ };
+
+diff --git slideshow/source/engine/shapes/viewshape.cxx slideshow/source/engine/shapes/viewshape.cxx
+index 61e07ed..84094db 100644
+--- slideshow/source/engine/shapes/viewshape.cxx
++++ slideshow/source/engine/shapes/viewshape.cxx
+@@ -59,7 +59,6 @@
+
+ #include "viewshape.hxx"
+ #include "tools.hxx"
+-#include "lerp.hxx"
+
+ #include <boost/bind.hpp>
+
+@@ -463,9 +462,9 @@ namespace slideshow
+ if( mbForceUpdate || (nUpdateFlags & ALPHA) )
+ {
+ mpSprite->setAlpha( (pAttr && pAttr->isAlphaValid()) ?
+- ::canvas::tools::clamp(pAttr->getAlpha(),
+- 0.0,
+- 1.0) :
++ ::basegfx::clamp(pAttr->getAlpha(),
++ 0.0,
++ 1.0) :
+ 1.0 );
+ }
+ if( mbForceUpdate || (nUpdateFlags & CLIP) )
+diff --git slideshow/source/engine/tools.cxx slideshow/source/engine/tools.cxx
+index b4caa0a..ecac060 100644
+--- slideshow/source/engine/tools.cxx
++++ slideshow/source/engine/tools.cxx
+@@ -51,10 +51,10 @@
+ #include <basegfx/vector/b2ivector.hxx>
+ #include <basegfx/matrix/b2dhommatrix.hxx>
+ #include <basegfx/numeric/ftools.hxx>
++#include <basegfx/tools/lerp.hxx>
+
+ #include <cppcanvas/basegfxfactory.hxx>
+
+-#include "lerp.hxx"
+ #include "unoview.hxx"
+ #include "smilfunctionparser.hxx"
+ #include "tools.hxx"
+@@ -641,18 +641,18 @@ namespace slideshow
+ const ::basegfx::B2DRange& rShapeBounds )
+ {
+ return ::basegfx::B2DRectangle(
+- lerp( rShapeBounds.getMinX(),
+- rShapeBounds.getMaxX(),
+- rUnitBounds.getMinX() ),
+- lerp( rShapeBounds.getMinY(),
+- rShapeBounds.getMaxY(),
+- rUnitBounds.getMinY() ),
+- lerp( rShapeBounds.getMinX(),
+- rShapeBounds.getMaxX(),
+- rUnitBounds.getMaxX() ),
+- lerp( rShapeBounds.getMinY(),
+- rShapeBounds.getMaxY(),
+- rUnitBounds.getMaxY() ) );
++ basegfx::tools::lerp( rShapeBounds.getMinX(),
++ rShapeBounds.getMaxX(),
++ rUnitBounds.getMinX() ),
++ basegfx::tools::lerp( rShapeBounds.getMinY(),
++ rShapeBounds.getMaxY(),
++ rUnitBounds.getMinY() ),
++ basegfx::tools::lerp( rShapeBounds.getMinX(),
++ rShapeBounds.getMaxX(),
++ rUnitBounds.getMaxX() ),
++ basegfx::tools::lerp( rShapeBounds.getMinY(),
++ rShapeBounds.getMaxY(),
++ rUnitBounds.getMaxY() ) );
+ }
+
+ ::basegfx::B2DRectangle getShapePosSize( const ::basegfx::B2DRectangle& rOrigBounds,
+diff --git slideshow/source/inc/lerp.hxx slideshow/source/inc/lerp.hxx
+deleted file mode 100644
+index 83f3da0..0000000
+--- slideshow/source/inc/lerp.hxx
++++ /dev/null
+@@ -1,62 +0,0 @@
+-/*************************************************************************
+- *
+- * 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 INCLUDED_SLIDESHOW_LERP_HXX
+-#define INCLUDED_SLIDESHOW_LERP_HXX
+-
+-#include <sal/types.h>
+-
+-namespace slideshow
+-{
+- namespace internal
+- {
+-
+- /** 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 /* INCLUDED_SLIDESHOW_LERP_HXX */
diff --git a/patches/test/slideshow-primitives.diff b/patches/test/slideshow-primitives.diff
new file mode 100644
index 0000000..8bd28ac
--- /dev/null
+++ b/patches/test/slideshow-primitives.diff
@@ -0,0 +1,1774 @@
+Move slideshow to drawinglayer primitives
+
+From: Thorsten Behrens <thb at openoffice.org>
+
+
+---
+
+ .../drawinglayer/processor2d/canvasprocessor.hxx | 4
+ .../source/processor2d/canvasprocessor.cxx | 1480 ++------------------
+ offapi/com/sun/star/graphic/XPrimitive2D.idl | 21
+ .../com/sun/star/graphic/XPrimitiveFactory2D.idl | 72 +
+ 4 files changed, 252 insertions(+), 1325 deletions(-)
+
+
+diff --git drawinglayer/inc/drawinglayer/processor2d/canvasprocessor.hxx drawinglayer/inc/drawinglayer/processor2d/canvasprocessor.hxx
+index 8e46feb..55e89e3 100644
+--- drawinglayer/inc/drawinglayer/processor2d/canvasprocessor.hxx
++++ drawinglayer/inc/drawinglayer/processor2d/canvasprocessor.hxx
+@@ -120,6 +120,10 @@ namespace drawinglayer
+ canvasProcessor2D(
+ const geometry::ViewInformation2D& rViewInformation,
+ OutputDevice& rOutDev);
++ canvasProcessor2D(
++ const geometry::ViewInformation2D& rViewInformation,
++ const com::sun::star::uno::Reference< com::sun::star::rendering::XCanvas >& xCanvas,
++ const com::sun::star::rendering::ViewState& rViewState );
+ virtual ~canvasProcessor2D();
+
+ // access to Drawinglayer configuration options
+diff --git drawinglayer/source/processor2d/canvasprocessor.cxx drawinglayer/source/processor2d/canvasprocessor.cxx
+index f99634f..6695cb4 100644
+--- drawinglayer/source/processor2d/canvasprocessor.cxx
++++ drawinglayer/source/processor2d/canvasprocessor.cxx
+@@ -81,1206 +81,6 @@
+
+ using namespace com::sun::star;
+
+-//////////////////////////////////////////////////////////////////////////////
+-// AW: Adding the canvas example from THB here to extract stuff later
+-/*
+- // TODO(Q3): share impCreateEmptyBitmapWithPattern() and other
+- // helper methods with vclprocessor.cxx
+- Bitmap impCreateEmptyBitmapWithPattern(Bitmap aSource, const Size& aTargetSizePixel)
+- {
+- Bitmap aRetval;
+- BitmapReadAccess* pReadAccess = aSource.AcquireReadAccess();
+-
+- if(pReadAccess)
+- {
+- if(aSource.GetBitCount() <= 8)
+- {
+- BitmapPalette aPalette(pReadAccess->GetPalette());
+- aRetval = Bitmap(aTargetSizePixel, aSource.GetBitCount(), &aPalette);
+- }
+- else
+- {
+- aRetval = Bitmap(aTargetSizePixel, aSource.GetBitCount());
+- }
+-
+- delete pReadAccess;
+- }
+-
+- return aRetval;
+- }
+-
+- Bitmap impModifyBitmap(const basegfx::BColorModifier& rModifier, const Bitmap& rSource)
+- {
+- Bitmap aRetval(rSource);
+-
+- switch(rModifier.getMode())
+- {
+- case basegfx::BCOLORMODIFYMODE_REPLACE :
+- {
+- aRetval = impCreateEmptyBitmapWithPattern(aRetval, Size(1L, 1L));
+- aRetval.Erase(Color(rModifier.getBColor()));
+- break;
+- }
+-
+- default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE
+- {
+- BitmapWriteAccess* pContent = aRetval.AcquireWriteAccess();
+-
+- if(pContent)
+- {
+- for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
+- {
+- for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
+- {
+- const Color aColor = pContent->GetPixel(y, x);
+- const basegfx::BColor aBColor(rModifier.getModifiedColor(aColor.getBColor()));
+- pContent->SetPixel(y, x, BitmapColor(Color(aBColor)));
+- }
+- }
+-
+- delete pContent;
+- }
+-
+- break;
+- }
+- }
+-
+- return aRetval;
+- }
+-
+- Bitmap impModifyBitmap(const basegfx::BColorModifierStack& rBColorModifierStack, const Bitmap& rSource)
+- {
+- Bitmap aRetval(rSource);
+-
+- for(sal_uInt32 a(rBColorModifierStack.count()); a; )
+- {
+- const basegfx::BColorModifier& rModifier = rBColorModifierStack.getBColorModifier(--a);
+- aRetval = impModifyBitmap(rModifier, aRetval);
+- }
+-
+- return aRetval;
+- }
+-
+- sal_uInt32 impCalcGradientSteps(sal_uInt32 nSteps, const basegfx::B2DRange& rRange, sal_uInt32 nMaxDist)
+- {
+- if(nSteps == 0L)
+- nSteps = (sal_uInt32)(rRange.getWidth() + rRange.getHeight()) / 8;
+-
+- if(nSteps < 2L)
+- {
+- nSteps = 2L;
+- }
+-
+- if(nSteps > nMaxDist)
+- {
+- nSteps = nMaxDist;
+- }
+-
+- return nSteps;
+- }
+-
+- void canvasProcessor::impDrawGradientSimple(
+- const basegfx::B2DPolyPolygon& rTargetForm,
+- const ::std::vector< basegfx::B2DHomMatrix >& rMatrices,
+- const ::std::vector< basegfx::BColor >& rColors,
+- const basegfx::B2DPolygon& rUnitPolygon)
+- {
+- uno::Reference< rendering::XPolyPolygon2D > xPoly(
+- basegfx::unotools::xPolyPolygonFromB2DPolygon(
+- mxCanvas->getDevice(),
+- rUnitPolygon));
+- uno::Reference< rendering::XPolyPolygon2D > xTargetPoly(
+- basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+- mxCanvas->getDevice(),
+- rTargetForm));
+-
+- for(sal_uInt32 a(0L); a < rColors.size(); a++)
+- {
+- // set correct color
+- const basegfx::BColor aFillColor(rColors[a]);
+-
+- maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+- mxCanvas->getDevice(),
+- aFillColor);
+-
+- if(a)
+- {
+- if(a - 1L < rMatrices.size())
+- {
+- canvas::tools::setRenderStateTransform( maRenderState,
+- rMatrices[a - 1L] );
+- mxCanvas->fillPolyPolygon(xPoly,maViewState,maRenderState);
+- }
+- }
+- else
+- {
+- canvas::tools::setRenderStateTransform( maRenderState,
+- basegfx::B2DHomMatrix() );
+- mxCanvas->fillPolyPolygon(xTargetPoly,maViewState,maRenderState);
+- }
+- }
+- }
+-
+- void canvasProcessor::impDrawGradientComplex(
+- const basegfx::B2DPolyPolygon& rTargetForm,
+- const ::std::vector< basegfx::B2DHomMatrix >& rMatrices,
+- const ::std::vector< basegfx::BColor >& rColors,
+- const basegfx::B2DPolygon& rUnitPolygon)
+- {
+- uno::Reference< rendering::XPolyPolygon2D > xPoly(
+- basegfx::unotools::xPolyPolygonFromB2DPolygon(
+- mxCanvas->getDevice(),
+- rUnitPolygon));
+- uno::Reference< rendering::XPolyPolygon2D > xTargetPoly(
+- basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+- mxCanvas->getDevice(),
+- rTargetForm));
+-
+- maRenderState.Clip = xTargetPoly;
+-
+- // draw gradient PolyPolygons
+- for(std::size_t a = 0L; a < rMatrices.size(); a++)
+- {
+- // set correct color
+- if(rColors.size() > a)
+- {
+- const basegfx::BColor aFillColor(rColors[a]);
+-
+- maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+- mxCanvas->getDevice(),
+- aFillColor);
+- }
+-
+- canvas::tools::setRenderStateTransform( maRenderState,
+- rMatrices[a] );
+-
+- if(a)
+- mxCanvas->fillPolyPolygon(xPoly,maViewState,maRenderState);
+- else
+- mxCanvas->fillPolyPolygon(xTargetPoly,maViewState,maRenderState);
+- }
+-
+- maRenderState.Clip.clear();
+- }
+-
+- void canvasProcessor::impDrawGradient(
+- const basegfx::B2DPolyPolygon& rTargetForm,
+- ::drawinglayer::primitive::GradientStyle eGradientStyle,
+- sal_uInt32 nSteps,
+- const basegfx::BColor& rStart,
+- const basegfx::BColor& rEnd,
+- double fBorder, double fAngle, double fOffsetX, double fOffsetY, bool bSimple)
+- {
+- fprintf(stderr,"impDrawGradient\n");
+-
+- basegfx::B2DPolyPolygon aTmp(rTargetForm);
+- aTmp.transform( maWorldToView );
+- const basegfx::B2DRange aOutlineRangePixel(basegfx::tools::getRange(aTmp));
+- const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(rTargetForm));
+-
+- fprintf(stderr,"impDrawGradient: #%d\n",nSteps);
+-
+- if( // step count is infinite, can use native canvas
+- // gradients here
+- nSteps == 0 ||
+- // step count is sufficiently high, such that no
+- // discernible difference should be visible.
+- nSteps > 64 )
+- {
+- uno::Reference< rendering::XParametricPolyPolygon2DFactory > xFactory(
+- mxCanvas->getDevice()->getParametricPolyPolygonFactory() );
+-
+- if( xFactory.is() )
+- {
+- fprintf(stderr,"native gradient #1\n");
+-
+- basegfx::B2DHomMatrix aTextureTransformation;
+- rendering::Texture aTexture;
+-
+- aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
+- aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
+- aTexture.Alpha = 1.0;
+-
+-
+- // setup start/end color values
+- // ----------------------------
+-
+- const uno::Sequence< double > aStartColor(
+- basegfx::unotools::colorToDoubleSequence( mxCanvas->getDevice(),
+- rStart ));
+- const uno::Sequence< double > aEndColor(
+- basegfx::unotools::colorToDoubleSequence( mxCanvas->getDevice(),
+- rEnd ));
+-
+- // Setup texture transformation
+- // ----------------------------
+-
+- const basegfx::B2DRange& rBounds(
+- basegfx::tools::getRange( rTargetForm ));
+-
+- // setup rotation angle. VCL rotates
+- // counter-clockwise, while canvas transformation
+- // rotates clockwise
+- //fAngle = -fAngle;
+-
+- switch(eGradientStyle)
+- {
+- case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR:
+- // FALLTHROUGH intended
+- case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL:
+- {
+- // standard orientation for VCL linear
+- // gradient is vertical, thus, rotate 90
+- // degrees
+- fAngle += M_PI/2.0;
+-
+- // shrink texture, to account for border
+- // (only in x direction, linear gradient
+- // is constant in y direction, anyway)
+- aTextureTransformation.scale(
+- basegfx::pruneScaleValue(1.0 - fBorder),
+- 1.0 );
+-
+- double fBorderX(0.0);
+-
+- // determine type of gradient (and necessary
+- // transformation matrix, should it be emulated by a
+- // generic gradient)
+- switch(eGradientStyle)
+- {
+- case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR:
+- // 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. Gradient is
+- // invariant in y direction: leave
+- // y offset alone.
+- fBorderX = fBorder;
+- aTexture.Gradient = xFactory->createLinearHorizontalGradient( aStartColor,
+- aEndColor );
+- break;
+-
+- case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL:
+- // axial gradients have border on
+- // both sides. Gradient is
+- // invariant in y direction: leave
+- // y offset alone.
+- fBorderX = fBorder * .5;
+- aTexture.Gradient = xFactory->createAxialHorizontalGradient( aStartColor,
+- aEndColor );
+- break;
+- }
+-
+- // apply border offset values
+- aTextureTransformation.translate( fBorderX,
+- 0.0 );
+-
+- // rotate texture according to gradient rotation
+- aTextureTransformation.translate( -0.5, -0.5 );
+- aTextureTransformation.rotate( fAngle );
+-
+- // 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( rBounds.getHeight()*sin(fAngle) ) +
+- fabs( rBounds.getWidth()*cos(fAngle) )));
+-
+- aTextureTransformation.scale( nScale, nScale );
+-
+- // translate back origin to center of
+- // primitive
+- aTextureTransformation.translate( 0.5*rBounds.getWidth(),
+- 0.5*rBounds.getHeight() );
+- break;
+- }
+-
+- case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL:
+- // FALLTHROUGH intended
+- case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL:
+- // FALLTHROUGH intended
+- case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE:
+- // FALLTHROUGH intended
+- case ::drawinglayer::primitive::GRADIENTSTYLE_RECT:
+- {
+- fprintf(stderr,"native gradient #2\n");
+-
+- // 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( rBounds.getWidth() * (1.0 - fBorder) );
+- double nScaleY( rBounds.getHeight()* (1.0 - fBorder) );
+-
+- // determine offset values. Since the
+- // border is divided half-by-half to both
+- // sides of the gradient, divide
+- // translation offset by an additional
+- // factor of 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( rBounds.getWidth() *
+- (2.0 * fOffsetX - 1.0 + fBorder)*.5 );
+- double nOffsetY( rBounds.getHeight() *
+- (2.0 * fOffsetY - 1.0 + fBorder)*.5 );
+-
+- // determine type of gradient (and necessary
+- // transformation matrix, should it be emulated by a
+- // generic gradient)
+- switch(eGradientStyle)
+- {
+- case ::drawinglayer::primitive::GRADIENTSTYLE_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(rBounds.getWidth(),
+- rBounds.getHeight()) / nScaleX );
+- aTextureTransformation.scale( nScale, nScale );
+- aTextureTransformation.translate( 0.5, 0.5 );
+-
+- aTexture.Gradient = xFactory->createEllipticalGradient(
+- aEndColor,
+- aStartColor,
+- cssgeom::RealRectangle2D(0.0,0.0,
+- 1.0,1.0) );
+- }
+- break;
+-
+- case ::drawinglayer::primitive::GRADIENTSTYLE_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(
+- aEndColor,
+- aStartColor,
+- cssgeom::RealRectangle2D( rBounds.getMinX(),
+- rBounds.getMinY(),
+- rBounds.getMaxX(),
+- rBounds.getMaxY() ));
+- }
+- break;
+-
+- case ::drawinglayer::primitive::GRADIENTSTYLE_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(
+- aEndColor,
+- aStartColor,
+- cssgeom::RealRectangle2D(0.0,0.0,
+- 1.0,1.0));
+- }
+- break;
+-
+- case ::drawinglayer::primitive::GRADIENTSTYLE_RECT:
+- {
+- aTexture.Gradient = xFactory->createRectangularGradient(
+- aEndColor,
+- aStartColor,
+- cssgeom::RealRectangle2D( rBounds.getMinX(),
+- rBounds.getMinY(),
+- rBounds.getMaxX(),
+- rBounds.getMaxY() ));
+- }
+- 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( fAngle );
+- aTextureTransformation.translate( 0.5*nScaleX, 0.5*nScaleY );
+-
+- aTextureTransformation.translate( nOffsetX, nOffsetY );
+- }
+- break;
+-
+- default:
+- OSL_ENSURE( false,
+- "canvasProcessor::impDrawGradient(): Unexpected gradient type" );
+- break;
+- }
+-
+- // As the texture coordinate space is relative to
+- // the polygon coordinate space (NOT to the
+- // polygon itself), move gradient to the start of
+- // the actual polygon. If we skip this, the
+- // gradient will always display at the origin, and
+- // not within the polygon bound (which might be
+- // miles away from the origin).
+- aTextureTransformation.translate( rBounds.getMinX(),
+- rBounds.getMinY() );
+-
+- basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
+- aTextureTransformation );
+- uno::Sequence< rendering::Texture > aSeq(1);
+- aSeq[0] = aTexture;
+-
+- mxCanvas->fillTexturedPolyPolygon(
+- basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+- mxCanvas->getDevice(),
+- rTargetForm),
+- maViewState,
+- maRenderState,
+- aSeq );
+-
+- // done, using native gradients
+- return;
+- }
+- }
+- else
+- {
+- // make sure steps is not too high/low
+- nSteps = impCalcGradientSteps(nSteps,
+- aOutlineRangePixel,
+- sal_uInt32((rStart.getMaximumDistance(rEnd) * 127.5) + 0.5));
+-
+-
+- ::std::vector< basegfx::B2DHomMatrix > aMatrices;
+- ::std::vector< basegfx::BColor > aColors;
+- basegfx::B2DPolygon aUnitPolygon;
+-
+- if( drawinglayer::primitive::GRADIENTSTYLE_RADIAL == eGradientStyle ||
+- drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL == eGradientStyle)
+- {
+- const basegfx::B2DPoint aCircleCenter(0.5, 0.5);
+- aUnitPolygon = basegfx::tools::createPolygonFromEllipse(aCircleCenter, 0.5, 0.5);
+- aUnitPolygon = basegfx::tools::adaptiveSubdivideByAngle(aUnitPolygon);
+- }
+- else
+- {
+- aUnitPolygon = basegfx::tools::createPolygonFromRect(
+- basegfx::B2DRange(0.0, 0.0, 1.0, 1.0));
+- }
+-
+- // create geometries
+- switch(eGradientStyle)
+- {
+- case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR:
+- {
+- ::drawinglayer::primitive::geoTexSvxGradientLinear aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle);
+- aGradient.appendTransformations(aMatrices);
+- aGradient.appendColors(aColors);
+- break;
+- }
+- case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL:
+- {
+- ::drawinglayer::primitive::geoTexSvxGradientAxial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle);
+- aGradient.appendTransformations(aMatrices);
+- aGradient.appendColors(aColors);
+- break;
+- }
+- case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL:
+- {
+- ::drawinglayer::primitive::geoTexSvxGradientRadial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetY);
+- aGradient.appendTransformations(aMatrices);
+- aGradient.appendColors(aColors);
+- break;
+- }
+- case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL:
+- {
+- ::drawinglayer::primitive::geoTexSvxGradientElliptical aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
+- aGradient.appendTransformations(aMatrices);
+- aGradient.appendColors(aColors);
+- break;
+- }
+- case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE:
+- {
+- ::drawinglayer::primitive::geoTexSvxGradientSquare aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
+- aGradient.appendTransformations(aMatrices);
+- aGradient.appendColors(aColors);
+- break;
+- }
+- case ::drawinglayer::primitive::GRADIENTSTYLE_RECT:
+- {
+- ::drawinglayer::primitive::geoTexSvxGradientRect aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
+- aGradient.appendTransformations(aMatrices);
+- aGradient.appendColors(aColors);
+- break;
+- }
+- }
+-
+- // paint them with mask using the XOR method
+- if(aMatrices.size())
+- {
+- if(bSimple)
+- {
+- impDrawGradientSimple(rTargetForm, aMatrices, aColors, aUnitPolygon);
+- }
+- else
+- {
+- impDrawGradientComplex(rTargetForm, aMatrices, aColors, aUnitPolygon);
+- }
+- }
+- }
+- }
+-
+-
+- //////////////////////////////////////////////////////////////////////////////
+- // rendering support
+-
+- // directdraw of text simple portion
+- void canvasProcessor::impRender_STXP(const textSimplePortionPrimitive& rTextCandidate)
+- {
+- const fontAttributes& rFontAttrs( rTextCandidate.getFontAttributes() );
+- rendering::FontRequest aFontRequest;
+-
+- aFontRequest.FontDescription.FamilyName = rFontAttrs.maFamilyName;
+- aFontRequest.FontDescription.StyleName = rFontAttrs.maStyleName;
+- aFontRequest.FontDescription.IsSymbolFont = rFontAttrs.mbSymbol ? util::TriState_YES : util::TriState_NO;
+- aFontRequest.FontDescription.IsVertical = rFontAttrs.mbVertical ? util::TriState_YES : util::TriState_NO;
+-
+- // TODO(F2): improve vclenum->panose conversion
+- aFontRequest.FontDescription.FontDescription.Weight =
+- rFontAttrs.mnWeight;
+- aFontRequest.FontDescription.FontDescription.Letterform =
+- rFontAttrs.mbItalic ? 9 : 0;
+-
+- // font matrix should only be used for glyph rotations etc.
+- css::geometry::Matrix2D aFontMatrix;
+- canvas::tools::setIdentityMatrix2D( aFontMatrix );
+-
+- uno::Reference<rendering::XCanvasFont> xFont(
+- mxCanvas->createFont( aFontRequest,
+- uno::Sequence< beans::PropertyValue >(),
+- aFontMatrix ));
+-
+- if( !xFont.is() )
+- return;
+-
+- uno::Reference<rendering::XTextLayout> xLayout(
+- xFont->createTextLayout(
+- rendering::StringContext( rTextCandidate.getText(),
+- 0,
+- rTextCandidate.getText().Len() ),
+- // TODO(F3): Is this sufficient?
+- rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
+- 0 ));
+- if( !xLayout.is() )
+- return;
+-
+- xLayout->applyLogicalAdvancements(
+- uno::Sequence<double>(&rTextCandidate.getDXArray()[0],
+- rTextCandidate.getDXArray().size() ));
+-
+- const basegfx::BColor aRGBColor(
+- maBColorModifierStack.getModifiedColor(
+- rTextCandidate.getFontColor()));
+-
+- maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+- mxCanvas->getDevice(),
+- aRGBColor);
+-
+- // get render parameters and paint
+- mxCanvas->drawTextLayout( xLayout,
+- maViewState,
+- maRenderState );
+- }
+-
+- // direct draw of hairline
+- void canvasProcessor::impRender_POHL(const polygonHairlinePrimitive& rPolygonCandidate)
+- {
+- const basegfx::BColor aRGBColor(
+- maBColorModifierStack.getModifiedColor(
+- rPolygonCandidate.getBColor()));
+-
+- maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+- mxCanvas->getDevice(),
+- aRGBColor);
+-
+- mxCanvas->drawPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolygon(
+- mxCanvas->getDevice(),
+- rPolygonCandidate.getB2DPolygon()),
+- maViewState,
+- maRenderState );
+- }
+-
+- // direct draw of transformed BitmapEx primitive
+- void canvasProcessor::impRender_BMPR(const bitmapPrimitive& rBitmapCandidate)
+- {
+- BitmapEx aBitmapEx(rBitmapCandidate.getBitmapEx());
+-
+- if(maBColorModifierStack.count())
+- {
+- // TODO(Q3): Share common bmp modification code with
+- // vclprocessor.cxx
+- Bitmap aChangedBitmap(impModifyBitmap(maBColorModifierStack, aBitmapEx.GetBitmap()));
+-
+- if(aBitmapEx.IsTransparent())
+- {
+- if(aBitmapEx.IsAlpha())
+- aBitmapEx = BitmapEx(aChangedBitmap, aBitmapEx.GetAlpha());
+- else
+- aBitmapEx = BitmapEx(aChangedBitmap, aBitmapEx.GetMask());
+- }
+- else
+- aBitmapEx = BitmapEx(aChangedBitmap);
+- }
+-
+- mxCanvas->drawBitmap(
+- vcl::unotools::xBitmapFromBitmapEx( mxCanvas->getDevice(),
+- aBitmapEx ),
+- maViewState,
+- maRenderState);
+- }
+-
+- void canvasProcessor::impRender_PPLB(const polyPolygonBitmapPrimitive& rPolyBitmapCandidate )
+- {
+- const fillBitmapAttribute& rFillBmpAttr( rPolyBitmapCandidate.getFillBitmap() );
+- const basegfx::B2DPolyPolygon& rPoly( rPolyBitmapCandidate.getB2DPolyPolygon() );
+-
+- // TODO(Q3): Share common bmp modification code with
+- // vclprocessor.cxx
+- Bitmap aChangedBitmap(
+- impModifyBitmap(maBColorModifierStack,
+- rFillBmpAttr.getBitmap()));
+-
+- rendering::Texture aTexture;
+- const basegfx::B2DVector aBmpSize( rFillBmpAttr.getSize() );
+-
+- const basegfx::B2DRange& rBounds(
+- basegfx::tools::getRange( rPoly ));
+-
+- basegfx::B2DHomMatrix aScale;
+- aScale.scale( aBmpSize.getX() * rBounds.getWidth(),
+- aBmpSize.getY() * rBounds.getHeight() );
+-
+- basegfx::unotools::affineMatrixFromHomMatrix(
+- aTexture.AffineTransform,
+- aScale );
+-
+- aTexture.Alpha = 1.0;
+- aTexture.Bitmap =
+- ::vcl::unotools::xBitmapFromBitmapEx(
+- mxCanvas->getDevice(),
+- aChangedBitmap );
+- aTexture.RepeatModeX = rendering::TexturingMode::REPEAT;
+- aTexture.RepeatModeY = rendering::TexturingMode::REPEAT;
+-
+- uno::Sequence< rendering::Texture > aSeq(1);
+- aSeq[0] = aTexture;
+-
+- mxCanvas->fillTexturedPolyPolygon(
+- basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+- mxCanvas->getDevice(),
+- rPoly),
+- maViewState,
+- maRenderState,
+- aSeq );
+- }
+-
+- // direct draw of gradient
+- void canvasProcessor::impRender_PPLG(const polyPolygonGradientPrimitive& rPolygonCandidate)
+- {
+- const fillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient());
+- basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor()));
+- basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor()));
+- basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
+-
+- if(aStartColor == aEndColor)
+- {
+- // no gradient at all, draw as polygon
+-
+- maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+- mxCanvas->getDevice(),
+- aStartColor);
+-
+- mxCanvas->drawPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+- mxCanvas->getDevice(),
+- aLocalPolyPolygon),
+- maViewState,
+- maRenderState );
+- }
+- else
+- {
+- // TODO(F3): if rGradient.getSteps() > 0, render
+- // gradient manually!
+- impDrawGradient(
+- aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(),
+- aStartColor, aEndColor, rGradient.getBorder(),
+- -rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), false);
+- }
+- }
+-
+- // direct draw of PolyPolygon with color
+- void canvasProcessor::impRender_PPLC(const polyPolygonColorPrimitive& rPolygonCandidate)
+- {
+- const basegfx::BColor aRGBColor(
+- maBColorModifierStack.getModifiedColor(
+- rPolygonCandidate.getBColor()));
+-
+- maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+- mxCanvas->getDevice(),
+- aRGBColor);
+-
+- mxCanvas->fillPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+- mxCanvas->getDevice(),
+- rPolygonCandidate.getB2DPolyPolygon()),
+- maViewState,
+- maRenderState );
+- }
+-
+- // direct draw of MetaFile
+- void canvasProcessor::impRender_META(const metafilePrimitive& rMetaCandidate)
+- {
+- // get metafile (copy it)
+- GDIMetaFile aMetaFile;
+-
+- // TODO(Q3): Share common metafile modification code with
+- // vclprocessor.cxx
+- if(maBColorModifierStack.count())
+- {
+- const basegfx::BColor aRGBBaseColor(0, 0, 0);
+- const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor));
+- aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor));
+- }
+- else
+- {
+- aMetaFile = rMetaCandidate.getMetaFile();
+- }
+-
+- cppcanvas::BitmapCanvasSharedPtr pCanvas(
+- cppcanvas::VCLFactory::getInstance().createCanvas(
+- uno::Reference<rendering::XBitmapCanvas>(
+- mxCanvas,
+- uno::UNO_QUERY_THROW) ));
+- cppcanvas::RendererSharedPtr pMtfRenderer(
+- cppcanvas::VCLFactory::getInstance().createRenderer(
+- pCanvas,
+- aMetaFile,
+- cppcanvas::Renderer::Parameters() ));
+- if( pMtfRenderer )
+- {
+- pCanvas->setTransformation(maWorldToView);
+- pMtfRenderer->setTransformation(rMetaCandidate.getTransform());
+- pMtfRenderer->draw();
+- }
+- }
+-
+- // mask group. Set mask polygon as clip
+- void canvasProcessor::impRender_MASK(const maskPrimitive& rMaskCandidate)
+- {
+- const primitiveVector& rSubList = rMaskCandidate.getPrimitiveVector();
+-
+- if(!rSubList.empty())
+- {
+- // TODO(F3): cannot use state-global renderstate, when recursing!
+- maRenderState.Clip =
+- basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+- mxCanvas->getDevice(),
+- rMaskCandidate.getMask());
+-
+- // paint to it
+- process(rSubList);
+-
+- maRenderState.Clip.clear();
+- }
+- }
+-
+- // modified color group. Force output to unified color.
+- void canvasProcessor::impRender_MCOL(const modifiedColorPrimitive& rModifiedCandidate)
+- {
+- const primitiveVector& rSubList = rModifiedCandidate.getPrimitiveVector();
+-
+- if(!rSubList.empty())
+- {
+- maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
+- process(rModifiedCandidate.getPrimitiveVector());
+- maBColorModifierStack.pop();
+- }
+- }
+-
+- // sub-transparence group. Draw to bitmap device first.
+- void canvasProcessor::impRender_TRPR(const transparencePrimitive& rTransCandidate)
+- {
+- const primitiveVector& rSubList = rTransCandidate.getPrimitiveVector();
+-
+- if(!rSubList.empty())
+- {
+- basegfx::B2DRange aRange(
+- get2DRangeFromVector(rSubList,
+- getViewInformation()));
+- aRange.transform(maWorldToView);
+- const basegfx::B2I64Tuple& rSize(
+- canvas::tools::spritePixelAreaFromB2DRange(aRange).getRange());
+- uno::Reference< rendering::XCanvas > xBitmap(
+- mxCanvas->getDevice()->createCompatibleAlphaBitmap(
+- css::geometry::IntegerSize2D(rSize.getX(),
+- rSize.getY())),
+- uno::UNO_QUERY_THROW);
+-
+- // remember last worldToView and add pixel offset
+- basegfx::B2DHomMatrix aLastWorldToView(maWorldToView);
+- basegfx::B2DHomMatrix aPixelOffset;
+- aPixelOffset.translate(aRange.getMinX(),
+- aRange.getMinY());
+- setWorldToView(aPixelOffset * maWorldToView);
+-
+- // remember last canvas, set bitmap as target
+- uno::Reference< rendering::XCanvas > xLastCanvas( mxCanvas );
+- mxCanvas = xBitmap;
+-
+- // paint content to it
+- process(rSubList);
+-
+- // TODO(F3): render transparent list to alpha
+- // channel. Note that the OutDev implementation has a
+- // shortcoming, in that nested transparency groups
+- // don't work - alpha is not combined properly.
+-
+- // process(rTransCandidate.getTransparenceList());
+-
+- // back to old OutDev and worldToView
+- mxCanvas = xLastCanvas;
+- setWorldToView(aLastWorldToView);
+-
+- // DUMMY: add alpha modulation value to DeviceColor
+- // TODO(F3): color management
+- canvas::tools::setDeviceColor( maRenderState,
+- 1.0, 1.0, 1.0, 0.5 );
+- // finally, draw bitmap
+- mxCanvas->drawBitmapModulated(
+- uno::Reference< rendering::XBitmap >(
+- xBitmap,
+- uno::UNO_QUERY_THROW),
+- maViewState,
+- maRenderState );
+- }
+- }
+-
+- // transform group.
+- void canvasProcessor::impRender_TRN2(const transformPrimitive& rTransformCandidate)
+- {
+- // remember current transformation
+- basegfx::B2DHomMatrix aLastWorldToView(maWorldToView);
+-
+- // create new transformations
+- setWorldToView(maWorldToView * rTransformCandidate.getTransformation());
+-
+- // let break down
+- process(rTransformCandidate.getPrimitiveVector());
+-
+- // restore transformations
+- setWorldToView(aLastWorldToView);
+- }
+-
+- // marker
+- void canvasProcessor::impRender_MARK(const markerPrimitive& rMarkCandidate)
+- {
+- const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rMarkCandidate.getRGBColor()));
+-
+- canvas::tools::initRenderState(maMarkerRenderState);
+- maMarkerRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+- mxCanvas->getDevice(),
+- aRGBColor);
+-
+- // Markers are special objects - their position is
+- // determined by the view transformation, but their size
+- // is always the same
+- const basegfx::B2DPoint aViewPos(maWorldToView * rMarkCandidate.getPosition());
+-
+- uno::Reference< rendering::XPolyPolygon2D > xMarkerPoly;
+- uno::Reference< rendering::XPolyPolygon2D > xHighlightMarkerPoly;
+- switch(rMarkCandidate.getStyle())
+- {
+- default:
+- case MARKERSTYLE_POINT:
+- mxCanvas->drawPoint( basegfx::unotools::point2DFromB2DPoint(aViewPos),
+- maMarkerViewState,
+- maMarkerRenderState );
+- return;
+-
+- case MARKERSTYLE_CROSS:
+- if( !mxCrossMarkerPoly.is() )
+- {
+- basegfx::B2DPolyPolygon aPoly;
+- basegfx::tools::importFromSvgD(
+- aPoly,
+- rtl::OUString::createFromAscii(
+- "m-1 0 h2 m0 -1 v2" ));
+- mxCrossMarkerPoly =
+- basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+- mxCanvas->getDevice(),
+- aPoly );
+- }
+- xMarkerPoly = mxCrossMarkerPoly;
+- break;
+-
+- case MARKERSTYLE_GLUEPOINT :
+- if( !mxGluePointPoly.is() )
+- {
+- basegfx::B2DPolyPolygon aPoly;
+- basegfx::tools::importFromSvgD(
+- aPoly,
+- rtl::OUString::createFromAscii(
+- "m-2 -3 l5 5 m-3 -2 l5 5 m-3 2 l5 -5 m-2 3 l5 -5" ));
+- mxGluePointPoly =
+- basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+- mxCanvas->getDevice(),
+- aPoly );
+- }
+- if( !mxGluePointHighlightPoly.is() )
+- {
+- basegfx::B2DPolyPolygon aPoly;
+- basegfx::tools::importFromSvgD(
+- aPoly,
+- rtl::OUString::createFromAscii(
+- "m-2 -2 l4 4 m-2 2 l4 -4" ));
+- mxGluePointHighlightPoly =
+- basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+- mxCanvas->getDevice(),
+- aPoly );
+- }
+- xMarkerPoly = mxGluePointPoly;
+- xHighlightMarkerPoly = mxGluePointHighlightPoly;
+- break;
+- }
+-
+- basegfx::B2DRange aRange;
+- rMarkCandidate.getRealtiveViewRange(aRange);
+- const basegfx::B2DPoint aCenter(aRange.getCenter());
+-
+- basegfx::B2DHomMatrix aTranslate;
+- aTranslate.translate(aViewPos.getX()+aCenter.getX(),
+- aViewPos.getY()+aCenter.getY());
+-
+- canvas::tools::setRenderStateTransform( maMarkerRenderState,
+- aTranslate );
+-
+-
+- mxCanvas->drawPolyPolygon( xMarkerPoly,
+- maMarkerViewState,
+- maMarkerRenderState );
+- if( xHighlightMarkerPoly.is() )
+- {
+- // TODO(F3): color management
+- canvas::tools::setDeviceColor(maMarkerRenderState,
+- 0.0, 0.0, 1.0, 1.0);
+- mxCanvas->drawPolyPolygon( xMarkerPoly,
+- maMarkerViewState,
+- maMarkerRenderState );
+- }
+- }
+-
+- void canvasProcessor::setWorldToView(const basegfx::B2DHomMatrix& rMat)
+- {
+- maWorldToView = rMat;
+- canvas::tools::setViewStateTransform(maViewState,
+- maWorldToView);
+- }
+-
+- //////////////////////////////////////////////////////////////////////////////
+- // internal processing support
+-
+- void canvasProcessor::process(const primitiveVector& rSource)
+- {
+- primitiveVector::const_iterator aCurr = rSource.begin();
+- const primitiveVector::const_iterator aEnd = rSource.end();
+- while( aCurr != aEnd )
+- {
+- const referencedPrimitive& rCandidate = *aCurr;
+-
+- switch(rCandidate.getID())
+- {
+- case CreatePrimitiveID('S', 'T', 'X', 'P'):
+- {
+- // directdraw of text simple portion
+- impRender_STXP(static_cast< const textSimplePortionPrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('P', 'O', 'H', 'L'):
+- {
+- // direct draw of hairline
+- impRender_POHL(static_cast< const polygonHairlinePrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('B', 'M', 'P', 'R'):
+- {
+- // direct draw of transformed BitmapEx primitive
+- impRender_BMPR(static_cast< const bitmapPrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('F', 'B', 'M', 'P'):
+- {
+- OSL_ENSURE(false,"fillBitmapPrimitive not yet implemented");
+- break;
+- }
+-
+- case CreatePrimitiveID('P', 'P', 'L', 'B'):
+- {
+- // direct draw of polygon with bitmap fill
+- impRender_PPLB(static_cast< const polyPolygonBitmapPrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('P', 'P', 'L', 'G'):
+- {
+- // direct draw of gradient
+- impRender_PPLG(static_cast< const polyPolygonGradientPrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('P', 'P', 'L', 'C'):
+- {
+- // direct draw of PolyPolygon with color
+- impRender_PPLC(static_cast< const polyPolygonColorPrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('M', 'E', 'T', 'A'):
+- {
+- // direct draw of MetaFile
+- impRender_META(static_cast< const metafilePrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('M', 'A', 'S', 'K'):
+- {
+- // mask group. Force output to VDev and create mask from given mask
+- impRender_MASK(static_cast< const maskPrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('M', 'C', 'O', 'L'):
+- {
+- // modified color group. Force output to unified color.
+- impRender_MCOL(static_cast< const modifiedColorPrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('T', 'R', 'P', 'R'):
+- {
+- // sub-transparence group. Draw to VDev first.
+- impRender_TRPR(static_cast< const transparencePrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('T', 'R', 'N', '2'):
+- {
+- // transform group.
+- impRender_TRN2(static_cast< const transformPrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('M', 'A', 'R', 'K'):
+- {
+- // marker
+- impRender_MARK(static_cast< const markerPrimitive& >(rCandidate.getBasePrimitive()));
+- break;
+- }
+-
+- case CreatePrimitiveID('A', 'N', 'S', 'W'):
+- case CreatePrimitiveID('A', 'N', 'B', 'L'):
+- case CreatePrimitiveID('A', 'N', 'I', 'N'):
+- {
+- // check timing, but do not accept
+- const animatedSwitchPrimitive& rAnimatedCandidate(static_cast< const animatedSwitchPrimitive& >(rCandidate.getBasePrimitive()));
+- const ::drawinglayer::animation::animationEntryList& rAnimationList = rAnimatedCandidate.getAnimationList();
+- const double fNewTime(rAnimationList.getNextEventTime(getViewInformation().getViewTime()));
+-
+- // let break down
+- process(rAnimatedCandidate.getDecomposition(getViewInformation()));
+-
+- break;
+- }
+-
+- default:
+- {
+- // let break down
+- process(rCandidate.getBasePrimitive().getDecomposition(getViewInformation()));
+- }
+- }
+-
+- ++aCurr;
+- }
+- }
+-
+- canvasProcessor::canvasProcessor( const ::drawinglayer::geometry::viewInformation& rViewInformation,
+- const uno::Reference<rendering::XCanvas>& rCanvas ) :
+- processor(rViewInformation),
+- mxCanvas( rCanvas ),
+- mxCrossMarkerPoly(),
+- mxGluePointPoly(),
+- mxGluePointHighlightPoly(),
+- maBColorModifierStack(),
+- maWorldToView(),
+- maViewState(),
+- maRenderState(),
+- maMarkerViewState(),
+- maMarkerRenderState()
+- {
+- canvas::tools::initViewState(maViewState);
+- canvas::tools::initRenderState(maRenderState);
+- canvas::tools::initViewState(maMarkerViewState);
+- canvas::tools::initRenderState(maMarkerRenderState);
+-
+- maWorldToView = maViewInformation.getViewTransformation();
+-
+- canvas::tools::setViewStateTransform(maViewState,
+- maWorldToView);
+- }
+-
+- canvasProcessor::~canvasProcessor()
+- {}
+-*/
+-//////////////////////////////////////////////////////////////////////////////
+-
+ namespace drawinglayer
+ {
+ namespace processor2d
+@@ -1309,7 +109,7 @@ namespace drawinglayer
+ // alpha-using XBitmap for content and draw the mask as alpha. Both have their
+ // advantages and disadvantages, so here are both with a bool allowing simple
+ // change
+- if(bUseMaskBitmapMethod)
++ if(bUseMaskBitmapMethod && mpOutputDevice)
+ {
+ // get logic range of transparent part, clip with ViewRange
+ basegfx::B2DRange aLogicRange(aMask.getB2DRange());
+@@ -1415,55 +215,45 @@ namespace drawinglayer
+ }
+ else
+ {
+- // transform new mask polygon to view coordinates for processing. All masks
+- // are processed in view coordinates and clipped against each other evtl. to
++ // transform new mask polygon to view
++ // coordinates for processing. All masks are
++ // processed in view coordinates and clipped
++ // against each other (if necessary), to
+ // create multi-clips
+ aMask.transform(getViewInformation2D().getObjectTransformation());
+
+- // remember last current clip polygon
+ const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
++ const uno::Reference<rendering::XPolyPolygon2D> xLastClipPoly = maViewState.Clip;
+
+- if(maClipPolyPolygon.count())
++ if(xLastClipPoly.is())
+ {
+- // there is already a clip polygon set; build clipped union of
+- // current mask polygon and new one
++ // build clipped union of current mask
++ // polygon and new one - this is to avoid
++ // costly, repeated clip calculations
++ // inside the canvas impls for all the
++ // mask group contents
+ maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(aMask, maClipPolyPolygon, false, false);
+ }
+ else
+ {
+- // use mask directly
+ maClipPolyPolygon = aMask;
+ }
+
+- // set at ViewState
+- if(maClipPolyPolygon.count())
+- {
+- // set new as clip polygon
+- maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
+- }
+- else
+- {
+- // empty, reset
+- maViewState.Clip.clear();
+- }
++ // set new clip polygon at viewstate -
++ // unconditionally, an empty maClipPolyPolygon
++ // denotes the empty clip (nothing visible),
++ // and need not be confused with the empty
++ // interface (the null clip, i.e. everything
++ // visible)
++ maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(),
++ maClipPolyPolygon);
+
+ // paint content
+ process(rChildren);
+
+ // restore local current to rescued clip polygon
+ maClipPolyPolygon = aLastClipPolyPolygon;
+-
+- // set at ViewState
+- if(maClipPolyPolygon.count())
+- {
+- // set new as clip polygon
+- maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
+- }
+- else
+- {
+- // empty, reset
+- maViewState.Clip.clear();
+- }
++ maViewState.Clip = xLastClipPoly;
+ }
+ }
+ }
+@@ -1499,6 +289,8 @@ namespace drawinglayer
+
+ void canvasProcessor2D::impRenderTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate)
+ {
++ static bool bAvoidShearedText(true);
++
+ if(rTextCandidate.getTextLength())
+ {
+ double fShearX(0.0);
+@@ -1509,10 +301,12 @@ namespace drawinglayer
+ aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+ }
+
+- if(!basegfx::fTools::equalZero(fShearX))
++ if(bAvoidShearedText && !basegfx::fTools::equalZero(fShearX))
+ {
+- // text is sheared. As long as the canvas renderers do not support this,
+- // use the decomposed primitive
++ // text is sheared. As long as the canvas
++ // renderers do not support this, use the
++ // decomposed primitive (iirc this is only a
++ // problem with vclcanvas)
+ process(rTextCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ else
+@@ -1532,7 +326,9 @@ namespace drawinglayer
+ aFontRequest.CellSize = 1.0;
+ aFontRequest.Locale = rTextCandidate.getLocale();
+
+- // font matrix should only be used for glyph rotations etc.
++ // font matrix should only be used for glyph
++ // rotations etc. - why, then use it for sheared
++ // text, no?
+ com::sun::star::geometry::Matrix2D aFontMatrix;
+ canvas::tools::setIdentityMatrix2D(aFontMatrix);
+
+@@ -1640,86 +436,93 @@ namespace drawinglayer
+ {
+ // get discrete range of transparent part
+ basegfx::B2DRange aDiscreteRange(aLogicRange);
+- aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
+-
+- // expand to next covering discrete values (pixel bounds)
++ aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
++
++ // expand to next covering discrete values (pixel bounds)
+ aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY())));
+ aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY())));
+
+- // use VCL-based buffer device
+- impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false);
++ if( mpOutputDevice )
++ {
++ // use VCL-based buffer device
++ impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false);
+
+- if(aBufferDevice.isVisible())
+- {
+- // remember current OutDev, Canvas and ViewInformation
+- OutputDevice* pLastOutputDevice = mpOutputDevice;
+- uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas);
+- const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
+-
+- // prepare discrete offset for XBitmap, do not forget that the buffer bitmap
+- // may be truncated to discrete visible pixels
+- basegfx::B2DHomMatrix aDiscreteOffset;
+- aDiscreteOffset.translate(
+- aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0,
+- aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0);
+-
+- // create new local ViewInformation2D with new transformation
+- const geometry::ViewInformation2D aViewInformation2D(
+- getViewInformation2D().getObjectTransformation(),
+- aDiscreteOffset * getViewInformation2D().getViewTransformation(),
+- getViewInformation2D().getViewport(),
+- getViewInformation2D().getVisualizedPage(),
+- getViewInformation2D().getViewTime(),
+- getViewInformation2D().getExtendedInformationSequence());
+- updateViewInformation(aViewInformation2D);
+-
+- // set OutDev and Canvas to content target
+- mpOutputDevice = &aBufferDevice.getContent();
+- mxCanvas = mpOutputDevice->GetCanvas();
+- canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
+-
+- // if ViewState transform is changed, the clipping polygon needs to be adapted, too
+- const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon);
+-
+- if(maClipPolyPolygon.count())
++ if(aBufferDevice.isVisible())
+ {
+- maClipPolyPolygon.transform(aDiscreteOffset);
+- maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
+- }
++ // remember current OutDev, Canvas and ViewInformation
++ OutputDevice* pLastOutputDevice = mpOutputDevice;
++ uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas);
++ const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
++
++ // prepare discrete offset for XBitmap, do not forget that the buffer bitmap
++ // may be truncated to discrete visible pixels
++ basegfx::B2DHomMatrix aDiscreteOffset;
++ aDiscreteOffset.translate(
++ aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0,
++ aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0);
++
++ // create new local ViewInformation2D with new transformation
++ const geometry::ViewInformation2D aViewInformation2D(
++ getViewInformation2D().getObjectTransformation(),
++ aDiscreteOffset * getViewInformation2D().getViewTransformation(),
++ getViewInformation2D().getViewport(),
++ getViewInformation2D().getVisualizedPage(),
++ getViewInformation2D().getViewTime(),
++ getViewInformation2D().getExtendedInformationSequence());
++ updateViewInformation(aViewInformation2D);
++
++ // set OutDev and Canvas to content target
++ mpOutputDevice = &aBufferDevice.getContent();
++ mxCanvas = mpOutputDevice->GetCanvas();
++ canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
++
++ // if ViewState transform is changed, the clipping polygon needs to be adapted, too
++ const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon);
++
++ if(maClipPolyPolygon.count())
++ {
++ maClipPolyPolygon.transform(aDiscreteOffset);
++ maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
++ }
+
+- // paint content
+- process(rChildren);
++ // paint content
++ process(rChildren);
+
+- // set to mask
+- mpOutputDevice = &aBufferDevice.getAlpha();
+- mxCanvas = mpOutputDevice->GetCanvas();
+- canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
++ // set to mask
++ mpOutputDevice = &aBufferDevice.getAlpha();
++ mxCanvas = mpOutputDevice->GetCanvas();
++ canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
+
+- // when painting alpha masks, reset the color stack
+- basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack);
+- maBColorModifierStack = basegfx::BColorModifierStack();
++ // when painting alpha masks, reset the color stack
++ basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack);
++ maBColorModifierStack = basegfx::BColorModifierStack();
+
+- // paint mask to it (always with alpha intensities, evtl. with AA)
+- process(rAlpha);
++ // paint mask to it (always with alpha intensities, evtl. with AA)
++ process(rAlpha);
+
+- // back to old color stack, OutDev, Canvas and ViewTransform
+- maBColorModifierStack = aLastBColorModifierStack;
+- mpOutputDevice = pLastOutputDevice;
+- mxCanvas = xLastCanvas;
+- updateViewInformation(aLastViewInformation2D);
+- canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
++ // back to old color stack, OutDev, Canvas and ViewTransform
++ maBColorModifierStack = aLastBColorModifierStack;
++ mpOutputDevice = pLastOutputDevice;
++ mxCanvas = xLastCanvas;
++ updateViewInformation(aLastViewInformation2D);
++ canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
+
+- // restore clipping polygon
+- maClipPolyPolygon = aOldClipPolyPolygon;
++ // restore clipping polygon
++ maClipPolyPolygon = aOldClipPolyPolygon;
+
+- if(maClipPolyPolygon.count())
+- {
+- maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
+- }
++ if(maClipPolyPolygon.count())
++ {
++ maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
++ }
+
+- // dump buffer to outdev
+- aBufferDevice.paint();
+- }
++ // dump buffer to outdev
++ aBufferDevice.paint();
++ }
++ }
++ else
++ {
++ // do it the canvas way
++ }
+ }
+ }
+ }
+@@ -2100,19 +903,27 @@ namespace drawinglayer
+ }
+ case PRIMITIVE2D_ID_CHARTPRIMITIVE2D :
+ {
++ const primitive2d::ChartPrimitive2D& rChartPrimitive = static_cast< const primitive2d::ChartPrimitive2D& >(rCandidate);
++
+ // chart primitive in canvas renderer; restore original DrawMode during call
+ // since the evtl. used ChartPrettyPainter will use the MapMode
+- const primitive2d::ChartPrimitive2D& rChartPrimitive = static_cast< const primitive2d::ChartPrimitive2D& >(rCandidate);
+- mpOutputDevice->Push(PUSH_MAPMODE);
+- mpOutputDevice->SetMapMode(maOriginalMapMode);
++ bool bDone=false;
++ if( mpOutputDevice )
++ {
++ mpOutputDevice->Push(PUSH_MAPMODE);
++ mpOutputDevice->SetMapMode(maOriginalMapMode);
+
+- if(!renderChartPrimitive2D(rChartPrimitive, *mpOutputDevice))
+- {
+- // fallback to decomposition (MetaFile)
+- process(rChartPrimitive.get2DDecomposition(getViewInformation2D()));
+- }
++ if(renderChartPrimitive2D(rChartPrimitive, *mpOutputDevice))
++ bDone=true;
++
++ mpOutputDevice->Pop();
++ }
+
+- mpOutputDevice->Pop();
++ if( !bDone )
++ {
++ // fallback to decomposition (MetaFile)
++ process(rChartPrimitive.get2DDecomposition(getViewInformation2D()));
++ }
+ break;
+ }
+ case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
+@@ -2122,7 +933,8 @@ namespace drawinglayer
+ // this can be removed anytime and the decomposition may be used
+ const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive = static_cast< const primitive2d::WrongSpellPrimitive2D& >(rCandidate);
+
+- if(!renderWrongSpellPrimitive2D(
++ if(!mpOutputDevice ||
++ !renderWrongSpellPrimitive2D(
+ rWrongSpellPrimitive,
+ *mpOutputDevice,
+ getViewInformation2D().getObjectToViewTransformation(),
+@@ -2157,6 +969,28 @@ namespace drawinglayer
+ // process support
+
+ canvasProcessor2D::canvasProcessor2D(
++ const geometry::ViewInformation2D& rViewInformation,
++ const uno::Reference< rendering::XCanvas >& xCanvas,
++ const rendering::ViewState& rViewState )
++ : BaseProcessor2D(rViewInformation),
++ maOriginalMapMode(),
++ mpOutputDevice(NULL),
++ mxCanvas(xCanvas),
++ maViewState(rViewState),
++ maRenderState(),
++ maBColorModifierStack(),
++ maDrawinglayerOpt(),
++ maClipPolyPolygon()
++ {
++ canvas::tools::initRenderState(maRenderState);
++ canvas::tools::appendToViewState(maViewState,
++ getViewInformation2D().getViewTransformation());
++ if( maViewState.Clip.is() )
++ maClipPolyPolygon = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(
++ maViewState.Clip);
++ }
++
++ canvasProcessor2D::canvasProcessor2D(
+ const geometry::ViewInformation2D& rViewInformation,
+ OutputDevice& rOutDev)
+ : BaseProcessor2D(rViewInformation),
+@@ -2178,20 +1012,21 @@ namespace drawinglayer
+
+ // set digit language, derived from SvtCTLOptions to have the correct
+ // number display for arabic/hindi numerals
++ LanguageType eLang;
+ if(SvtCTLOptions::NUMERALS_HINDI == aSvtCTLOptions.GetCTLTextNumerals())
+ {
+- meLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
++ eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
+ }
+ else if(SvtCTLOptions::NUMERALS_ARABIC == aSvtCTLOptions.GetCTLTextNumerals())
+ {
+- meLang = LANGUAGE_ENGLISH;
++ eLang = LANGUAGE_ENGLISH;
+ }
+ else
+ {
+- meLang = (LanguageType)Application::GetSettings().GetLanguage();
++ eLang = (LanguageType)Application::GetSettings().GetLanguage();
+ }
+
+- rOutDev.SetDigitLanguage(meLang);
++ rOutDev.SetDigitLanguage(eLang);
+
+ // prepare output directly to pixels
+ mpOutputDevice->Push(PUSH_MAPMODE);
+@@ -2210,11 +1045,14 @@ namespace drawinglayer
+
+ canvasProcessor2D::~canvasProcessor2D()
+ {
+- // restore MapMode
+- mpOutputDevice->Pop();
+-
+- // restore AntiAliasing
+- mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
++ if( mpOutputDevice )
++ {
++ // restore MapMode
++ mpOutputDevice->Pop();
++
++ // restore AntiAliasing
++ mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
++ }
+ }
+ } // end of namespace processor2d
+ } // end of namespace drawinglayer
+diff --git offapi/com/sun/star/graphic/XPrimitive2D.idl offapi/com/sun/star/graphic/XPrimitive2D.idl
+index ccdc91d..00b41b8 100644
+--- offapi/com/sun/star/graphic/XPrimitive2D.idl
++++ offapi/com/sun/star/graphic/XPrimitive2D.idl
+@@ -57,11 +57,19 @@ interface XPrimitive2D : ::com::sun::star::uno::XInterface
+ 2D View-specific parameter set. The defined but not mandatory
+ parameters include:
+
+- ::com::sun::star::geometry::AffineMatrix2D Transformation
++ ::com::sun::star::geometry::AffineMatrix2D ObjectTransformation
+
+- A transformation matrix which maps between world coordinates (which
+- is equal to object's local coordinates) to view coordinates. If not
+- defined, an empty transformation is implied.
++ A transformation matrix which maps between object coordinates
++ (which is equal to object's local coordinates) to world
++ coordinates. If not defined, the identity transformation is
++ implied.
++
++ ::com::sun::star::geometry::AffineMatrix2D ViewTransformation
++
++ A transformation matrix which maps between world coordinates
++ to view coordinates, i.e. usually the actual pixel on
++ screen. If not defined, the identity transformation is
++ implied.
+
+ ::com::sun::star::geometry::RealRectangle2D Viewport
+
+@@ -76,6 +84,11 @@ interface XPrimitive2D : ::com::sun::star::uno::XInterface
+ lead to varied results for animated objects. This value is defined in the
+ range [0.0 .. n[, negative values are not allowed. If not given, a value of
+ 0.0 is implied.
++
++ ::com::sun::star::drawing::XDrawPage VisualizedPage
++
++ The page object this is displayed on. Used to e.g. resolve
++ page number placeholders and the like.
+ */
+ sequence< XPrimitive2D > getDecomposition( [in] sequence< ::com::sun::star::beans::PropertyValue > aViewParameters );
+
+diff --git offapi/com/sun/star/graphic/XPrimitiveFactory2D.idl offapi/com/sun/star/graphic/XPrimitiveFactory2D.idl
+index 8022207..643e7a4 100644
+--- offapi/com/sun/star/graphic/XPrimitiveFactory2D.idl
++++ offapi/com/sun/star/graphic/XPrimitiveFactory2D.idl
+@@ -69,6 +69,42 @@ interface XPrimitiveFactory2D : ::com::sun::star::uno::XInterface
+ Sequence of factory parameters, whose semantics depend on the
+ shape to be generated.
+
++ 2D View-specific parameter set. The defined but not mandatory
++ parameters include:
++
++ ::com::sun::star::geometry::AffineMatrix2D ObjectTransformation
++
++ A transformation matrix which maps between object coordinates
++ (which is equal to object's local coordinates) to world
++ coordinates. If not defined, the identity transformation is
++ implied.
++
++ ::com::sun::star::geometry::AffineMatrix2D ViewTransformation
++
++ A transformation matrix which maps between world coordinates
++ to view coordinates, i.e. usually the actual pixel on
++ screen. If not defined, the identity transformation is
++ implied.
++
++ ::com::sun::star::geometry::RealRectangle2D Viewport
++
++ Defines the visible part of the view in world coordinates. May be used
++ to optimize decompositions, e.g. for 3d scenes only the visible part
++ needs to be created. If not given, an empty Viewport is implied which
++ means all is visible.
++
++ double Time
++
++ Defines the point in time for which the geometry is defined. This may
++ lead to varied results for animated objects. This value is defined in the
++ range [0.0 .. n[, negative values are not allowed. If not given, a value of
++ 0.0 is implied.
++
++ ::com::sun::star::drawing::XDrawPage VisualizedPage
++
++ The page object this is displayed on. Used to e.g. resolve
++ page number placeholders and the like.
++
+ @return a sequence of primitives, that consists of the
+ geometrical representation from the given XShape.
+ */
+@@ -87,6 +123,42 @@ interface XPrimitiveFactory2D : ::com::sun::star::uno::XInterface
+ Sequence of factory parameters, whose semantics depend on the
+ page to be generated.
+
++ 2D View-specific parameter set. The defined but not mandatory
++ parameters include:
++
++ ::com::sun::star::geometry::AffineMatrix2D ObjectTransformation
++
++ A transformation matrix which maps between object coordinates
++ (which is equal to object's local coordinates) to world
++ coordinates. If not defined, the identity transformation is
++ implied.
++
++ ::com::sun::star::geometry::AffineMatrix2D ViewTransformation
++
++ A transformation matrix which maps between world coordinates
++ to view coordinates, i.e. usually the actual pixel on
++ screen. If not defined, the identity transformation is
++ implied.
++
++ ::com::sun::star::geometry::RealRectangle2D Viewport
++
++ Defines the visible part of the view in world coordinates. May be used
++ to optimize decompositions, e.g. for 3d scenes only the visible part
++ needs to be created. If not given, an empty Viewport is implied which
++ means all is visible.
++
++ double Time
++
++ Defines the point in time for which the geometry is defined. This may
++ lead to varied results for animated objects. This value is defined in the
++ range [0.0 .. n[, negative values are not allowed. If not given, a value of
++ 0.0 is implied.
++
++ ::com::sun::star::drawing::XDrawPage VisualizedPage
++
++ The page object this is displayed on. Used to e.g. resolve
++ page number placeholders and the like.
++
+ @return a sequence of primitives, that consists of the
+ geometrical representation for the given XDrawPage.
+ */
diff --git a/patches/test/slideshow-unittests.diff b/patches/test/slideshow-unittests.diff
new file mode 100644
index 0000000..16b92fe
--- /dev/null
+++ b/patches/test/slideshow-unittests.diff
@@ -0,0 +1,60 @@
+Fix slideshow unit tests
+
+From: Thorsten Behrens <thb at openoffice.org>
+
+
+---
+
+ slideshow/test/demoshow.cxx | 5 +++++
+ slideshow/test/testview.cxx | 14 ++++++++++++++
+ 2 files changed, 19 insertions(+), 0 deletions(-)
+
+
+diff --git slideshow/test/demoshow.cxx slideshow/test/demoshow.cxx
+index 5cfc82c..c9ee73d 100644
+--- slideshow/test/demoshow.cxx
++++ slideshow/test/demoshow.cxx
+@@ -204,6 +204,11 @@ private:
+ {
+ }
+
++ virtual awt::Rectangle SAL_CALL getCanvasArea( ) throw (uno::RuntimeException)
++ {
++ return awt::Rectangle(0,0,maSize.Width(),maSize.Height());
++ }
++
+ uno::Reference< rendering::XSpriteCanvas > mxCanvas;
+ ::cppu::OInterfaceContainerHelper maPaintListeners;
+ ::cppu::OInterfaceContainerHelper maTransformationListeners;
+diff --git slideshow/test/testview.cxx slideshow/test/testview.cxx
+index 19618ff..e1e137d 100644
+--- slideshow/test/testview.cxx
++++ slideshow/test/testview.cxx
+@@ -136,6 +136,11 @@ public:
+ {
+ }
+
++ virtual awt::Rectangle SAL_CALL getCanvasArea( ) throw (uno::RuntimeException)
++ {
++ return awt::Rectangle(0,0,100,100);
++ }
++
+ // TestView
+ virtual bool isClearCalled() const
+ {
+@@ -278,6 +283,15 @@ public:
+ {
+ mbDisposed = true;
+ }
++
++ virtual bool isSoundEnabled (void) const
++ {
++ return true;
++ }
++
++ virtual void setIsSoundEnabled (const bool /*bValue*/)
++ {
++ }
+ };
+
+
More information about the ooo-build-commit
mailing list